wined3d: Make minMipLookup_noFilter and magLookup_noFilter const.
[wine/wine64.git] / dlls / wined3d / device.c
blob855bea536c4012300a96ee773f8fb0e9b4550ef2
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 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 object->resource.priority = 0; \
94 list_init(&object->resource.privateData); \
95 /* Check that we have enough video ram left */ \
96 if (Pool == WINED3DPOOL_DEFAULT) { \
97 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
98 WARN("Out of 'bogus' video memory\n"); \
99 HeapFree(GetProcessHeap(), 0, object); \
100 *pp##type = NULL; \
101 return WINED3DERR_OUTOFVIDEOMEMORY; \
103 WineD3DAdapterChangeGLRam(This, _size); \
105 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
106 if (object->resource.heapMemory == NULL && _size != 0) { \
107 FIXME("Out of memory!\n"); \
108 HeapFree(GetProcessHeap(), 0, object); \
109 *pp##type = NULL; \
110 return WINED3DERR_OUTOFVIDEOMEMORY; \
112 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
113 *pp##type = (IWineD3D##type *) object; \
114 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
115 TRACE("(%p) : Created resource %p\n", This, object); \
118 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
119 _basetexture.levels = Levels; \
120 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
121 _basetexture.LOD = 0; \
122 _basetexture.dirty = TRUE; \
123 _basetexture.is_srgb = FALSE; \
124 _basetexture.srgb_mode_change_count = 0; \
127 /**********************************************************
128 * Global variable / Constants follow
129 **********************************************************/
130 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
132 /**********************************************************
133 * IUnknown parts follows
134 **********************************************************/
136 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
140 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
141 if (IsEqualGUID(riid, &IID_IUnknown)
142 || IsEqualGUID(riid, &IID_IWineD3DBase)
143 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
144 IUnknown_AddRef(iface);
145 *ppobj = This;
146 return S_OK;
148 *ppobj = NULL;
149 return E_NOINTERFACE;
152 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
154 ULONG refCount = InterlockedIncrement(&This->ref);
156 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
157 return refCount;
160 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
162 ULONG refCount = InterlockedDecrement(&This->ref);
164 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
166 if (!refCount) {
167 /* TODO: Clean up all the surfaces and textures! */
168 /* NOTE: You must release the parent if the object was created via a callback
169 ** ***************************/
171 if (!list_empty(&This->resources)) {
172 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
173 dumpResources(&This->resources);
176 if(This->contexts) ERR("Context array not freed!\n");
177 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
178 This->haveHardwareCursor = FALSE;
180 IWineD3D_Release(This->wineD3D);
181 This->wineD3D = NULL;
182 HeapFree(GetProcessHeap(), 0, This);
183 TRACE("Freed device %p\n", This);
184 This = NULL;
186 return refCount;
189 /**********************************************************
190 * IWineD3DDevice implementation follows
191 **********************************************************/
192 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
194 *pParent = This->parent;
195 IUnknown_AddRef(This->parent);
196 return WINED3D_OK;
199 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
200 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
201 IUnknown *parent) {
202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
203 IWineD3DVertexBufferImpl *object;
204 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
205 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
206 BOOL conv;
208 if(Size == 0) {
209 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
210 *ppVertexBuffer = NULL;
211 return WINED3DERR_INVALIDCALL;
212 } else if(Pool == WINED3DPOOL_SCRATCH) {
213 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
214 * anyway, SCRATCH vertex buffers aren't usable anywhere
216 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
217 *ppVertexBuffer = NULL;
218 return WINED3DERR_INVALIDCALL;
221 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
223 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);
224 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
226 object->fvf = FVF;
228 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
229 * drawStridedFast (half-life 2).
231 * Basically converting the vertices in the buffer is quite expensive, and observations
232 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
233 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
235 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
236 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
237 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
238 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
239 * dx7 apps.
240 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
241 * more. In this call we can convert dx7 buffers too.
243 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
244 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
245 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
246 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
247 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
248 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
249 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
250 } else if(dxVersion <= 7 && conv) {
251 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
252 } else {
253 object->Flags |= VBFLAG_CREATEVBO;
255 return WINED3D_OK;
258 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
259 GLenum error, glUsage;
260 TRACE("Creating VBO for Index Buffer %p\n", object);
262 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
263 * restored on the next draw
265 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
267 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
268 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
269 ENTER_GL();
271 while(glGetError());
273 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
274 error = glGetError();
275 if(error != GL_NO_ERROR || object->vbo == 0) {
276 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
277 goto out;
280 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
281 error = glGetError();
282 if(error != GL_NO_ERROR) {
283 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
284 goto out;
287 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
288 * copy no readback will be needed
290 glUsage = GL_STATIC_DRAW_ARB;
291 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
292 error = glGetError();
293 if(error != GL_NO_ERROR) {
294 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
295 goto out;
297 LEAVE_GL();
298 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
299 return;
301 out:
302 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
303 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
304 LEAVE_GL();
305 object->vbo = 0;
308 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
309 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
310 HANDLE *sharedHandle, IUnknown *parent) {
311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
312 IWineD3DIndexBufferImpl *object;
313 TRACE("(%p) Creating index buffer\n", This);
315 /* Allocate the storage for the device */
316 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
318 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
319 CreateIndexBufferVBO(This, object);
322 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
323 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
324 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
326 return WINED3D_OK;
329 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
332 IWineD3DStateBlockImpl *object;
333 int i, j;
334 HRESULT temp_result;
336 D3DCREATEOBJECTINSTANCE(object, StateBlock)
337 object->blockType = Type;
339 for(i = 0; i < LIGHTMAP_SIZE; i++) {
340 list_init(&object->lightMap[i]);
343 /* Special case - Used during initialization to produce a placeholder stateblock
344 so other functions called can update a state block */
345 if (Type == WINED3DSBT_INIT) {
346 /* Don't bother increasing the reference count otherwise a device will never
347 be freed due to circular dependencies */
348 return WINED3D_OK;
351 temp_result = allocate_shader_constants(object);
352 if (WINED3D_OK != temp_result)
353 return temp_result;
355 /* Otherwise, might as well set the whole state block to the appropriate values */
356 if (This->stateBlock != NULL)
357 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
358 else
359 memset(object->streamFreq, 1, sizeof(object->streamFreq));
361 /* Reset the ref and type after kludging it */
362 object->wineD3DDevice = This;
363 object->ref = 1;
364 object->blockType = Type;
366 TRACE("Updating changed flags appropriate for type %d\n", Type);
368 if (Type == WINED3DSBT_ALL) {
370 TRACE("ALL => Pretend everything has changed\n");
371 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
373 /* Lights are not part of the changed / set structure */
374 for(j = 0; j < LIGHTMAP_SIZE; j++) {
375 struct list *e;
376 LIST_FOR_EACH(e, &object->lightMap[j]) {
377 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
378 light->changed = TRUE;
379 light->enabledChanged = TRUE;
382 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
383 object->contained_render_states[j - 1] = j;
385 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
386 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
387 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
388 object->contained_transform_states[j - 1] = j;
390 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
391 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
392 object->contained_vs_consts_f[j] = j;
394 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
395 for(j = 0; j < MAX_CONST_I; j++) {
396 object->contained_vs_consts_i[j] = j;
398 object->num_contained_vs_consts_i = MAX_CONST_I;
399 for(j = 0; j < MAX_CONST_B; j++) {
400 object->contained_vs_consts_b[j] = j;
402 object->num_contained_vs_consts_b = MAX_CONST_B;
403 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
404 object->contained_ps_consts_f[j] = j;
406 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
407 for(j = 0; j < MAX_CONST_I; j++) {
408 object->contained_ps_consts_i[j] = j;
410 object->num_contained_ps_consts_i = MAX_CONST_I;
411 for(j = 0; j < MAX_CONST_B; j++) {
412 object->contained_ps_consts_b[j] = j;
414 object->num_contained_ps_consts_b = MAX_CONST_B;
415 for(i = 0; i < MAX_TEXTURES; i++) {
416 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
417 object->contained_tss_states[object->num_contained_tss_states].stage = i;
418 object->contained_tss_states[object->num_contained_tss_states].state = j;
419 object->num_contained_tss_states++;
422 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
423 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
424 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
425 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
426 object->num_contained_sampler_states++;
430 for(i = 0; i < MAX_STREAMS; i++) {
431 if(object->streamSource[i]) {
432 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
435 if(object->pIndexData) {
436 IWineD3DIndexBuffer_AddRef(object->pIndexData);
438 if(object->vertexShader) {
439 IWineD3DVertexShader_AddRef(object->vertexShader);
441 if(object->pixelShader) {
442 IWineD3DPixelShader_AddRef(object->pixelShader);
445 } else if (Type == WINED3DSBT_PIXELSTATE) {
447 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
448 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
450 object->changed.pixelShader = TRUE;
452 /* Pixel Shader Constants */
453 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
454 object->contained_ps_consts_f[i] = i;
455 object->changed.pixelShaderConstantsF[i] = TRUE;
457 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
458 for (i = 0; i < MAX_CONST_B; ++i) {
459 object->contained_ps_consts_b[i] = i;
460 object->changed.pixelShaderConstantsB[i] = TRUE;
462 object->num_contained_ps_consts_b = MAX_CONST_B;
463 for (i = 0; i < MAX_CONST_I; ++i) {
464 object->contained_ps_consts_i[i] = i;
465 object->changed.pixelShaderConstantsI[i] = TRUE;
467 object->num_contained_ps_consts_i = MAX_CONST_I;
469 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
470 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
471 object->contained_render_states[i] = SavedPixelStates_R[i];
473 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
474 for (j = 0; j < MAX_TEXTURES; j++) {
475 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
476 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
477 object->contained_tss_states[object->num_contained_tss_states].stage = j;
478 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
479 object->num_contained_tss_states++;
482 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
483 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
484 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
485 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
486 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
487 object->num_contained_sampler_states++;
490 if(object->pixelShader) {
491 IWineD3DPixelShader_AddRef(object->pixelShader);
494 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
495 * on them. This makes releasing the buffer easier
497 for(i = 0; i < MAX_STREAMS; i++) {
498 object->streamSource[i] = NULL;
500 object->pIndexData = NULL;
501 object->vertexShader = NULL;
503 } else if (Type == WINED3DSBT_VERTEXSTATE) {
505 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
506 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
508 object->changed.vertexShader = TRUE;
510 /* Vertex Shader Constants */
511 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
512 object->changed.vertexShaderConstantsF[i] = TRUE;
513 object->contained_vs_consts_f[i] = i;
515 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
516 for (i = 0; i < MAX_CONST_B; ++i) {
517 object->changed.vertexShaderConstantsB[i] = TRUE;
518 object->contained_vs_consts_b[i] = i;
520 object->num_contained_vs_consts_b = MAX_CONST_B;
521 for (i = 0; i < MAX_CONST_I; ++i) {
522 object->changed.vertexShaderConstantsI[i] = TRUE;
523 object->contained_vs_consts_i[i] = i;
525 object->num_contained_vs_consts_i = MAX_CONST_I;
526 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
527 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
528 object->contained_render_states[i] = SavedVertexStates_R[i];
530 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
531 for (j = 0; j < MAX_TEXTURES; j++) {
532 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
533 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
534 object->contained_tss_states[object->num_contained_tss_states].stage = j;
535 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
536 object->num_contained_tss_states++;
539 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
540 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
541 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
542 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
543 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
544 object->num_contained_sampler_states++;
548 for(j = 0; j < LIGHTMAP_SIZE; j++) {
549 struct list *e;
550 LIST_FOR_EACH(e, &object->lightMap[j]) {
551 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
552 light->changed = TRUE;
553 light->enabledChanged = TRUE;
557 for(i = 0; i < MAX_STREAMS; i++) {
558 if(object->streamSource[i]) {
559 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
562 if(object->vertexShader) {
563 IWineD3DVertexShader_AddRef(object->vertexShader);
565 object->pIndexData = NULL;
566 object->pixelShader = NULL;
567 } else {
568 FIXME("Unrecognized state block type %d\n", Type);
571 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
572 return WINED3D_OK;
575 /* ************************************
576 MSDN:
577 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
579 Discard
580 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
582 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.
584 ******************************** */
586 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) {
587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
588 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
589 unsigned int Size = 1;
590 const GlPixelFormatDesc *glDesc;
591 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
592 UINT mul_4w, mul_4h;
593 TRACE("(%p) Create surface\n",This);
595 /** FIXME: Check ranges on the inputs are valid
596 * MSDN
597 * MultisampleQuality
598 * [in] Quality level. The valid range is between zero and one less than the level
599 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
600 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
601 * values of paired render targets, depth stencil surfaces, and the MultiSample type
602 * must all match.
603 *******************************/
607 * TODO: Discard MSDN
608 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
610 * If this flag is set, the contents of the depth stencil buffer will be
611 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
612 * with a different depth surface.
614 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
615 ***************************/
617 if(MultisampleQuality > 0) {
618 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
619 MultisampleQuality=0;
622 /** FIXME: Check that the format is supported
623 * by the device.
624 *******************************/
626 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
627 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
628 * space!
629 *********************************/
630 mul_4w = (Width + 3) & ~3;
631 mul_4h = (Height + 3) & ~3;
632 if (WINED3DFMT_UNKNOWN == Format) {
633 Size = 0;
634 } else if (Format == WINED3DFMT_DXT1) {
635 /* DXT1 is half byte per pixel */
636 Size = (mul_4w * tableEntry->bpp * mul_4h) >> 1;
638 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
639 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
640 Format == WINED3DFMT_ATI2N) {
641 Size = (mul_4w * tableEntry->bpp * mul_4h);
642 } else {
643 /* The pitch is a multiple of 4 bytes */
644 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
645 Size *= Height;
648 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
650 /** Create and initialise the surface resource **/
651 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
652 /* "Standalone" surface */
653 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
655 object->currentDesc.Width = Width;
656 object->currentDesc.Height = Height;
657 object->currentDesc.MultiSampleType = MultiSample;
658 object->currentDesc.MultiSampleQuality = MultisampleQuality;
659 object->glDescription.level = Level;
660 object->heightscale = glDesc->heightscale != 0.0 ? glDesc->heightscale : 1.0;
661 list_init(&object->overlays);
663 /* Flags */
664 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
665 object->Flags |= Discard ? SFLAG_DISCARD : 0;
666 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
667 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
670 if (WINED3DFMT_UNKNOWN != Format) {
671 object->bytesPerPixel = tableEntry->bpp;
672 } else {
673 object->bytesPerPixel = 0;
676 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
678 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
680 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
681 * this function is too deep to need to care about things like this.
682 * Levels need to be checked too, and possibly Type since they all affect what can be done.
683 * ****************************************/
684 switch(Pool) {
685 case WINED3DPOOL_SCRATCH:
686 if(!Lockable)
687 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
688 "which are mutually exclusive, setting lockable to TRUE\n");
689 Lockable = TRUE;
690 break;
691 case WINED3DPOOL_SYSTEMMEM:
692 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
693 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
694 case WINED3DPOOL_MANAGED:
695 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
696 "Usage of DYNAMIC which are mutually exclusive, not doing "
697 "anything just telling you.\n");
698 break;
699 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
700 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
701 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
702 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
703 break;
704 default:
705 FIXME("(%p) Unknown pool %d\n", This, Pool);
706 break;
709 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
710 FIXME("Trying to create a render target that isn't in the default pool\n");
713 /* mark the texture as dirty so that it gets loaded first time around*/
714 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
715 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
716 This, Width, Height, Format, debug_d3dformat(Format),
717 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
719 /* Look at the implementation and set the correct Vtable */
720 switch(Impl) {
721 case SURFACE_OPENGL:
722 /* Check if a 3D adapter is available when creating gl surfaces */
723 if(!This->adapter) {
724 ERR("OpenGL surfaces are not available without opengl\n");
725 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
726 HeapFree(GetProcessHeap(), 0, object);
727 return WINED3DERR_NOTAVAILABLE;
729 break;
731 case SURFACE_GDI:
732 object->lpVtbl = &IWineGDISurface_Vtbl;
733 break;
735 default:
736 /* To be sure to catch this */
737 ERR("Unknown requested surface implementation %d!\n", Impl);
738 IWineD3DSurface_Release((IWineD3DSurface *) object);
739 return WINED3DERR_INVALIDCALL;
742 list_init(&object->renderbuffers);
744 /* Call the private setup routine */
745 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
749 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
750 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
751 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
752 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
755 IWineD3DTextureImpl *object;
756 unsigned int i;
757 UINT tmpW;
758 UINT tmpH;
759 HRESULT hr;
760 unsigned int pow2Width;
761 unsigned int pow2Height;
762 const GlPixelFormatDesc *glDesc;
763 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
765 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
766 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
767 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
769 /* TODO: It should only be possible to create textures for formats
770 that are reported as supported */
771 if (WINED3DFMT_UNKNOWN >= Format) {
772 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
773 return WINED3DERR_INVALIDCALL;
776 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
777 D3DINITIALIZEBASETEXTURE(object->baseTexture);
778 object->width = Width;
779 object->height = Height;
781 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
782 object->baseTexture.minMipLookup = minMipLookup;
783 object->baseTexture.magLookup = magLookup;
784 } else {
785 object->baseTexture.minMipLookup = minMipLookup_noFilter;
786 object->baseTexture.magLookup = magLookup_noFilter;
789 /** Non-power2 support **/
790 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
791 pow2Width = Width;
792 pow2Height = Height;
793 } else {
794 /* Find the nearest pow2 match */
795 pow2Width = pow2Height = 1;
796 while (pow2Width < Width) pow2Width <<= 1;
797 while (pow2Height < Height) pow2Height <<= 1;
799 if(pow2Width != Width || pow2Height != Height) {
800 if(Levels > 1) {
801 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
802 HeapFree(GetProcessHeap(), 0, object);
803 *ppTexture = NULL;
804 return WINED3DERR_INVALIDCALL;
805 } else {
806 Levels = 1;
811 /** FIXME: add support for real non-power-two if it's provided by the video card **/
812 /* Precalculated scaling for 'faked' non power of two texture coords.
813 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
814 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
815 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
817 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
818 object->baseTexture.pow2Matrix[0] = 1.0;
819 object->baseTexture.pow2Matrix[5] = 1.0;
820 object->baseTexture.pow2Matrix[10] = 1.0;
821 object->baseTexture.pow2Matrix[15] = 1.0;
822 object->target = GL_TEXTURE_2D;
823 object->cond_np2 = TRUE;
824 object->baseTexture.minMipLookup = minMipLookup_noFilter;
825 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
826 (Width != pow2Width || Height != pow2Height) &&
827 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
829 object->baseTexture.pow2Matrix[0] = (float)Width;
830 object->baseTexture.pow2Matrix[5] = (float)Height;
831 object->baseTexture.pow2Matrix[10] = 1.0;
832 object->baseTexture.pow2Matrix[15] = 1.0;
833 object->target = GL_TEXTURE_RECTANGLE_ARB;
834 object->cond_np2 = TRUE;
835 object->baseTexture.minMipLookup = minMipLookup_noFilter;
836 } else {
837 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
838 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
839 object->baseTexture.pow2Matrix[10] = 1.0;
840 object->baseTexture.pow2Matrix[15] = 1.0;
841 object->target = GL_TEXTURE_2D;
842 object->cond_np2 = FALSE;
844 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
846 /* Calculate levels for mip mapping */
847 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
848 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
849 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
850 return WINED3DERR_INVALIDCALL;
852 if(Levels > 1) {
853 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
854 return WINED3DERR_INVALIDCALL;
856 object->baseTexture.levels = 1;
857 } else if (Levels == 0) {
858 TRACE("calculating levels %d\n", object->baseTexture.levels);
859 object->baseTexture.levels++;
860 tmpW = Width;
861 tmpH = Height;
862 while (tmpW > 1 || tmpH > 1) {
863 tmpW = max(1, tmpW >> 1);
864 tmpH = max(1, tmpH >> 1);
865 object->baseTexture.levels++;
867 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
870 /* Generate all the surfaces */
871 tmpW = Width;
872 tmpH = Height;
873 for (i = 0; i < object->baseTexture.levels; i++)
875 /* use the callback to create the texture surface */
876 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
877 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
878 FIXME("Failed to create surface %p\n", object);
879 /* clean up */
880 object->surfaces[i] = NULL;
881 IWineD3DTexture_Release((IWineD3DTexture *)object);
883 *ppTexture = NULL;
884 return hr;
887 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
888 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
889 surface_set_texture_target(object->surfaces[i], object->target);
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 object->baseTexture.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;
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 /* Find the nearest pow2 match */
1081 pow2EdgeLength = 1;
1082 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1084 object->edgeLength = EdgeLength;
1086 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
1087 /* Precalculated scaling for 'faked' non power of two texture coords */
1088 object->baseTexture.pow2Matrix[ 0] = 1.0;
1089 object->baseTexture.pow2Matrix[ 5] = 1.0;
1090 object->baseTexture.pow2Matrix[10] = 1.0;
1091 object->baseTexture.pow2Matrix[15] = 1.0;
1092 } else {
1093 /* Precalculated scaling for 'faked' non power of two texture coords */
1094 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1095 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1096 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1097 object->baseTexture.pow2Matrix[15] = 1.0;
1100 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1101 object->baseTexture.minMipLookup = minMipLookup;
1102 object->baseTexture.magLookup = magLookup;
1103 } else {
1104 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1105 object->baseTexture.magLookup = magLookup_noFilter;
1108 /* Calculate levels for mip mapping */
1109 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1110 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1111 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1112 HeapFree(GetProcessHeap(), 0, object);
1113 *ppCubeTexture = NULL;
1115 return WINED3DERR_INVALIDCALL;
1117 if(Levels > 1) {
1118 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1119 HeapFree(GetProcessHeap(), 0, object);
1120 *ppCubeTexture = NULL;
1122 return WINED3DERR_INVALIDCALL;
1124 object->baseTexture.levels = 1;
1125 } else if (Levels == 0) {
1126 object->baseTexture.levels++;
1127 tmpW = EdgeLength;
1128 while (tmpW > 1) {
1129 tmpW = max(1, tmpW >> 1);
1130 object->baseTexture.levels++;
1132 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1135 /* Generate all the surfaces */
1136 tmpW = EdgeLength;
1137 for (i = 0; i < object->baseTexture.levels; i++) {
1139 /* Create the 6 faces */
1140 for (j = 0; j < 6; j++) {
1141 static const GLenum cube_targets[6] = {
1142 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1143 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1144 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1145 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1146 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1147 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1150 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1151 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1153 if(hr!= WINED3D_OK) {
1154 /* clean up */
1155 unsigned int k;
1156 unsigned int l;
1157 for (l = 0; l < j; l++) {
1158 IWineD3DSurface_Release(object->surfaces[l][i]);
1160 for (k = 0; k < i; k++) {
1161 for (l = 0; l < 6; l++) {
1162 IWineD3DSurface_Release(object->surfaces[l][k]);
1166 FIXME("(%p) Failed to create surface\n",object);
1167 HeapFree(GetProcessHeap(),0,object);
1168 *ppCubeTexture = NULL;
1169 return hr;
1171 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1172 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1173 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1175 tmpW = max(1, tmpW >> 1);
1177 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1179 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1180 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1181 return WINED3D_OK;
1184 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1186 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1187 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1188 const IWineD3DQueryVtbl *vtable;
1190 /* Just a check to see if we support this type of query */
1191 switch(Type) {
1192 case WINED3DQUERYTYPE_OCCLUSION:
1193 TRACE("(%p) occlusion query\n", This);
1194 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1195 hr = WINED3D_OK;
1196 else
1197 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1199 vtable = &IWineD3DOcclusionQuery_Vtbl;
1200 break;
1202 case WINED3DQUERYTYPE_EVENT:
1203 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1204 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1205 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1207 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1209 vtable = &IWineD3DEventQuery_Vtbl;
1210 hr = WINED3D_OK;
1211 break;
1213 case WINED3DQUERYTYPE_VCACHE:
1214 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1215 case WINED3DQUERYTYPE_VERTEXSTATS:
1216 case WINED3DQUERYTYPE_TIMESTAMP:
1217 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1218 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1219 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1220 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1221 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1222 case WINED3DQUERYTYPE_PIXELTIMINGS:
1223 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1224 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1225 default:
1226 /* Use the base Query vtable until we have a special one for each query */
1227 vtable = &IWineD3DQuery_Vtbl;
1228 FIXME("(%p) Unhandled query type %d\n", This, Type);
1230 if(NULL == ppQuery || hr != WINED3D_OK) {
1231 return hr;
1234 D3DCREATEOBJECTINSTANCE(object, Query)
1235 object->lpVtbl = vtable;
1236 object->type = Type;
1237 object->state = QUERY_CREATED;
1238 /* allocated the 'extended' data based on the type of query requested */
1239 switch(Type){
1240 case WINED3DQUERYTYPE_OCCLUSION:
1241 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1242 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1244 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1245 TRACE("(%p) Allocating data for an occlusion query\n", This);
1246 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1247 break;
1249 case WINED3DQUERYTYPE_EVENT:
1250 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1251 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1253 if(GL_SUPPORT(APPLE_FENCE)) {
1254 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1255 checkGLcall("glGenFencesAPPLE");
1256 } else if(GL_SUPPORT(NV_FENCE)) {
1257 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1258 checkGLcall("glGenFencesNV");
1260 break;
1262 case WINED3DQUERYTYPE_VCACHE:
1263 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1264 case WINED3DQUERYTYPE_VERTEXSTATS:
1265 case WINED3DQUERYTYPE_TIMESTAMP:
1266 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1267 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1268 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1269 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1270 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1271 case WINED3DQUERYTYPE_PIXELTIMINGS:
1272 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1273 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1274 default:
1275 object->extendedData = 0;
1276 FIXME("(%p) Unhandled query type %d\n",This , Type);
1278 TRACE("(%p) : Created Query %p\n", This, object);
1279 return WINED3D_OK;
1282 /*****************************************************************************
1283 * IWineD3DDeviceImpl_SetupFullscreenWindow
1285 * Helper function that modifies a HWND's Style and ExStyle for proper
1286 * fullscreen use.
1288 * Params:
1289 * iface: Pointer to the IWineD3DDevice interface
1290 * window: Window to setup
1292 *****************************************************************************/
1293 static LONG fullscreen_style(LONG orig_style) {
1294 LONG style = orig_style;
1295 style &= ~WS_CAPTION;
1296 style &= ~WS_THICKFRAME;
1298 /* Make sure the window is managed, otherwise we won't get keyboard input */
1299 style |= WS_POPUP | WS_SYSMENU;
1301 return style;
1304 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1305 LONG exStyle = orig_exStyle;
1307 /* Filter out window decorations */
1308 exStyle &= ~WS_EX_WINDOWEDGE;
1309 exStyle &= ~WS_EX_CLIENTEDGE;
1311 return exStyle;
1314 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1317 LONG style, exStyle;
1318 /* Don't do anything if an original style is stored.
1319 * That shouldn't happen
1321 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1322 if (This->style || This->exStyle) {
1323 ERR("(%p): Want to change the window parameters of HWND %p, but "
1324 "another style is stored for restoration afterwards\n", This, window);
1327 /* Get the parameters and save them */
1328 style = GetWindowLongW(window, GWL_STYLE);
1329 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1330 This->style = style;
1331 This->exStyle = exStyle;
1333 style = fullscreen_style(style);
1334 exStyle = fullscreen_exStyle(exStyle);
1336 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1337 This->style, This->exStyle, style, exStyle);
1339 SetWindowLongW(window, GWL_STYLE, style);
1340 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1342 /* Inform the window about the update. */
1343 SetWindowPos(window, HWND_TOP, 0, 0,
1344 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1347 /*****************************************************************************
1348 * IWineD3DDeviceImpl_RestoreWindow
1350 * Helper function that restores a windows' properties when taking it out
1351 * of fullscreen mode
1353 * Params:
1354 * iface: Pointer to the IWineD3DDevice interface
1355 * window: Window to setup
1357 *****************************************************************************/
1358 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1360 LONG style, exStyle;
1362 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1363 * switch, do nothing
1365 if (!This->style && !This->exStyle) return;
1367 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1368 This, window, This->style, This->exStyle);
1370 style = GetWindowLongW(window, GWL_STYLE);
1371 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1373 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1374 * Some applications change it before calling Reset() when switching between windowed and
1375 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1377 if(style == fullscreen_style(This->style) &&
1378 exStyle == fullscreen_style(This->exStyle)) {
1379 SetWindowLongW(window, GWL_STYLE, This->style);
1380 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1383 /* Delete the old values */
1384 This->style = 0;
1385 This->exStyle = 0;
1387 /* Inform the window about the update */
1388 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1389 0, 0, 0, 0, /* Pos, Size, ignored */
1390 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1393 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1394 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice* iface,
1395 WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1396 IUnknown* parent, D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1397 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil, WINED3DSURFTYPE surface_type)
1399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1401 HDC hDc;
1402 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1403 HRESULT hr;
1404 IUnknown *bufferParent;
1405 BOOL displaymode_set = FALSE;
1406 WINED3DDISPLAYMODE Mode;
1407 const StaticPixelFormatDesc *formatDesc;
1409 TRACE("(%p) : Created Additional Swap Chain\n", This);
1411 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1412 * does a device hold a reference to a swap chain giving them a lifetime of the device
1413 * or does the swap chain notify the device of its destruction.
1414 *******************************/
1416 /* Check the params */
1417 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1418 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1419 return WINED3DERR_INVALIDCALL;
1420 } else if (pPresentationParameters->BackBufferCount > 1) {
1421 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");
1424 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1425 switch(surface_type) {
1426 case SURFACE_GDI:
1427 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1428 break;
1429 case SURFACE_OPENGL:
1430 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1431 break;
1432 case SURFACE_UNKNOWN:
1433 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1434 return WINED3DERR_INVALIDCALL;
1437 /*********************
1438 * Lookup the window Handle and the relating X window handle
1439 ********************/
1441 /* Setup hwnd we are using, plus which display this equates to */
1442 object->win_handle = pPresentationParameters->hDeviceWindow;
1443 if (!object->win_handle) {
1444 object->win_handle = This->createParms.hFocusWindow;
1446 if(!pPresentationParameters->Windowed && object->win_handle) {
1447 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1448 pPresentationParameters->BackBufferWidth,
1449 pPresentationParameters->BackBufferHeight);
1452 hDc = GetDC(object->win_handle);
1453 TRACE("Using hDc %p\n", hDc);
1455 if (NULL == hDc) {
1456 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1457 return WINED3DERR_NOTAVAILABLE;
1460 /* Get info on the current display setup */
1461 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1462 object->orig_width = Mode.Width;
1463 object->orig_height = Mode.Height;
1464 object->orig_fmt = Mode.Format;
1465 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1467 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1468 * then the corresponding dimension of the client area of the hDeviceWindow
1469 * (or the focus window, if hDeviceWindow is NULL) is taken.
1470 **********************/
1472 if (pPresentationParameters->Windowed &&
1473 ((pPresentationParameters->BackBufferWidth == 0) ||
1474 (pPresentationParameters->BackBufferHeight == 0) ||
1475 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1477 RECT Rect;
1478 GetClientRect(object->win_handle, &Rect);
1480 if (pPresentationParameters->BackBufferWidth == 0) {
1481 pPresentationParameters->BackBufferWidth = Rect.right;
1482 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1484 if (pPresentationParameters->BackBufferHeight == 0) {
1485 pPresentationParameters->BackBufferHeight = Rect.bottom;
1486 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1488 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1489 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1490 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1494 /* Put the correct figures in the presentation parameters */
1495 TRACE("Copying across presentation parameters\n");
1496 object->presentParms = *pPresentationParameters;
1498 TRACE("calling rendertarget CB\n");
1499 hr = D3DCB_CreateRenderTarget(This->parent,
1500 parent,
1501 object->presentParms.BackBufferWidth,
1502 object->presentParms.BackBufferHeight,
1503 object->presentParms.BackBufferFormat,
1504 object->presentParms.MultiSampleType,
1505 object->presentParms.MultiSampleQuality,
1506 TRUE /* Lockable */,
1507 &object->frontBuffer,
1508 NULL /* pShared (always null)*/);
1509 if (SUCCEEDED(hr)) {
1510 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1511 if(surface_type == SURFACE_OPENGL) {
1512 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1514 } else {
1515 ERR("Failed to create the front buffer\n");
1516 goto error;
1519 /*********************
1520 * Windowed / Fullscreen
1521 *******************/
1524 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1525 * so we should really check to see if there is a fullscreen swapchain already
1526 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1527 **************************************/
1529 if (!pPresentationParameters->Windowed) {
1530 WINED3DDISPLAYMODE mode;
1533 /* Change the display settings */
1534 mode.Width = pPresentationParameters->BackBufferWidth;
1535 mode.Height = pPresentationParameters->BackBufferHeight;
1536 mode.Format = pPresentationParameters->BackBufferFormat;
1537 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1539 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1540 displaymode_set = TRUE;
1544 * Create an opengl context for the display visual
1545 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1546 * use different properties after that point in time. FIXME: How to handle when requested format
1547 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1548 * it chooses is identical to the one already being used!
1549 **********************************/
1550 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1552 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1553 if(!object->context) {
1554 ERR("Failed to create the context array\n");
1555 hr = E_OUTOFMEMORY;
1556 goto error;
1558 object->num_contexts = 1;
1560 if(surface_type == SURFACE_OPENGL) {
1561 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1562 if (!object->context[0]) {
1563 ERR("Failed to create a new context\n");
1564 hr = WINED3DERR_NOTAVAILABLE;
1565 goto error;
1566 } else {
1567 TRACE("Context created (HWND=%p, glContext=%p)\n",
1568 object->win_handle, object->context[0]->glCtx);
1572 /*********************
1573 * Create the back, front and stencil buffers
1574 *******************/
1575 if(object->presentParms.BackBufferCount > 0) {
1576 UINT i;
1578 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1579 if(!object->backBuffer) {
1580 ERR("Out of memory\n");
1581 hr = E_OUTOFMEMORY;
1582 goto error;
1585 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1586 TRACE("calling rendertarget CB\n");
1587 hr = D3DCB_CreateRenderTarget(This->parent,
1588 parent,
1589 object->presentParms.BackBufferWidth,
1590 object->presentParms.BackBufferHeight,
1591 object->presentParms.BackBufferFormat,
1592 object->presentParms.MultiSampleType,
1593 object->presentParms.MultiSampleQuality,
1594 TRUE /* Lockable */,
1595 &object->backBuffer[i],
1596 NULL /* pShared (always null)*/);
1597 if(SUCCEEDED(hr)) {
1598 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1599 } else {
1600 ERR("Cannot create new back buffer\n");
1601 goto error;
1603 if(surface_type == SURFACE_OPENGL) {
1604 ENTER_GL();
1605 glDrawBuffer(GL_BACK);
1606 checkGLcall("glDrawBuffer(GL_BACK)");
1607 LEAVE_GL();
1610 } else {
1611 object->backBuffer = NULL;
1613 /* Single buffering - draw to front buffer */
1614 if(surface_type == SURFACE_OPENGL) {
1615 ENTER_GL();
1616 glDrawBuffer(GL_FRONT);
1617 checkGLcall("glDrawBuffer(GL_FRONT)");
1618 LEAVE_GL();
1622 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1623 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1624 TRACE("Creating depth stencil buffer\n");
1625 if (This->auto_depth_stencil_buffer == NULL ) {
1626 hr = D3DCB_CreateDepthStencil(This->parent,
1627 parent,
1628 object->presentParms.BackBufferWidth,
1629 object->presentParms.BackBufferHeight,
1630 object->presentParms.AutoDepthStencilFormat,
1631 object->presentParms.MultiSampleType,
1632 object->presentParms.MultiSampleQuality,
1633 FALSE /* FIXME: Discard */,
1634 &This->auto_depth_stencil_buffer,
1635 NULL /* pShared (always null)*/ );
1636 if (SUCCEEDED(hr)) {
1637 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1638 } else {
1639 ERR("Failed to create the auto depth stencil\n");
1640 goto error;
1645 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1647 TRACE("Created swapchain %p\n", object);
1648 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1649 return WINED3D_OK;
1651 error:
1652 if (displaymode_set) {
1653 DEVMODEW devmode;
1654 RECT clip_rc;
1656 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1657 ClipCursor(NULL);
1659 /* Change the display settings */
1660 memset(&devmode, 0, sizeof(devmode));
1661 devmode.dmSize = sizeof(devmode);
1662 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1663 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1664 devmode.dmPelsWidth = object->orig_width;
1665 devmode.dmPelsHeight = object->orig_height;
1666 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1669 if (object->backBuffer) {
1670 UINT i;
1671 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1672 if(object->backBuffer[i]) {
1673 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1674 IUnknown_Release(bufferParent); /* once for the get parent */
1675 if (IUnknown_Release(bufferParent) > 0) {
1676 FIXME("(%p) Something's still holding the back buffer\n",This);
1680 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1681 object->backBuffer = NULL;
1683 if(object->context && object->context[0])
1684 DestroyContext(This, object->context[0]);
1685 if(object->frontBuffer) {
1686 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1687 IUnknown_Release(bufferParent); /* once for the get parent */
1688 if (IUnknown_Release(bufferParent) > 0) {
1689 FIXME("(%p) Something's still holding the front buffer\n",This);
1692 HeapFree(GetProcessHeap(), 0, object);
1693 return hr;
1696 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1697 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1699 TRACE("(%p)\n", This);
1701 return This->NumberOfSwapChains;
1704 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1706 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1708 if(iSwapChain < This->NumberOfSwapChains) {
1709 *pSwapChain = This->swapchains[iSwapChain];
1710 IWineD3DSwapChain_AddRef(*pSwapChain);
1711 TRACE("(%p) returning %p\n", This, *pSwapChain);
1712 return WINED3D_OK;
1713 } else {
1714 TRACE("Swapchain out of range\n");
1715 *pSwapChain = NULL;
1716 return WINED3DERR_INVALIDCALL;
1720 /*****
1721 * Vertex Declaration
1722 *****/
1723 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1724 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1726 IWineD3DVertexDeclarationImpl *object = NULL;
1727 HRESULT hr = WINED3D_OK;
1729 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1730 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1732 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1734 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1735 if(FAILED(hr)) {
1736 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1737 *ppVertexDeclaration = NULL;
1740 return hr;
1743 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1744 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1746 unsigned int idx, idx2;
1747 unsigned int offset;
1748 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1749 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1750 BOOL has_blend_idx = has_blend &&
1751 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1752 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1753 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1754 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1755 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1756 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1757 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1759 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1760 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1762 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1763 WINED3DVERTEXELEMENT *elements = NULL;
1765 unsigned int size;
1766 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1767 if (has_blend_idx) num_blends--;
1769 /* Compute declaration size */
1770 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1771 has_psize + has_diffuse + has_specular + num_textures + 1;
1773 /* convert the declaration */
1774 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1775 if (!elements)
1776 return 0;
1778 elements[size-1] = end_element;
1779 idx = 0;
1780 if (has_pos) {
1781 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1782 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1783 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1785 else {
1786 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1787 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1789 elements[idx].UsageIndex = 0;
1790 idx++;
1792 if (has_blend && (num_blends > 0)) {
1793 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1794 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1795 else {
1796 switch(num_blends) {
1797 case 1: elements[idx].Type = WINED3DDECLTYPE_FLOAT1; break;
1798 case 2: elements[idx].Type = WINED3DDECLTYPE_FLOAT2; break;
1799 case 3: elements[idx].Type = WINED3DDECLTYPE_FLOAT3; break;
1800 case 4: elements[idx].Type = WINED3DDECLTYPE_FLOAT4; break;
1801 default:
1802 ERR("Unexpected amount of blend values: %u\n", num_blends);
1805 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1806 elements[idx].UsageIndex = 0;
1807 idx++;
1809 if (has_blend_idx) {
1810 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1811 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1812 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1813 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1814 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1815 else
1816 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1817 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1818 elements[idx].UsageIndex = 0;
1819 idx++;
1821 if (has_normal) {
1822 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1823 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1824 elements[idx].UsageIndex = 0;
1825 idx++;
1827 if (has_psize) {
1828 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1829 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1830 elements[idx].UsageIndex = 0;
1831 idx++;
1833 if (has_diffuse) {
1834 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1835 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1836 elements[idx].UsageIndex = 0;
1837 idx++;
1839 if (has_specular) {
1840 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1841 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1842 elements[idx].UsageIndex = 1;
1843 idx++;
1845 for (idx2 = 0; idx2 < num_textures; idx2++) {
1846 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1847 switch (numcoords) {
1848 case WINED3DFVF_TEXTUREFORMAT1:
1849 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1850 break;
1851 case WINED3DFVF_TEXTUREFORMAT2:
1852 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1853 break;
1854 case WINED3DFVF_TEXTUREFORMAT3:
1855 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1856 break;
1857 case WINED3DFVF_TEXTUREFORMAT4:
1858 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1859 break;
1861 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1862 elements[idx].UsageIndex = idx2;
1863 idx++;
1866 /* Now compute offsets, and initialize the rest of the fields */
1867 for (idx = 0, offset = 0; idx < size-1; idx++) {
1868 elements[idx].Stream = 0;
1869 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1870 elements[idx].Offset = offset;
1871 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1874 *ppVertexElements = elements;
1875 return size;
1878 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1879 WINED3DVERTEXELEMENT* elements = NULL;
1880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1881 unsigned int size;
1882 DWORD hr;
1884 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1885 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1887 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1888 HeapFree(GetProcessHeap(), 0, elements);
1889 if (hr != S_OK) return hr;
1891 return WINED3D_OK;
1894 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1896 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1897 HRESULT hr = WINED3D_OK;
1898 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1899 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1901 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1903 if (vertex_declaration) {
1904 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1907 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1909 if (WINED3D_OK != hr) {
1910 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1911 IWineD3DVertexShader_Release(*ppVertexShader);
1912 return WINED3DERR_INVALIDCALL;
1914 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1916 return WINED3D_OK;
1919 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1920 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1921 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1922 HRESULT hr = WINED3D_OK;
1924 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1925 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1926 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1927 if (WINED3D_OK == hr) {
1928 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1929 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1930 } else {
1931 WARN("(%p) : Failed to create pixel shader\n", This);
1934 return hr;
1937 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1938 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1941 IWineD3DPaletteImpl *object;
1942 HRESULT hr;
1943 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1945 /* Create the new object */
1946 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1947 if(!object) {
1948 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1949 return E_OUTOFMEMORY;
1952 object->lpVtbl = &IWineD3DPalette_Vtbl;
1953 object->ref = 1;
1954 object->Flags = Flags;
1955 object->parent = Parent;
1956 object->wineD3DDevice = This;
1957 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1959 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1961 if(!object->hpal) {
1962 HeapFree( GetProcessHeap(), 0, object);
1963 return E_OUTOFMEMORY;
1966 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1967 if(FAILED(hr)) {
1968 IWineD3DPalette_Release((IWineD3DPalette *) object);
1969 return hr;
1972 *Palette = (IWineD3DPalette *) object;
1974 return WINED3D_OK;
1977 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1978 HBITMAP hbm;
1979 BITMAP bm;
1980 HRESULT hr;
1981 HDC dcb = NULL, dcs = NULL;
1982 WINEDDCOLORKEY colorkey;
1984 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1985 if(hbm)
1987 GetObjectA(hbm, sizeof(BITMAP), &bm);
1988 dcb = CreateCompatibleDC(NULL);
1989 if(!dcb) goto out;
1990 SelectObject(dcb, hbm);
1992 else
1994 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1995 * couldn't be loaded
1997 memset(&bm, 0, sizeof(bm));
1998 bm.bmWidth = 32;
1999 bm.bmHeight = 32;
2002 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2003 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2004 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
2005 if(FAILED(hr)) {
2006 ERR("Wine logo requested, but failed to create surface\n");
2007 goto out;
2010 if(dcb) {
2011 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2012 if(FAILED(hr)) goto out;
2013 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2014 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2016 colorkey.dwColorSpaceLowValue = 0;
2017 colorkey.dwColorSpaceHighValue = 0;
2018 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2019 } else {
2020 /* Fill the surface with a white color to show that wined3d is there */
2021 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2024 out:
2025 if(dcb) {
2026 DeleteDC(dcb);
2028 if(hbm) {
2029 DeleteObject(hbm);
2031 return;
2034 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2035 unsigned int i;
2036 /* Under DirectX you can have texture stage operations even if no texture is
2037 bound, whereas opengl will only do texture operations when a valid texture is
2038 bound. We emulate this by creating dummy textures and binding them to each
2039 texture stage, but disable all stages by default. Hence if a stage is enabled
2040 then the default texture will kick in until replaced by a SetTexture call */
2041 ENTER_GL();
2043 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2044 /* The dummy texture does not have client storage backing */
2045 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2046 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2048 for (i = 0; i < GL_LIMITS(textures); i++) {
2049 GLubyte white = 255;
2051 /* Make appropriate texture active */
2052 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2053 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2054 checkGLcall("glActiveTextureARB");
2055 } else if (i > 0) {
2056 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2059 /* Generate an opengl texture name */
2060 glGenTextures(1, &This->dummyTextureName[i]);
2061 checkGLcall("glGenTextures");
2062 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2064 /* Generate a dummy 2d texture (not using 1d because they cause many
2065 * DRI drivers fall back to sw) */
2066 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2067 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2068 checkGLcall("glBindTexture");
2070 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2071 checkGLcall("glTexImage2D");
2073 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2074 /* Reenable because if supported it is enabled by default */
2075 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2076 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2079 LEAVE_GL();
2082 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2084 IWineD3DSwapChainImpl *swapchain = NULL;
2085 HRESULT hr;
2086 DWORD state;
2087 unsigned int i;
2089 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateSwapChain);
2090 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2091 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2093 /* TODO: Test if OpenGL is compiled in and loaded */
2095 TRACE("(%p) : Creating stateblock\n", This);
2096 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2097 hr = IWineD3DDevice_CreateStateBlock(iface,
2098 WINED3DSBT_INIT,
2099 (IWineD3DStateBlock **)&This->stateBlock,
2100 NULL);
2101 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2102 WARN("Failed to create stateblock\n");
2103 goto err_out;
2105 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2106 This->updateStateBlock = This->stateBlock;
2107 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2109 hr = allocate_shader_constants(This->updateStateBlock);
2110 if (WINED3D_OK != hr) {
2111 goto err_out;
2114 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2115 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2117 This->NumberOfPalettes = 1;
2118 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2119 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2120 ERR("Out of memory!\n");
2121 goto err_out;
2123 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2124 if(!This->palettes[0]) {
2125 ERR("Out of memory!\n");
2126 goto err_out;
2128 for (i = 0; i < 256; ++i) {
2129 This->palettes[0][i].peRed = 0xFF;
2130 This->palettes[0][i].peGreen = 0xFF;
2131 This->palettes[0][i].peBlue = 0xFF;
2132 This->palettes[0][i].peFlags = 0xFF;
2134 This->currentPalette = 0;
2136 /* Initialize the texture unit mapping to a 1:1 mapping */
2137 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2138 if (state < GL_LIMITS(fragment_samplers)) {
2139 This->texUnitMap[state] = state;
2140 This->rev_tex_unit_map[state] = state;
2141 } else {
2142 This->texUnitMap[state] = -1;
2143 This->rev_tex_unit_map[state] = -1;
2147 /* Setup the implicit swapchain */
2148 TRACE("Creating implicit swapchain\n");
2149 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2150 if (FAILED(hr) || !swapchain) {
2151 WARN("Failed to create implicit swapchain\n");
2152 goto err_out;
2155 This->NumberOfSwapChains = 1;
2156 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2157 if(!This->swapchains) {
2158 ERR("Out of memory!\n");
2159 goto err_out;
2161 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2163 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2164 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2165 This->render_targets[0] = swapchain->backBuffer[0];
2166 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2168 else {
2169 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2170 This->render_targets[0] = swapchain->frontBuffer;
2171 This->lastActiveRenderTarget = swapchain->frontBuffer;
2173 IWineD3DSurface_AddRef(This->render_targets[0]);
2174 This->activeContext = swapchain->context[0];
2175 This->lastThread = GetCurrentThreadId();
2177 /* Depth Stencil support */
2178 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2179 if (NULL != This->stencilBufferTarget) {
2180 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2183 hr = This->shader_backend->shader_alloc_private(iface);
2184 if(FAILED(hr)) {
2185 TRACE("Shader private data couldn't be allocated\n");
2186 goto err_out;
2188 hr = This->frag_pipe->alloc_private(iface);
2189 if(FAILED(hr)) {
2190 TRACE("Fragment pipeline private data couldn't be allocated\n");
2191 goto err_out;
2193 hr = This->blitter->alloc_private(iface);
2194 if(FAILED(hr)) {
2195 TRACE("Blitter private data couldn't be allocated\n");
2196 goto err_out;
2199 /* Set up some starting GL setup */
2201 /* Setup all the devices defaults */
2202 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2203 create_dummy_textures(This);
2205 ENTER_GL();
2207 { /* Set a default viewport */
2208 WINED3DVIEWPORT vp;
2209 vp.X = 0;
2210 vp.Y = 0;
2211 vp.Width = pPresentationParameters->BackBufferWidth;
2212 vp.Height = pPresentationParameters->BackBufferHeight;
2213 vp.MinZ = 0.0f;
2214 vp.MaxZ = 1.0f;
2215 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2218 /* Initialize the current view state */
2219 This->view_ident = 1;
2220 This->contexts[0]->last_was_rhw = 0;
2221 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2222 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2224 switch(wined3d_settings.offscreen_rendering_mode) {
2225 case ORM_FBO:
2226 case ORM_PBUFFER:
2227 This->offscreenBuffer = GL_BACK;
2228 break;
2230 case ORM_BACKBUFFER:
2232 if(This->activeContext->aux_buffers > 0) {
2233 TRACE("Using auxilliary buffer for offscreen rendering\n");
2234 This->offscreenBuffer = GL_AUX0;
2235 } else {
2236 TRACE("Using back buffer for offscreen rendering\n");
2237 This->offscreenBuffer = GL_BACK;
2242 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2243 LEAVE_GL();
2245 /* Clear the screen */
2246 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2247 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2248 0x00, 1.0, 0);
2250 This->d3d_initialized = TRUE;
2252 if(wined3d_settings.logo) {
2253 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2255 This->highest_dirty_ps_const = 0;
2256 This->highest_dirty_vs_const = 0;
2257 return WINED3D_OK;
2259 err_out:
2260 HeapFree(GetProcessHeap(), 0, This->render_targets);
2261 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2262 HeapFree(GetProcessHeap(), 0, This->swapchains);
2263 This->NumberOfSwapChains = 0;
2264 if(This->palettes) {
2265 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2266 HeapFree(GetProcessHeap(), 0, This->palettes);
2268 This->NumberOfPalettes = 0;
2269 if(swapchain) {
2270 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2272 if(This->stateBlock) {
2273 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2274 This->stateBlock = NULL;
2276 if (This->blit_priv) {
2277 This->blitter->free_private(iface);
2279 if (This->fragment_priv) {
2280 This->frag_pipe->free_private(iface);
2282 if (This->shader_priv) {
2283 This->shader_backend->shader_free_private(iface);
2285 return hr;
2288 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2290 IWineD3DSwapChainImpl *swapchain = NULL;
2291 HRESULT hr;
2293 /* Setup the implicit swapchain */
2294 TRACE("Creating implicit swapchain\n");
2295 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2296 if (FAILED(hr) || !swapchain) {
2297 WARN("Failed to create implicit swapchain\n");
2298 goto err_out;
2301 This->NumberOfSwapChains = 1;
2302 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2303 if(!This->swapchains) {
2304 ERR("Out of memory!\n");
2305 goto err_out;
2307 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2308 return WINED3D_OK;
2310 err_out:
2311 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2312 return hr;
2315 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2317 int sampler;
2318 UINT i;
2319 TRACE("(%p)\n", This);
2321 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2323 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2324 * it was created. Thus make sure a context is active for the glDelete* calls
2326 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2328 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2330 TRACE("Deleting high order patches\n");
2331 for(i = 0; i < PATCHMAP_SIZE; i++) {
2332 struct list *e1, *e2;
2333 struct WineD3DRectPatch *patch;
2334 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2335 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2336 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2340 /* Delete the palette conversion shader if it is around */
2341 if(This->paletteConversionShader) {
2342 ENTER_GL();
2343 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2344 LEAVE_GL();
2345 This->paletteConversionShader = 0;
2348 /* Delete the pbuffer context if there is any */
2349 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2351 /* Delete the mouse cursor texture */
2352 if(This->cursorTexture) {
2353 ENTER_GL();
2354 glDeleteTextures(1, &This->cursorTexture);
2355 LEAVE_GL();
2356 This->cursorTexture = 0;
2359 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2360 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2362 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2363 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2366 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2367 * private data, it might contain opengl pointers
2369 if(This->depth_blt_texture) {
2370 glDeleteTextures(1, &This->depth_blt_texture);
2371 This->depth_blt_texture = 0;
2373 if (This->depth_blt_rb) {
2374 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2375 This->depth_blt_rb = 0;
2376 This->depth_blt_rb_w = 0;
2377 This->depth_blt_rb_h = 0;
2380 /* Release the update stateblock */
2381 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2382 if(This->updateStateBlock != This->stateBlock)
2383 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2385 This->updateStateBlock = NULL;
2387 { /* because were not doing proper internal refcounts releasing the primary state block
2388 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2389 to set this->stateBlock = NULL; first */
2390 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2391 This->stateBlock = NULL;
2393 /* Release the stateblock */
2394 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2395 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2399 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2400 This->blitter->free_private(iface);
2401 This->frag_pipe->free_private(iface);
2402 This->shader_backend->shader_free_private(iface);
2404 /* Release the buffers (with sanity checks)*/
2405 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2406 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2407 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2408 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2410 This->stencilBufferTarget = NULL;
2412 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2413 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2414 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2416 TRACE("Setting rendertarget to NULL\n");
2417 This->render_targets[0] = NULL;
2419 if (This->auto_depth_stencil_buffer) {
2420 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2421 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2423 This->auto_depth_stencil_buffer = NULL;
2426 for(i=0; i < This->NumberOfSwapChains; i++) {
2427 TRACE("Releasing the implicit swapchain %d\n", i);
2428 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2429 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2433 HeapFree(GetProcessHeap(), 0, This->swapchains);
2434 This->swapchains = NULL;
2435 This->NumberOfSwapChains = 0;
2437 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2438 HeapFree(GetProcessHeap(), 0, This->palettes);
2439 This->palettes = NULL;
2440 This->NumberOfPalettes = 0;
2442 HeapFree(GetProcessHeap(), 0, This->render_targets);
2443 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2444 This->render_targets = NULL;
2445 This->draw_buffers = NULL;
2447 This->d3d_initialized = FALSE;
2448 return WINED3D_OK;
2451 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2453 unsigned int i;
2455 for(i=0; i < This->NumberOfSwapChains; i++) {
2456 TRACE("Releasing the implicit swapchain %d\n", i);
2457 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2458 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2462 HeapFree(GetProcessHeap(), 0, This->swapchains);
2463 This->swapchains = NULL;
2464 This->NumberOfSwapChains = 0;
2465 return WINED3D_OK;
2468 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2469 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2470 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2472 * There is no way to deactivate thread safety once it is enabled.
2474 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2477 /*For now just store the flag(needed in case of ddraw) */
2478 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2480 return;
2483 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2484 const WINED3DDISPLAYMODE* pMode) {
2485 DEVMODEW devmode;
2486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2487 LONG ret;
2488 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2489 RECT clip_rc;
2491 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2493 /* Resize the screen even without a window:
2494 * The app could have unset it with SetCooperativeLevel, but not called
2495 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2496 * but we don't have any hwnd
2499 memset(&devmode, 0, sizeof(devmode));
2500 devmode.dmSize = sizeof(devmode);
2501 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2502 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2503 devmode.dmPelsWidth = pMode->Width;
2504 devmode.dmPelsHeight = pMode->Height;
2506 devmode.dmDisplayFrequency = pMode->RefreshRate;
2507 if (pMode->RefreshRate != 0) {
2508 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2511 /* Only change the mode if necessary */
2512 if( (This->ddraw_width == pMode->Width) &&
2513 (This->ddraw_height == pMode->Height) &&
2514 (This->ddraw_format == pMode->Format) &&
2515 (pMode->RefreshRate == 0) ) {
2516 return WINED3D_OK;
2519 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2520 if (ret != DISP_CHANGE_SUCCESSFUL) {
2521 if(devmode.dmDisplayFrequency != 0) {
2522 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2523 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2524 devmode.dmDisplayFrequency = 0;
2525 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2527 if(ret != DISP_CHANGE_SUCCESSFUL) {
2528 return WINED3DERR_NOTAVAILABLE;
2532 /* Store the new values */
2533 This->ddraw_width = pMode->Width;
2534 This->ddraw_height = pMode->Height;
2535 This->ddraw_format = pMode->Format;
2537 /* And finally clip mouse to our screen */
2538 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2539 ClipCursor(&clip_rc);
2541 return WINED3D_OK;
2544 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2546 *ppD3D= This->wineD3D;
2547 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2548 IWineD3D_AddRef(*ppD3D);
2549 return WINED3D_OK;
2552 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2555 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2556 (This->adapter->TextureRam/(1024*1024)),
2557 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2558 /* return simulated texture memory left */
2559 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2564 /*****
2565 * Get / Set FVF
2566 *****/
2567 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2570 /* Update the current state block */
2571 This->updateStateBlock->changed.fvf = TRUE;
2573 if(This->updateStateBlock->fvf == fvf) {
2574 TRACE("Application is setting the old fvf over, nothing to do\n");
2575 return WINED3D_OK;
2578 This->updateStateBlock->fvf = fvf;
2579 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2580 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2581 return WINED3D_OK;
2585 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2587 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2588 *pfvf = This->stateBlock->fvf;
2589 return WINED3D_OK;
2592 /*****
2593 * Get / Set Stream Source
2594 *****/
2595 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2597 IWineD3DVertexBuffer *oldSrc;
2599 if (StreamNumber >= MAX_STREAMS) {
2600 WARN("Stream out of range %d\n", StreamNumber);
2601 return WINED3DERR_INVALIDCALL;
2602 } else if(OffsetInBytes & 0x3) {
2603 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2604 return WINED3DERR_INVALIDCALL;
2607 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2608 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2610 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2612 if(oldSrc == pStreamData &&
2613 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2614 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2615 TRACE("Application is setting the old values over, nothing to do\n");
2616 return WINED3D_OK;
2619 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2620 if (pStreamData) {
2621 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2622 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2625 /* Handle recording of state blocks */
2626 if (This->isRecordingState) {
2627 TRACE("Recording... not performing anything\n");
2628 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2629 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2630 return WINED3D_OK;
2633 /* Need to do a getParent and pass the references up */
2634 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2635 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2636 so for now, just count internally */
2637 if (pStreamData != NULL) {
2638 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2639 InterlockedIncrement(&vbImpl->bindCount);
2640 IWineD3DVertexBuffer_AddRef(pStreamData);
2642 if (oldSrc != NULL) {
2643 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2644 IWineD3DVertexBuffer_Release(oldSrc);
2647 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2649 return WINED3D_OK;
2652 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2655 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2656 This->stateBlock->streamSource[StreamNumber],
2657 This->stateBlock->streamOffset[StreamNumber],
2658 This->stateBlock->streamStride[StreamNumber]);
2660 if (StreamNumber >= MAX_STREAMS) {
2661 WARN("Stream out of range %d\n", StreamNumber);
2662 return WINED3DERR_INVALIDCALL;
2664 *pStream = This->stateBlock->streamSource[StreamNumber];
2665 *pStride = This->stateBlock->streamStride[StreamNumber];
2666 if (pOffset) {
2667 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2670 if (*pStream != NULL) {
2671 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2673 return WINED3D_OK;
2676 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2678 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2679 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2681 /* Verify input at least in d3d9 this is invalid*/
2682 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2683 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2684 return WINED3DERR_INVALIDCALL;
2686 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2687 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2688 return WINED3DERR_INVALIDCALL;
2690 if( Divider == 0 ){
2691 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2692 return WINED3DERR_INVALIDCALL;
2695 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2696 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2698 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2699 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2701 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2702 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2703 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2706 return WINED3D_OK;
2709 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2712 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2713 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2715 TRACE("(%p) : returning %d\n", This, *Divider);
2717 return WINED3D_OK;
2720 /*****
2721 * Get / Set & Multiply Transform
2722 *****/
2723 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2726 /* Most of this routine, comments included copied from ddraw tree initially: */
2727 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2729 /* Handle recording of state blocks */
2730 if (This->isRecordingState) {
2731 TRACE("Recording... not performing anything\n");
2732 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2733 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2734 return WINED3D_OK;
2738 * If the new matrix is the same as the current one,
2739 * we cut off any further processing. this seems to be a reasonable
2740 * optimization because as was noticed, some apps (warcraft3 for example)
2741 * tend towards setting the same matrix repeatedly for some reason.
2743 * From here on we assume that the new matrix is different, wherever it matters.
2745 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2746 TRACE("The app is setting the same matrix over again\n");
2747 return WINED3D_OK;
2748 } else {
2749 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2753 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2754 where ViewMat = Camera space, WorldMat = world space.
2756 In OpenGL, camera and world space is combined into GL_MODELVIEW
2757 matrix. The Projection matrix stay projection matrix.
2760 /* Capture the times we can just ignore the change for now */
2761 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2762 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2763 /* Handled by the state manager */
2766 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2767 return WINED3D_OK;
2770 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2772 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2773 *pMatrix = This->stateBlock->transforms[State];
2774 return WINED3D_OK;
2777 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2778 const WINED3DMATRIX *mat = NULL;
2779 WINED3DMATRIX temp;
2781 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2782 * below means it will be recorded in a state block change, but it
2783 * works regardless where it is recorded.
2784 * If this is found to be wrong, change to StateBlock.
2786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2787 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2789 if (State < HIGHEST_TRANSFORMSTATE)
2791 mat = &This->updateStateBlock->transforms[State];
2792 } else {
2793 FIXME("Unhandled transform state!!\n");
2796 multiply_matrix(&temp, mat, pMatrix);
2798 /* Apply change via set transform - will reapply to eg. lights this way */
2799 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2802 /*****
2803 * Get / Set Light
2804 *****/
2805 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2806 you can reference any indexes you want as long as that number max are enabled at any
2807 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2808 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2809 but when recording, just build a chain pretty much of commands to be replayed. */
2811 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2812 float rho;
2813 PLIGHTINFOEL *object = NULL;
2814 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2815 struct list *e;
2817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2818 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2820 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2821 * the gl driver.
2823 if(!pLight) {
2824 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2825 return WINED3DERR_INVALIDCALL;
2828 switch(pLight->Type) {
2829 case WINED3DLIGHT_POINT:
2830 case WINED3DLIGHT_SPOT:
2831 case WINED3DLIGHT_PARALLELPOINT:
2832 case WINED3DLIGHT_GLSPOT:
2833 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2834 * most wanted
2836 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2837 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2838 return WINED3DERR_INVALIDCALL;
2840 break;
2842 case WINED3DLIGHT_DIRECTIONAL:
2843 /* Ignores attenuation */
2844 break;
2846 default:
2847 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2848 return WINED3DERR_INVALIDCALL;
2851 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2852 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2853 if(object->OriginalIndex == Index) break;
2854 object = NULL;
2857 if(!object) {
2858 TRACE("Adding new light\n");
2859 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2860 if(!object) {
2861 ERR("Out of memory error when allocating a light\n");
2862 return E_OUTOFMEMORY;
2864 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2865 object->glIndex = -1;
2866 object->OriginalIndex = Index;
2867 object->changed = TRUE;
2870 /* Initialize the object */
2871 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,
2872 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2873 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2874 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2875 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2876 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2877 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2879 /* Save away the information */
2880 object->OriginalParms = *pLight;
2882 switch (pLight->Type) {
2883 case WINED3DLIGHT_POINT:
2884 /* Position */
2885 object->lightPosn[0] = pLight->Position.x;
2886 object->lightPosn[1] = pLight->Position.y;
2887 object->lightPosn[2] = pLight->Position.z;
2888 object->lightPosn[3] = 1.0f;
2889 object->cutoff = 180.0f;
2890 /* FIXME: Range */
2891 break;
2893 case WINED3DLIGHT_DIRECTIONAL:
2894 /* Direction */
2895 object->lightPosn[0] = -pLight->Direction.x;
2896 object->lightPosn[1] = -pLight->Direction.y;
2897 object->lightPosn[2] = -pLight->Direction.z;
2898 object->lightPosn[3] = 0.0;
2899 object->exponent = 0.0f;
2900 object->cutoff = 180.0f;
2901 break;
2903 case WINED3DLIGHT_SPOT:
2904 /* Position */
2905 object->lightPosn[0] = pLight->Position.x;
2906 object->lightPosn[1] = pLight->Position.y;
2907 object->lightPosn[2] = pLight->Position.z;
2908 object->lightPosn[3] = 1.0;
2910 /* Direction */
2911 object->lightDirn[0] = pLight->Direction.x;
2912 object->lightDirn[1] = pLight->Direction.y;
2913 object->lightDirn[2] = pLight->Direction.z;
2914 object->lightDirn[3] = 1.0;
2917 * opengl-ish and d3d-ish spot lights use too different models for the
2918 * light "intensity" as a function of the angle towards the main light direction,
2919 * so we only can approximate very roughly.
2920 * however spot lights are rather rarely used in games (if ever used at all).
2921 * furthermore if still used, probably nobody pays attention to such details.
2923 if (pLight->Falloff == 0) {
2924 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2925 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2926 * will always be 1.0 for both of them, and we don't have to care for the
2927 * rest of the rather complex calculation
2929 object->exponent = 0;
2930 } else {
2931 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2932 if (rho < 0.0001) rho = 0.0001f;
2933 object->exponent = -0.3/log(cos(rho/2));
2935 if (object->exponent > 128.0) {
2936 object->exponent = 128.0;
2938 object->cutoff = pLight->Phi*90/M_PI;
2940 /* FIXME: Range */
2941 break;
2943 default:
2944 FIXME("Unrecognized light type %d\n", pLight->Type);
2947 /* Update the live definitions if the light is currently assigned a glIndex */
2948 if (object->glIndex != -1 && !This->isRecordingState) {
2949 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2951 return WINED3D_OK;
2954 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2955 PLIGHTINFOEL *lightInfo = NULL;
2956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2957 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2958 struct list *e;
2959 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2961 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2962 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2963 if(lightInfo->OriginalIndex == Index) break;
2964 lightInfo = NULL;
2967 if (lightInfo == NULL) {
2968 TRACE("Light information requested but light not defined\n");
2969 return WINED3DERR_INVALIDCALL;
2972 *pLight = lightInfo->OriginalParms;
2973 return WINED3D_OK;
2976 /*****
2977 * Get / Set Light Enable
2978 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2979 *****/
2980 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2981 PLIGHTINFOEL *lightInfo = NULL;
2982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2983 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2984 struct list *e;
2985 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2987 /* Tests show true = 128...not clear why */
2988 Enable = Enable? 128: 0;
2990 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2991 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2992 if(lightInfo->OriginalIndex == Index) break;
2993 lightInfo = NULL;
2995 TRACE("Found light: %p\n", lightInfo);
2997 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2998 if (lightInfo == NULL) {
3000 TRACE("Light enabled requested but light not defined, so defining one!\n");
3001 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3003 /* Search for it again! Should be fairly quick as near head of list */
3004 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3005 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3006 if(lightInfo->OriginalIndex == Index) break;
3007 lightInfo = NULL;
3009 if (lightInfo == NULL) {
3010 FIXME("Adding default lights has failed dismally\n");
3011 return WINED3DERR_INVALIDCALL;
3015 lightInfo->enabledChanged = TRUE;
3016 if(!Enable) {
3017 if(lightInfo->glIndex != -1) {
3018 if(!This->isRecordingState) {
3019 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3022 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3023 lightInfo->glIndex = -1;
3024 } else {
3025 TRACE("Light already disabled, nothing to do\n");
3027 lightInfo->enabled = FALSE;
3028 } else {
3029 lightInfo->enabled = TRUE;
3030 if (lightInfo->glIndex != -1) {
3031 /* nop */
3032 TRACE("Nothing to do as light was enabled\n");
3033 } else {
3034 int i;
3035 /* Find a free gl light */
3036 for(i = 0; i < This->maxConcurrentLights; i++) {
3037 if(This->updateStateBlock->activeLights[i] == NULL) {
3038 This->updateStateBlock->activeLights[i] = lightInfo;
3039 lightInfo->glIndex = i;
3040 break;
3043 if(lightInfo->glIndex == -1) {
3044 /* Our tests show that Windows returns D3D_OK in this situation, even with
3045 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3046 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3047 * as well for those lights.
3049 * TODO: Test how this affects rendering
3051 FIXME("Too many concurrently active lights\n");
3052 return WINED3D_OK;
3055 /* i == lightInfo->glIndex */
3056 if(!This->isRecordingState) {
3057 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3062 return WINED3D_OK;
3065 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3067 PLIGHTINFOEL *lightInfo = NULL;
3068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3069 struct list *e;
3070 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3071 TRACE("(%p) : for idx(%d)\n", This, Index);
3073 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3074 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3075 if(lightInfo->OriginalIndex == Index) break;
3076 lightInfo = NULL;
3079 if (lightInfo == NULL) {
3080 TRACE("Light enabled state requested but light not defined\n");
3081 return WINED3DERR_INVALIDCALL;
3083 /* true is 128 according to SetLightEnable */
3084 *pEnable = lightInfo->enabled ? 128 : 0;
3085 return WINED3D_OK;
3088 /*****
3089 * Get / Set Clip Planes
3090 *****/
3091 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3092 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3093 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3095 /* Validate Index */
3096 if (Index >= GL_LIMITS(clipplanes)) {
3097 TRACE("Application has requested clipplane this device doesn't support\n");
3098 return WINED3DERR_INVALIDCALL;
3101 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3103 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3104 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3105 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3106 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3107 TRACE("Application is setting old values over, nothing to do\n");
3108 return WINED3D_OK;
3111 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3112 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3113 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3114 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3116 /* Handle recording of state blocks */
3117 if (This->isRecordingState) {
3118 TRACE("Recording... not performing anything\n");
3119 return WINED3D_OK;
3122 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3124 return WINED3D_OK;
3127 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3129 TRACE("(%p) : for idx %d\n", This, Index);
3131 /* Validate Index */
3132 if (Index >= GL_LIMITS(clipplanes)) {
3133 TRACE("Application has requested clipplane this device doesn't support\n");
3134 return WINED3DERR_INVALIDCALL;
3137 pPlane[0] = This->stateBlock->clipplane[Index][0];
3138 pPlane[1] = This->stateBlock->clipplane[Index][1];
3139 pPlane[2] = This->stateBlock->clipplane[Index][2];
3140 pPlane[3] = This->stateBlock->clipplane[Index][3];
3141 return WINED3D_OK;
3144 /*****
3145 * Get / Set Clip Plane Status
3146 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3147 *****/
3148 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3150 FIXME("(%p) : stub\n", This);
3151 if (NULL == pClipStatus) {
3152 return WINED3DERR_INVALIDCALL;
3154 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3155 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3156 return WINED3D_OK;
3159 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3161 FIXME("(%p) : stub\n", This);
3162 if (NULL == pClipStatus) {
3163 return WINED3DERR_INVALIDCALL;
3165 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3166 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3167 return WINED3D_OK;
3170 /*****
3171 * Get / Set Material
3172 *****/
3173 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3176 This->updateStateBlock->changed.material = TRUE;
3177 This->updateStateBlock->material = *pMaterial;
3179 /* Handle recording of state blocks */
3180 if (This->isRecordingState) {
3181 TRACE("Recording... not performing anything\n");
3182 return WINED3D_OK;
3185 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3186 return WINED3D_OK;
3189 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3191 *pMaterial = This->updateStateBlock->material;
3192 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3193 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3194 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3195 pMaterial->Ambient.b, pMaterial->Ambient.a);
3196 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3197 pMaterial->Specular.b, pMaterial->Specular.a);
3198 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3199 pMaterial->Emissive.b, pMaterial->Emissive.a);
3200 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3202 return WINED3D_OK;
3205 /*****
3206 * Get / Set Indices
3207 *****/
3208 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3210 IWineD3DIndexBuffer *oldIdxs;
3212 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3213 oldIdxs = This->updateStateBlock->pIndexData;
3215 This->updateStateBlock->changed.indices = TRUE;
3216 This->updateStateBlock->pIndexData = pIndexData;
3218 /* Handle recording of state blocks */
3219 if (This->isRecordingState) {
3220 TRACE("Recording... not performing anything\n");
3221 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3222 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3223 return WINED3D_OK;
3226 if(oldIdxs != pIndexData) {
3227 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3228 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3229 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3231 return WINED3D_OK;
3234 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3237 *ppIndexData = This->stateBlock->pIndexData;
3239 /* up ref count on ppindexdata */
3240 if (*ppIndexData) {
3241 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3242 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3243 }else{
3244 TRACE("(%p) No index data set\n", This);
3246 TRACE("Returning %p\n", *ppIndexData);
3248 return WINED3D_OK;
3251 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3252 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3253 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3254 TRACE("(%p)->(%d)\n", This, BaseIndex);
3256 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3257 TRACE("Application is setting the old value over, nothing to do\n");
3258 return WINED3D_OK;
3261 This->updateStateBlock->baseVertexIndex = BaseIndex;
3263 if (This->isRecordingState) {
3264 TRACE("Recording... not performing anything\n");
3265 return WINED3D_OK;
3267 /* The base vertex index affects the stream sources */
3268 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3269 return WINED3D_OK;
3272 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3274 TRACE("(%p) : base_index %p\n", This, base_index);
3276 *base_index = This->stateBlock->baseVertexIndex;
3278 TRACE("Returning %u\n", *base_index);
3280 return WINED3D_OK;
3283 /*****
3284 * Get / Set Viewports
3285 *****/
3286 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3289 TRACE("(%p)\n", This);
3290 This->updateStateBlock->changed.viewport = TRUE;
3291 This->updateStateBlock->viewport = *pViewport;
3293 /* Handle recording of state blocks */
3294 if (This->isRecordingState) {
3295 TRACE("Recording... not performing anything\n");
3296 return WINED3D_OK;
3299 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3300 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3302 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3303 return WINED3D_OK;
3307 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3309 TRACE("(%p)\n", This);
3310 *pViewport = This->stateBlock->viewport;
3311 return WINED3D_OK;
3314 /*****
3315 * Get / Set Render States
3316 * TODO: Verify against dx9 definitions
3317 *****/
3318 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3321 DWORD oldValue = This->stateBlock->renderState[State];
3323 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3325 This->updateStateBlock->changed.renderState[State] = TRUE;
3326 This->updateStateBlock->renderState[State] = Value;
3328 /* Handle recording of state blocks */
3329 if (This->isRecordingState) {
3330 TRACE("Recording... not performing anything\n");
3331 return WINED3D_OK;
3334 /* Compared here and not before the assignment to allow proper stateblock recording */
3335 if(Value == oldValue) {
3336 TRACE("Application is setting the old value over, nothing to do\n");
3337 } else {
3338 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3341 return WINED3D_OK;
3344 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3346 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3347 *pValue = This->stateBlock->renderState[State];
3348 return WINED3D_OK;
3351 /*****
3352 * Get / Set Sampler States
3353 * TODO: Verify against dx9 definitions
3354 *****/
3356 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3358 DWORD oldValue;
3360 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3361 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3363 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3364 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3367 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3368 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3369 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3372 * SetSampler is designed to allow for more than the standard up to 8 textures
3373 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3374 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3376 * http://developer.nvidia.com/object/General_FAQ.html#t6
3378 * There are two new settings for GForce
3379 * the sampler one:
3380 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3381 * and the texture one:
3382 * GL_MAX_TEXTURE_COORDS_ARB.
3383 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3384 ******************/
3386 oldValue = This->stateBlock->samplerState[Sampler][Type];
3387 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3388 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3390 /* Handle recording of state blocks */
3391 if (This->isRecordingState) {
3392 TRACE("Recording... not performing anything\n");
3393 return WINED3D_OK;
3396 if(oldValue == Value) {
3397 TRACE("Application is setting the old value over, nothing to do\n");
3398 return WINED3D_OK;
3401 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3403 return WINED3D_OK;
3406 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3407 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3409 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3410 This, Sampler, debug_d3dsamplerstate(Type), Type);
3412 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3413 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3416 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3417 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3418 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3420 *Value = This->stateBlock->samplerState[Sampler][Type];
3421 TRACE("(%p) : Returning %#x\n", This, *Value);
3423 return WINED3D_OK;
3426 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3429 This->updateStateBlock->changed.scissorRect = TRUE;
3430 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3431 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3432 return WINED3D_OK;
3434 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3436 if(This->isRecordingState) {
3437 TRACE("Recording... not performing anything\n");
3438 return WINED3D_OK;
3441 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3443 return WINED3D_OK;
3446 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3449 *pRect = This->updateStateBlock->scissorRect;
3450 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3451 return WINED3D_OK;
3454 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3456 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3458 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3460 This->updateStateBlock->vertexDecl = pDecl;
3461 This->updateStateBlock->changed.vertexDecl = TRUE;
3463 if (This->isRecordingState) {
3464 TRACE("Recording... not performing anything\n");
3465 return WINED3D_OK;
3466 } else if(pDecl == oldDecl) {
3467 /* Checked after the assignment to allow proper stateblock recording */
3468 TRACE("Application is setting the old declaration over, nothing to do\n");
3469 return WINED3D_OK;
3472 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3473 return WINED3D_OK;
3476 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3479 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3481 *ppDecl = This->stateBlock->vertexDecl;
3482 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3483 return WINED3D_OK;
3486 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3488 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3490 This->updateStateBlock->vertexShader = pShader;
3491 This->updateStateBlock->changed.vertexShader = TRUE;
3493 if (This->isRecordingState) {
3494 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3495 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3496 TRACE("Recording... not performing anything\n");
3497 return WINED3D_OK;
3498 } else if(oldShader == pShader) {
3499 /* Checked here to allow proper stateblock recording */
3500 TRACE("App is setting the old shader over, nothing to do\n");
3501 return WINED3D_OK;
3504 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3505 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3506 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3508 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3510 return WINED3D_OK;
3513 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3516 if (NULL == ppShader) {
3517 return WINED3DERR_INVALIDCALL;
3519 *ppShader = This->stateBlock->vertexShader;
3520 if( NULL != *ppShader)
3521 IWineD3DVertexShader_AddRef(*ppShader);
3523 TRACE("(%p) : returning %p\n", This, *ppShader);
3524 return WINED3D_OK;
3527 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3528 IWineD3DDevice *iface,
3529 UINT start,
3530 CONST BOOL *srcData,
3531 UINT count) {
3533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3534 int i, cnt = min(count, MAX_CONST_B - start);
3536 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3537 iface, srcData, start, count);
3539 if (srcData == NULL || cnt < 0)
3540 return WINED3DERR_INVALIDCALL;
3542 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3543 for (i = 0; i < cnt; i++)
3544 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3546 for (i = start; i < cnt + start; ++i) {
3547 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3550 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3552 return WINED3D_OK;
3555 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3556 IWineD3DDevice *iface,
3557 UINT start,
3558 BOOL *dstData,
3559 UINT count) {
3561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3562 int cnt = min(count, MAX_CONST_B - start);
3564 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3565 iface, dstData, start, count);
3567 if (dstData == NULL || cnt < 0)
3568 return WINED3DERR_INVALIDCALL;
3570 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3571 return WINED3D_OK;
3574 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3575 IWineD3DDevice *iface,
3576 UINT start,
3577 CONST int *srcData,
3578 UINT count) {
3580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3581 int i, cnt = min(count, MAX_CONST_I - start);
3583 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3584 iface, srcData, start, count);
3586 if (srcData == NULL || cnt < 0)
3587 return WINED3DERR_INVALIDCALL;
3589 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3590 for (i = 0; i < cnt; i++)
3591 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3592 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3594 for (i = start; i < cnt + start; ++i) {
3595 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3598 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3600 return WINED3D_OK;
3603 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3604 IWineD3DDevice *iface,
3605 UINT start,
3606 int *dstData,
3607 UINT count) {
3609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3610 int cnt = min(count, MAX_CONST_I - start);
3612 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3613 iface, dstData, start, count);
3615 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3616 return WINED3DERR_INVALIDCALL;
3618 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3619 return WINED3D_OK;
3622 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3623 IWineD3DDevice *iface,
3624 UINT start,
3625 CONST float *srcData,
3626 UINT count) {
3628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3629 UINT i;
3631 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3632 iface, srcData, start, count);
3634 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3635 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3636 return WINED3DERR_INVALIDCALL;
3638 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3639 if(TRACE_ON(d3d)) {
3640 for (i = 0; i < count; i++)
3641 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3642 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3645 for (i = start; i < count + start; ++i) {
3646 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3647 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3648 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3649 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3650 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3652 ptr->idx[ptr->count++] = i;
3653 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3657 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3659 return WINED3D_OK;
3662 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3663 IWineD3DDevice *iface,
3664 UINT start,
3665 CONST float *srcData,
3666 UINT count) {
3668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3669 UINT i;
3671 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3672 iface, srcData, start, count);
3674 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3675 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3676 return WINED3DERR_INVALIDCALL;
3678 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3679 if(TRACE_ON(d3d)) {
3680 for (i = 0; i < count; i++)
3681 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3682 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3685 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3686 * context. On a context switch the old context will be fully dirtified
3688 memset(This->activeContext->vshader_const_dirty + start, 1,
3689 sizeof(*This->activeContext->vshader_const_dirty) * count);
3690 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count+1);
3692 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3694 return WINED3D_OK;
3697 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3698 IWineD3DDevice *iface,
3699 UINT start,
3700 float *dstData,
3701 UINT count) {
3703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3704 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3706 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3707 iface, dstData, start, count);
3709 if (dstData == NULL || cnt < 0)
3710 return WINED3DERR_INVALIDCALL;
3712 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3713 return WINED3D_OK;
3716 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3717 DWORD i;
3718 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3719 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3723 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3724 int i = This->rev_tex_unit_map[unit];
3725 int j = This->texUnitMap[stage];
3727 This->texUnitMap[stage] = unit;
3728 if (i != -1 && i != stage) {
3729 This->texUnitMap[i] = -1;
3732 This->rev_tex_unit_map[unit] = stage;
3733 if (j != -1 && j != unit) {
3734 This->rev_tex_unit_map[j] = -1;
3738 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3739 int i;
3741 for (i = 0; i < MAX_TEXTURES; ++i) {
3742 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3743 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3744 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3745 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3746 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3747 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3748 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3749 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3751 if (color_op == WINED3DTOP_DISABLE) {
3752 /* Not used, and disable higher stages */
3753 while (i < MAX_TEXTURES) {
3754 This->fixed_function_usage_map[i] = FALSE;
3755 ++i;
3757 break;
3760 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3761 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3762 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3763 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3764 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3765 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3766 This->fixed_function_usage_map[i] = TRUE;
3767 } else {
3768 This->fixed_function_usage_map[i] = FALSE;
3771 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3772 This->fixed_function_usage_map[i+1] = TRUE;
3777 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3778 int i, tex;
3780 device_update_fixed_function_usage_map(This);
3782 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3783 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3784 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3785 if (!This->fixed_function_usage_map[i]) continue;
3787 if (This->texUnitMap[i] != i) {
3788 device_map_stage(This, i, i);
3789 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3790 markTextureStagesDirty(This, i);
3793 return;
3796 /* Now work out the mapping */
3797 tex = 0;
3798 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3799 if (!This->fixed_function_usage_map[i]) continue;
3801 if (This->texUnitMap[i] != tex) {
3802 device_map_stage(This, i, tex);
3803 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3804 markTextureStagesDirty(This, i);
3807 ++tex;
3811 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3812 const DWORD *sampler_tokens =
3813 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3814 int i;
3816 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3817 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3818 device_map_stage(This, i, i);
3819 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3820 if (i < MAX_TEXTURES) {
3821 markTextureStagesDirty(This, i);
3827 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3828 const DWORD *vshader_sampler_tokens, int unit)
3830 int current_mapping = This->rev_tex_unit_map[unit];
3832 if (current_mapping == -1) {
3833 /* Not currently used */
3834 return TRUE;
3837 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3838 /* Used by a fragment sampler */
3840 if (!pshader_sampler_tokens) {
3841 /* No pixel shader, check fixed function */
3842 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3845 /* Pixel shader, check the shader's sampler map */
3846 return !pshader_sampler_tokens[current_mapping];
3849 /* Used by a vertex sampler */
3850 return !vshader_sampler_tokens[current_mapping];
3853 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3854 const DWORD *vshader_sampler_tokens =
3855 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3856 const DWORD *pshader_sampler_tokens = NULL;
3857 int start = GL_LIMITS(combined_samplers) - 1;
3858 int i;
3860 if (ps) {
3861 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3863 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3864 IWineD3DPixelShader_UpdateSamplers((IWineD3DPixelShader *)pshader);
3865 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3868 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3869 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3870 if (vshader_sampler_tokens[i]) {
3871 if (This->texUnitMap[vsampler_idx] != -1) {
3872 /* Already mapped somewhere */
3873 continue;
3876 while (start >= 0) {
3877 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3878 device_map_stage(This, vsampler_idx, start);
3879 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3881 --start;
3882 break;
3885 --start;
3891 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3892 BOOL vs = use_vs(This);
3893 BOOL ps = use_ps(This);
3895 * Rules are:
3896 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3897 * that would be really messy and require shader recompilation
3898 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3899 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3901 if (ps) {
3902 device_map_psamplers(This);
3903 } else {
3904 device_map_fixed_function_samplers(This);
3907 if (vs) {
3908 device_map_vsamplers(This, ps);
3912 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3914 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3915 This->updateStateBlock->pixelShader = pShader;
3916 This->updateStateBlock->changed.pixelShader = TRUE;
3918 /* Handle recording of state blocks */
3919 if (This->isRecordingState) {
3920 TRACE("Recording... not performing anything\n");
3923 if (This->isRecordingState) {
3924 TRACE("Recording... not performing anything\n");
3925 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3926 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3927 return WINED3D_OK;
3930 if(pShader == oldShader) {
3931 TRACE("App is setting the old pixel shader over, nothing to do\n");
3932 return WINED3D_OK;
3935 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3936 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3938 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3939 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3941 return WINED3D_OK;
3944 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3947 if (NULL == ppShader) {
3948 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3949 return WINED3DERR_INVALIDCALL;
3952 *ppShader = This->stateBlock->pixelShader;
3953 if (NULL != *ppShader) {
3954 IWineD3DPixelShader_AddRef(*ppShader);
3956 TRACE("(%p) : returning %p\n", This, *ppShader);
3957 return WINED3D_OK;
3960 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3961 IWineD3DDevice *iface,
3962 UINT start,
3963 CONST BOOL *srcData,
3964 UINT count) {
3966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3967 int i, cnt = min(count, MAX_CONST_B - start);
3969 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3970 iface, srcData, start, count);
3972 if (srcData == NULL || cnt < 0)
3973 return WINED3DERR_INVALIDCALL;
3975 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3976 for (i = 0; i < cnt; i++)
3977 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3979 for (i = start; i < cnt + start; ++i) {
3980 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3983 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3985 return WINED3D_OK;
3988 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3989 IWineD3DDevice *iface,
3990 UINT start,
3991 BOOL *dstData,
3992 UINT count) {
3994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3995 int cnt = min(count, MAX_CONST_B - start);
3997 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3998 iface, dstData, start, count);
4000 if (dstData == NULL || cnt < 0)
4001 return WINED3DERR_INVALIDCALL;
4003 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4004 return WINED3D_OK;
4007 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4008 IWineD3DDevice *iface,
4009 UINT start,
4010 CONST int *srcData,
4011 UINT count) {
4013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4014 int i, cnt = min(count, MAX_CONST_I - start);
4016 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4017 iface, srcData, start, count);
4019 if (srcData == NULL || cnt < 0)
4020 return WINED3DERR_INVALIDCALL;
4022 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4023 for (i = 0; i < cnt; i++)
4024 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4025 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4027 for (i = start; i < cnt + start; ++i) {
4028 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4031 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4033 return WINED3D_OK;
4036 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4037 IWineD3DDevice *iface,
4038 UINT start,
4039 int *dstData,
4040 UINT count) {
4042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4043 int cnt = min(count, MAX_CONST_I - start);
4045 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4046 iface, dstData, start, count);
4048 if (dstData == NULL || cnt < 0)
4049 return WINED3DERR_INVALIDCALL;
4051 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4052 return WINED3D_OK;
4055 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4056 IWineD3DDevice *iface,
4057 UINT start,
4058 CONST float *srcData,
4059 UINT count) {
4061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4062 UINT i;
4064 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4065 iface, srcData, start, count);
4067 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4068 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4069 return WINED3DERR_INVALIDCALL;
4071 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4072 if(TRACE_ON(d3d)) {
4073 for (i = 0; i < count; i++)
4074 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4075 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4078 for (i = start; i < count + start; ++i) {
4079 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
4080 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
4081 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
4082 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
4083 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
4085 ptr->idx[ptr->count++] = i;
4086 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4090 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4092 return WINED3D_OK;
4095 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4096 IWineD3DDevice *iface,
4097 UINT start,
4098 CONST float *srcData,
4099 UINT count) {
4101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4102 UINT i;
4104 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4105 iface, srcData, start, count);
4107 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4108 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4109 return WINED3DERR_INVALIDCALL;
4111 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4112 if(TRACE_ON(d3d)) {
4113 for (i = 0; i < count; i++)
4114 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4115 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4118 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4119 * context. On a context switch the old context will be fully dirtified
4121 memset(This->activeContext->pshader_const_dirty + start, 1,
4122 sizeof(*This->activeContext->pshader_const_dirty) * count);
4123 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count+1);
4125 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4127 return WINED3D_OK;
4130 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4131 IWineD3DDevice *iface,
4132 UINT start,
4133 float *dstData,
4134 UINT count) {
4136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4137 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4139 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4140 iface, dstData, start, count);
4142 if (dstData == NULL || cnt < 0)
4143 return WINED3DERR_INVALIDCALL;
4145 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4146 return WINED3D_OK;
4149 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4150 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4151 const WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags)
4153 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4154 unsigned int i;
4155 DWORD DestFVF = dest->fvf;
4156 WINED3DVIEWPORT vp;
4157 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4158 BOOL doClip;
4159 DWORD numTextures;
4161 if (lpStrideData->u.s.normal.lpData) {
4162 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4165 if (lpStrideData->u.s.position.lpData == NULL) {
4166 ERR("Source has no position mask\n");
4167 return WINED3DERR_INVALIDCALL;
4170 /* We might access VBOs from this code, so hold the lock */
4171 ENTER_GL();
4173 if (dest->resource.allocatedMemory == NULL) {
4174 /* This may happen if we do direct locking into a vbo. Unlikely,
4175 * but theoretically possible(ddraw processvertices test)
4177 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4178 if(!dest->resource.allocatedMemory) {
4179 LEAVE_GL();
4180 ERR("Out of memory\n");
4181 return E_OUTOFMEMORY;
4183 if(dest->vbo) {
4184 const void *src;
4185 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4186 checkGLcall("glBindBufferARB");
4187 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4188 if(src) {
4189 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4191 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4192 checkGLcall("glUnmapBufferARB");
4196 /* Get a pointer into the destination vbo(create one if none exists) and
4197 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4199 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4200 dest->Flags |= VBFLAG_CREATEVBO;
4201 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4204 if(dest->vbo) {
4205 unsigned char extrabytes = 0;
4206 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4207 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4208 * this may write 4 extra bytes beyond the area that should be written
4210 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4211 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4212 if(!dest_conv_addr) {
4213 ERR("Out of memory\n");
4214 /* Continue without storing converted vertices */
4216 dest_conv = dest_conv_addr;
4219 /* Should I clip?
4220 * a) WINED3DRS_CLIPPING is enabled
4221 * b) WINED3DVOP_CLIP is passed
4223 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4224 static BOOL warned = FALSE;
4226 * The clipping code is not quite correct. Some things need
4227 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4228 * so disable clipping for now.
4229 * (The graphics in Half-Life are broken, and my processvertices
4230 * test crashes with IDirect3DDevice3)
4231 doClip = TRUE;
4233 doClip = FALSE;
4234 if(!warned) {
4235 warned = TRUE;
4236 FIXME("Clipping is broken and disabled for now\n");
4238 } else doClip = FALSE;
4239 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4241 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4242 WINED3DTS_VIEW,
4243 &view_mat);
4244 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4245 WINED3DTS_PROJECTION,
4246 &proj_mat);
4247 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4248 WINED3DTS_WORLDMATRIX(0),
4249 &world_mat);
4251 TRACE("View mat:\n");
4252 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);
4253 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);
4254 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);
4255 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);
4257 TRACE("Proj mat:\n");
4258 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);
4259 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);
4260 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);
4261 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);
4263 TRACE("World mat:\n");
4264 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);
4265 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);
4266 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);
4267 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);
4269 /* Get the viewport */
4270 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4271 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4272 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4274 multiply_matrix(&mat,&view_mat,&world_mat);
4275 multiply_matrix(&mat,&proj_mat,&mat);
4277 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4279 for (i = 0; i < dwCount; i+= 1) {
4280 unsigned int tex_index;
4282 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4283 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4284 /* The position first */
4285 const float *p =
4286 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4287 float x, y, z, rhw;
4288 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4290 /* Multiplication with world, view and projection matrix */
4291 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);
4292 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);
4293 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);
4294 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);
4296 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4298 /* WARNING: The following things are taken from d3d7 and were not yet checked
4299 * against d3d8 or d3d9!
4302 /* Clipping conditions: From msdn
4304 * A vertex is clipped if it does not match the following requirements
4305 * -rhw < x <= rhw
4306 * -rhw < y <= rhw
4307 * 0 < z <= rhw
4308 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4310 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4311 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4315 if( !doClip ||
4316 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4317 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4318 ( rhw > eps ) ) ) {
4320 /* "Normal" viewport transformation (not clipped)
4321 * 1) The values are divided by rhw
4322 * 2) The y axis is negative, so multiply it with -1
4323 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4324 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4325 * 4) Multiply x with Width/2 and add Width/2
4326 * 5) The same for the height
4327 * 6) Add the viewpoint X and Y to the 2D coordinates and
4328 * The minimum Z value to z
4329 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4331 * Well, basically it's simply a linear transformation into viewport
4332 * coordinates
4335 x /= rhw;
4336 y /= rhw;
4337 z /= rhw;
4339 y *= -1;
4341 x *= vp.Width / 2;
4342 y *= vp.Height / 2;
4343 z *= vp.MaxZ - vp.MinZ;
4345 x += vp.Width / 2 + vp.X;
4346 y += vp.Height / 2 + vp.Y;
4347 z += vp.MinZ;
4349 rhw = 1 / rhw;
4350 } else {
4351 /* That vertex got clipped
4352 * Contrary to OpenGL it is not dropped completely, it just
4353 * undergoes a different calculation.
4355 TRACE("Vertex got clipped\n");
4356 x += rhw;
4357 y += rhw;
4359 x /= 2;
4360 y /= 2;
4362 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4363 * outside of the main vertex buffer memory. That needs some more
4364 * investigation...
4368 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4371 ( (float *) dest_ptr)[0] = x;
4372 ( (float *) dest_ptr)[1] = y;
4373 ( (float *) dest_ptr)[2] = z;
4374 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4376 dest_ptr += 3 * sizeof(float);
4378 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4379 dest_ptr += sizeof(float);
4382 if(dest_conv) {
4383 float w = 1 / rhw;
4384 ( (float *) dest_conv)[0] = x * w;
4385 ( (float *) dest_conv)[1] = y * w;
4386 ( (float *) dest_conv)[2] = z * w;
4387 ( (float *) dest_conv)[3] = w;
4389 dest_conv += 3 * sizeof(float);
4391 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4392 dest_conv += sizeof(float);
4396 if (DestFVF & WINED3DFVF_PSIZE) {
4397 dest_ptr += sizeof(DWORD);
4398 if(dest_conv) dest_conv += sizeof(DWORD);
4400 if (DestFVF & WINED3DFVF_NORMAL) {
4401 const float *normal =
4402 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4403 /* AFAIK this should go into the lighting information */
4404 FIXME("Didn't expect the destination to have a normal\n");
4405 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4406 if(dest_conv) {
4407 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4411 if (DestFVF & WINED3DFVF_DIFFUSE) {
4412 const DWORD *color_d =
4413 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4414 if(!color_d) {
4415 static BOOL warned = FALSE;
4417 if(!warned) {
4418 ERR("No diffuse color in source, but destination has one\n");
4419 warned = TRUE;
4422 *( (DWORD *) dest_ptr) = 0xffffffff;
4423 dest_ptr += sizeof(DWORD);
4425 if(dest_conv) {
4426 *( (DWORD *) dest_conv) = 0xffffffff;
4427 dest_conv += sizeof(DWORD);
4430 else {
4431 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4432 if(dest_conv) {
4433 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4434 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4435 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4436 dest_conv += sizeof(DWORD);
4441 if (DestFVF & WINED3DFVF_SPECULAR) {
4442 /* What's the color value in the feedback buffer? */
4443 const DWORD *color_s =
4444 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4445 if(!color_s) {
4446 static BOOL warned = FALSE;
4448 if(!warned) {
4449 ERR("No specular color in source, but destination has one\n");
4450 warned = TRUE;
4453 *( (DWORD *) dest_ptr) = 0xFF000000;
4454 dest_ptr += sizeof(DWORD);
4456 if(dest_conv) {
4457 *( (DWORD *) dest_conv) = 0xFF000000;
4458 dest_conv += sizeof(DWORD);
4461 else {
4462 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4463 if(dest_conv) {
4464 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4465 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4466 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4467 dest_conv += sizeof(DWORD);
4472 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4473 const float *tex_coord =
4474 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4475 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4476 if(!tex_coord) {
4477 ERR("No source texture, but destination requests one\n");
4478 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4479 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4481 else {
4482 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4483 if(dest_conv) {
4484 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4490 if(dest_conv) {
4491 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4492 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4493 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4494 dwCount * get_flexible_vertex_size(DestFVF),
4495 dest_conv_addr));
4496 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4497 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4500 LEAVE_GL();
4502 return WINED3D_OK;
4504 #undef copy_and_next
4506 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4507 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4508 WineDirect3DVertexStridedData strided;
4509 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4510 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4512 if(pVertexDecl) {
4513 ERR("Output vertex declaration not implemented yet\n");
4516 /* Need any context to write to the vbo. */
4517 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4519 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4520 * control the streamIsUP flag, thus restore it afterwards.
4522 This->stateBlock->streamIsUP = FALSE;
4523 memset(&strided, 0, sizeof(strided));
4524 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4525 This->stateBlock->streamIsUP = streamWasUP;
4527 if(vbo || SrcStartIndex) {
4528 unsigned int i;
4529 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4530 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4532 * Also get the start index in, but only loop over all elements if there's something to add at all.
4534 #define FIXSRC(type) \
4535 if(strided.u.s.type.VBO) { \
4536 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4537 strided.u.s.type.VBO = 0; \
4538 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4539 ENTER_GL(); \
4540 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4541 vb->vbo = 0; \
4542 LEAVE_GL(); \
4544 if(strided.u.s.type.lpData) { \
4545 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4547 FIXSRC(position);
4548 FIXSRC(blendWeights);
4549 FIXSRC(blendMatrixIndices);
4550 FIXSRC(normal);
4551 FIXSRC(pSize);
4552 FIXSRC(diffuse);
4553 FIXSRC(specular);
4554 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4555 FIXSRC(texCoords[i]);
4557 FIXSRC(position2);
4558 FIXSRC(normal2);
4559 FIXSRC(tangent);
4560 FIXSRC(binormal);
4561 FIXSRC(tessFactor);
4562 FIXSRC(fog);
4563 FIXSRC(depth);
4564 FIXSRC(sample);
4565 #undef FIXSRC
4568 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4571 /*****
4572 * Get / Set Texture Stage States
4573 * TODO: Verify against dx9 definitions
4574 *****/
4575 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4577 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4579 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4581 if (Stage >= MAX_TEXTURES) {
4582 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4583 return WINED3D_OK;
4586 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4587 This->updateStateBlock->textureState[Stage][Type] = Value;
4589 if (This->isRecordingState) {
4590 TRACE("Recording... not performing anything\n");
4591 return WINED3D_OK;
4594 /* Checked after the assignments to allow proper stateblock recording */
4595 if(oldValue == Value) {
4596 TRACE("App is setting the old value over, nothing to do\n");
4597 return WINED3D_OK;
4600 if(Stage > This->stateBlock->lowest_disabled_stage &&
4601 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4602 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4603 * Changes in other states are important on disabled stages too
4605 return WINED3D_OK;
4608 if(Type == WINED3DTSS_COLOROP) {
4609 int i;
4611 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4612 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4613 * they have to be disabled
4615 * The current stage is dirtified below.
4617 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4618 TRACE("Additionally dirtifying stage %d\n", i);
4619 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4621 This->stateBlock->lowest_disabled_stage = Stage;
4622 TRACE("New lowest disabled: %d\n", Stage);
4623 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4624 /* Previously disabled stage enabled. Stages above it may need enabling
4625 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4626 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4628 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4631 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4632 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4633 break;
4635 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4636 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4638 This->stateBlock->lowest_disabled_stage = i;
4639 TRACE("New lowest disabled: %d\n", i);
4643 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4645 return WINED3D_OK;
4648 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4650 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4651 *pValue = This->updateStateBlock->textureState[Stage][Type];
4652 return WINED3D_OK;
4655 /*****
4656 * Get / Set Texture
4657 *****/
4658 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4660 IWineD3DBaseTexture *oldTexture;
4662 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4664 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4665 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4668 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4669 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4670 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4673 oldTexture = This->updateStateBlock->textures[Stage];
4675 if(pTexture != NULL) {
4676 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4678 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4679 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4680 return WINED3DERR_INVALIDCALL;
4682 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4685 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4686 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4688 This->updateStateBlock->changed.textures[Stage] = TRUE;
4689 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4690 This->updateStateBlock->textures[Stage] = pTexture;
4692 /* Handle recording of state blocks */
4693 if (This->isRecordingState) {
4694 TRACE("Recording... not performing anything\n");
4695 return WINED3D_OK;
4698 if(oldTexture == pTexture) {
4699 TRACE("App is setting the same texture again, nothing to do\n");
4700 return WINED3D_OK;
4703 /** NOTE: MSDN says that setTexture increases the reference count,
4704 * and that the application must set the texture back to null (or have a leaky application),
4705 * This means we should pass the refcount up to the parent
4706 *******************************/
4707 if (NULL != This->updateStateBlock->textures[Stage]) {
4708 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4709 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4711 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4712 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4713 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4714 * so the COLOROP and ALPHAOP have to be dirtified.
4716 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4719 if(bindCount == 1) {
4720 new->baseTexture.sampler = Stage;
4722 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4726 if (NULL != oldTexture) {
4727 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4728 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4730 IWineD3DBaseTexture_Release(oldTexture);
4731 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4732 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4733 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4736 if(bindCount && old->baseTexture.sampler == Stage) {
4737 int i;
4738 /* Have to do a search for the other sampler(s) where the texture is bound to
4739 * Shouldn't happen as long as apps bind a texture only to one stage
4741 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4742 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4743 if(This->updateStateBlock->textures[i] == oldTexture) {
4744 old->baseTexture.sampler = i;
4745 break;
4751 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4753 return WINED3D_OK;
4756 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4759 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4761 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4762 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4765 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4766 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4767 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4770 *ppTexture=This->stateBlock->textures[Stage];
4771 if (*ppTexture)
4772 IWineD3DBaseTexture_AddRef(*ppTexture);
4774 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4776 return WINED3D_OK;
4779 /*****
4780 * Get Back Buffer
4781 *****/
4782 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4783 IWineD3DSurface **ppBackBuffer) {
4784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4785 IWineD3DSwapChain *swapChain;
4786 HRESULT hr;
4788 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4790 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4791 if (hr == WINED3D_OK) {
4792 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4793 IWineD3DSwapChain_Release(swapChain);
4794 } else {
4795 *ppBackBuffer = NULL;
4797 return hr;
4800 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4802 WARN("(%p) : stub, calling idirect3d for now\n", This);
4803 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4806 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4808 IWineD3DSwapChain *swapChain;
4809 HRESULT hr;
4811 if(iSwapChain > 0) {
4812 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4813 if (hr == WINED3D_OK) {
4814 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4815 IWineD3DSwapChain_Release(swapChain);
4816 } else {
4817 FIXME("(%p) Error getting display mode\n", This);
4819 } else {
4820 /* Don't read the real display mode,
4821 but return the stored mode instead. X11 can't change the color
4822 depth, and some apps are pretty angry if they SetDisplayMode from
4823 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4825 Also don't relay to the swapchain because with ddraw it's possible
4826 that there isn't a swapchain at all */
4827 pMode->Width = This->ddraw_width;
4828 pMode->Height = This->ddraw_height;
4829 pMode->Format = This->ddraw_format;
4830 pMode->RefreshRate = 0;
4831 hr = WINED3D_OK;
4834 return hr;
4837 /*****
4838 * Stateblock related functions
4839 *****/
4841 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4843 IWineD3DStateBlockImpl *object;
4844 HRESULT temp_result;
4845 int i;
4847 TRACE("(%p)\n", This);
4849 if (This->isRecordingState) {
4850 return WINED3DERR_INVALIDCALL;
4853 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4854 if (NULL == object ) {
4855 FIXME("(%p)Error allocating memory for stateblock\n", This);
4856 return E_OUTOFMEMORY;
4858 TRACE("(%p) created object %p\n", This, object);
4859 object->wineD3DDevice= This;
4860 /** FIXME: object->parent = parent; **/
4861 object->parent = NULL;
4862 object->blockType = WINED3DSBT_RECORDED;
4863 object->ref = 1;
4864 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4866 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4867 list_init(&object->lightMap[i]);
4870 temp_result = allocate_shader_constants(object);
4871 if (WINED3D_OK != temp_result)
4872 return temp_result;
4874 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4875 This->updateStateBlock = object;
4876 This->isRecordingState = TRUE;
4878 TRACE("(%p) recording stateblock %p\n",This , object);
4879 return WINED3D_OK;
4882 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4884 unsigned int i, j;
4885 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4887 if (!This->isRecordingState) {
4888 FIXME("(%p) not recording! returning error\n", This);
4889 *ppStateBlock = NULL;
4890 return WINED3DERR_INVALIDCALL;
4893 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4894 if(object->changed.renderState[i]) {
4895 object->contained_render_states[object->num_contained_render_states] = i;
4896 object->num_contained_render_states++;
4899 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4900 if(object->changed.transform[i]) {
4901 object->contained_transform_states[object->num_contained_transform_states] = i;
4902 object->num_contained_transform_states++;
4905 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4906 if(object->changed.vertexShaderConstantsF[i]) {
4907 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4908 object->num_contained_vs_consts_f++;
4911 for(i = 0; i < MAX_CONST_I; i++) {
4912 if(object->changed.vertexShaderConstantsI[i]) {
4913 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4914 object->num_contained_vs_consts_i++;
4917 for(i = 0; i < MAX_CONST_B; i++) {
4918 if(object->changed.vertexShaderConstantsB[i]) {
4919 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4920 object->num_contained_vs_consts_b++;
4923 for(i = 0; i < MAX_CONST_I; i++) {
4924 if(object->changed.pixelShaderConstantsI[i]) {
4925 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4926 object->num_contained_ps_consts_i++;
4929 for(i = 0; i < MAX_CONST_B; i++) {
4930 if(object->changed.pixelShaderConstantsB[i]) {
4931 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4932 object->num_contained_ps_consts_b++;
4935 for(i = 0; i < MAX_TEXTURES; i++) {
4936 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4937 if(object->changed.textureState[i][j]) {
4938 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4939 object->contained_tss_states[object->num_contained_tss_states].state = j;
4940 object->num_contained_tss_states++;
4944 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4945 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4946 if(object->changed.samplerState[i][j]) {
4947 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4948 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4949 object->num_contained_sampler_states++;
4954 *ppStateBlock = (IWineD3DStateBlock*) object;
4955 This->isRecordingState = FALSE;
4956 This->updateStateBlock = This->stateBlock;
4957 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4958 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4959 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4960 return WINED3D_OK;
4963 /*****
4964 * Scene related functions
4965 *****/
4966 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4967 /* At the moment we have no need for any functionality at the beginning
4968 of a scene */
4969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4970 TRACE("(%p)\n", This);
4972 if(This->inScene) {
4973 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4974 return WINED3DERR_INVALIDCALL;
4976 This->inScene = TRUE;
4977 return WINED3D_OK;
4980 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4982 TRACE("(%p)\n", This);
4984 if(!This->inScene) {
4985 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4986 return WINED3DERR_INVALIDCALL;
4989 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4990 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4991 glFlush();
4992 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4993 * fails
4996 This->inScene = FALSE;
4997 return WINED3D_OK;
5000 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5001 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5002 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5004 IWineD3DSwapChain *swapChain = NULL;
5005 int i;
5006 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5008 TRACE("(%p) Presenting the frame\n", This);
5010 for(i = 0 ; i < swapchains ; i ++) {
5012 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5013 TRACE("presentinng chain %d, %p\n", i, swapChain);
5014 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5015 IWineD3DSwapChain_Release(swapChain);
5018 return WINED3D_OK;
5021 /* Not called from the VTable (internal subroutine) */
5022 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5023 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5024 float Z, DWORD Stencil) {
5025 GLbitfield glMask = 0;
5026 unsigned int i;
5027 WINED3DRECT curRect;
5028 RECT vp_rect;
5029 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5030 UINT drawable_width, drawable_height;
5031 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5032 IWineD3DSwapChainImpl *swapchain = NULL;
5034 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5035 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5036 * for the cleared parts, and the untouched parts.
5038 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5039 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5040 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5041 * checking all this if the dest surface is in the drawable anyway.
5043 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5044 while(1) {
5045 if(vp->X != 0 || vp->Y != 0 ||
5046 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5047 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5048 break;
5050 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5051 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5052 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5053 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5054 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5055 break;
5057 if(Count > 0 && pRects && (
5058 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5059 pRects[0].x2 < target->currentDesc.Width ||
5060 pRects[0].y2 < target->currentDesc.Height)) {
5061 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5062 break;
5064 break;
5068 target->get_drawable_size(target, &drawable_width, &drawable_height);
5070 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5071 ENTER_GL();
5073 /* Only set the values up once, as they are not changing */
5074 if (Flags & WINED3DCLEAR_STENCIL) {
5075 glClearStencil(Stencil);
5076 checkGLcall("glClearStencil");
5077 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5078 glStencilMask(0xFFFFFFFF);
5081 if (Flags & WINED3DCLEAR_ZBUFFER) {
5082 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5083 glDepthMask(GL_TRUE);
5084 glClearDepth(Z);
5085 checkGLcall("glClearDepth");
5086 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5087 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5089 if (vp->X != 0 || vp->Y != 0 ||
5090 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5091 surface_load_ds_location(This->stencilBufferTarget, location);
5093 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5094 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5095 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5096 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5097 surface_load_ds_location(This->stencilBufferTarget, location);
5099 else if (Count > 0 && pRects && (
5100 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5101 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5102 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5103 surface_load_ds_location(This->stencilBufferTarget, location);
5107 if (Flags & WINED3DCLEAR_TARGET) {
5108 TRACE("Clearing screen with glClear to color %x\n", Color);
5109 glClearColor(D3DCOLOR_R(Color),
5110 D3DCOLOR_G(Color),
5111 D3DCOLOR_B(Color),
5112 D3DCOLOR_A(Color));
5113 checkGLcall("glClearColor");
5115 /* Clear ALL colors! */
5116 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5117 glMask = glMask | GL_COLOR_BUFFER_BIT;
5120 vp_rect.left = vp->X;
5121 vp_rect.top = vp->Y;
5122 vp_rect.right = vp->X + vp->Width;
5123 vp_rect.bottom = vp->Y + vp->Height;
5124 if (!(Count > 0 && pRects)) {
5125 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5126 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5128 if(This->render_offscreen) {
5129 glScissor(vp_rect.left, vp_rect.top,
5130 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5131 } else {
5132 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5133 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5135 checkGLcall("glScissor");
5136 glClear(glMask);
5137 checkGLcall("glClear");
5138 } else {
5139 /* Now process each rect in turn */
5140 for (i = 0; i < Count; i++) {
5141 /* Note gl uses lower left, width/height */
5142 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5143 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5144 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5146 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5147 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5148 curRect.x1, (target->currentDesc.Height - curRect.y2),
5149 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5151 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5152 * The rectangle is not cleared, no error is returned, but further rectanlges are
5153 * still cleared if they are valid
5155 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5156 TRACE("Rectangle with negative dimensions, ignoring\n");
5157 continue;
5160 if(This->render_offscreen) {
5161 glScissor(curRect.x1, curRect.y1,
5162 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5163 } else {
5164 glScissor(curRect.x1, drawable_height - curRect.y2,
5165 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5167 checkGLcall("glScissor");
5169 glClear(glMask);
5170 checkGLcall("glClear");
5174 /* Restore the old values (why..?) */
5175 if (Flags & WINED3DCLEAR_STENCIL) {
5176 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5178 if (Flags & WINED3DCLEAR_TARGET) {
5179 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5180 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5181 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5182 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5183 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5185 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5186 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5188 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5190 if (Flags & WINED3DCLEAR_ZBUFFER) {
5191 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5192 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5193 surface_modify_ds_location(This->stencilBufferTarget, location);
5196 LEAVE_GL();
5198 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5199 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5200 glFlush();
5202 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5205 return WINED3D_OK;
5208 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5209 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5211 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5213 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5214 Count, pRects, Flags, Color, Z, Stencil);
5216 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5217 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5218 /* TODO: What about depth stencil buffers without stencil bits? */
5219 return WINED3DERR_INVALIDCALL;
5222 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5225 /*****
5226 * Drawing functions
5227 *****/
5228 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5229 UINT PrimitiveCount) {
5231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5233 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5234 debug_d3dprimitivetype(PrimitiveType),
5235 StartVertex, PrimitiveCount);
5237 if(!This->stateBlock->vertexDecl) {
5238 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5239 return WINED3DERR_INVALIDCALL;
5242 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5243 if(This->stateBlock->streamIsUP) {
5244 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5245 This->stateBlock->streamIsUP = FALSE;
5248 if(This->stateBlock->loadBaseVertexIndex != 0) {
5249 This->stateBlock->loadBaseVertexIndex = 0;
5250 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5252 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5253 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5254 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5255 return WINED3D_OK;
5258 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5259 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5260 WINED3DPRIMITIVETYPE PrimitiveType,
5261 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5264 UINT idxStride = 2;
5265 IWineD3DIndexBuffer *pIB;
5266 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5267 GLuint vbo;
5269 pIB = This->stateBlock->pIndexData;
5270 if (!pIB) {
5271 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5272 * without an index buffer set. (The first time at least...)
5273 * D3D8 simply dies, but I doubt it can do much harm to return
5274 * D3DERR_INVALIDCALL there as well. */
5275 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5276 return WINED3DERR_INVALIDCALL;
5279 if(!This->stateBlock->vertexDecl) {
5280 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5281 return WINED3DERR_INVALIDCALL;
5284 if(This->stateBlock->streamIsUP) {
5285 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5286 This->stateBlock->streamIsUP = FALSE;
5288 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5290 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5291 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5292 minIndex, NumVertices, startIndex, primCount);
5294 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5295 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5296 idxStride = 2;
5297 } else {
5298 idxStride = 4;
5301 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5302 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5303 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5306 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5307 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5309 return WINED3D_OK;
5312 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5313 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5314 UINT VertexStreamZeroStride) {
5315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5316 IWineD3DVertexBuffer *vb;
5318 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5319 debug_d3dprimitivetype(PrimitiveType),
5320 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5322 if(!This->stateBlock->vertexDecl) {
5323 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5324 return WINED3DERR_INVALIDCALL;
5327 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5328 vb = This->stateBlock->streamSource[0];
5329 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5330 if(vb) IWineD3DVertexBuffer_Release(vb);
5331 This->stateBlock->streamOffset[0] = 0;
5332 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5333 This->stateBlock->streamIsUP = TRUE;
5334 This->stateBlock->loadBaseVertexIndex = 0;
5336 /* TODO: Only mark dirty if drawing from a different UP address */
5337 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5339 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5340 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5342 /* MSDN specifies stream zero settings must be set to NULL */
5343 This->stateBlock->streamStride[0] = 0;
5344 This->stateBlock->streamSource[0] = NULL;
5346 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5347 * the new stream sources or use UP drawing again
5349 return WINED3D_OK;
5352 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5353 UINT MinVertexIndex, UINT NumVertices,
5354 UINT PrimitiveCount, CONST void* pIndexData,
5355 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5356 UINT VertexStreamZeroStride) {
5357 int idxStride;
5358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5359 IWineD3DVertexBuffer *vb;
5360 IWineD3DIndexBuffer *ib;
5362 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5363 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5364 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5365 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5367 if(!This->stateBlock->vertexDecl) {
5368 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5369 return WINED3DERR_INVALIDCALL;
5372 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5373 idxStride = 2;
5374 } else {
5375 idxStride = 4;
5378 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5379 vb = This->stateBlock->streamSource[0];
5380 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5381 if(vb) IWineD3DVertexBuffer_Release(vb);
5382 This->stateBlock->streamIsUP = TRUE;
5383 This->stateBlock->streamOffset[0] = 0;
5384 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5386 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5387 This->stateBlock->baseVertexIndex = 0;
5388 This->stateBlock->loadBaseVertexIndex = 0;
5389 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5390 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5391 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5393 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5395 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5396 This->stateBlock->streamSource[0] = NULL;
5397 This->stateBlock->streamStride[0] = 0;
5398 ib = This->stateBlock->pIndexData;
5399 if(ib) {
5400 IWineD3DIndexBuffer_Release(ib);
5401 This->stateBlock->pIndexData = NULL;
5403 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5404 * SetStreamSource to specify a vertex buffer
5407 return WINED3D_OK;
5410 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5411 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5413 /* Mark the state dirty until we have nicer tracking
5414 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5415 * that value.
5417 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5418 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5419 This->stateBlock->baseVertexIndex = 0;
5420 This->up_strided = DrawPrimStrideData;
5421 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5422 This->up_strided = NULL;
5423 return WINED3D_OK;
5426 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5428 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5430 /* Mark the state dirty until we have nicer tracking
5431 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5432 * that value.
5434 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5435 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5436 This->stateBlock->streamIsUP = TRUE;
5437 This->stateBlock->baseVertexIndex = 0;
5438 This->up_strided = DrawPrimStrideData;
5439 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5440 This->up_strided = NULL;
5441 return WINED3D_OK;
5444 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5445 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5446 * not callable by the app directly no parameter validation checks are needed here.
5448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5449 WINED3DLOCKED_BOX src;
5450 WINED3DLOCKED_BOX dst;
5451 HRESULT hr;
5452 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5454 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5455 * dirtification to improve loading performance.
5457 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5458 if(FAILED(hr)) return hr;
5459 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5460 if(FAILED(hr)) {
5461 IWineD3DVolume_UnlockBox(pSourceVolume);
5462 return hr;
5465 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5467 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5468 if(FAILED(hr)) {
5469 IWineD3DVolume_UnlockBox(pSourceVolume);
5470 } else {
5471 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5473 return hr;
5476 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5477 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5479 HRESULT hr = WINED3D_OK;
5480 WINED3DRESOURCETYPE sourceType;
5481 WINED3DRESOURCETYPE destinationType;
5482 int i ,levels;
5484 /* TODO: think about moving the code into IWineD3DBaseTexture */
5486 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5488 /* verify that the source and destination textures aren't NULL */
5489 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5490 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5491 This, pSourceTexture, pDestinationTexture);
5492 hr = WINED3DERR_INVALIDCALL;
5495 if (pSourceTexture == pDestinationTexture) {
5496 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5497 This, pSourceTexture, pDestinationTexture);
5498 hr = WINED3DERR_INVALIDCALL;
5500 /* Verify that the source and destination textures are the same type */
5501 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5502 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5504 if (sourceType != destinationType) {
5505 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5506 This);
5507 hr = WINED3DERR_INVALIDCALL;
5510 /* check that both textures have the identical numbers of levels */
5511 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5512 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5513 hr = WINED3DERR_INVALIDCALL;
5516 if (WINED3D_OK == hr) {
5518 /* Make sure that the destination texture is loaded */
5519 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5521 /* Update every surface level of the texture */
5522 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5524 switch (sourceType) {
5525 case WINED3DRTYPE_TEXTURE:
5527 IWineD3DSurface *srcSurface;
5528 IWineD3DSurface *destSurface;
5530 for (i = 0 ; i < levels ; ++i) {
5531 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5532 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5533 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5534 IWineD3DSurface_Release(srcSurface);
5535 IWineD3DSurface_Release(destSurface);
5536 if (WINED3D_OK != hr) {
5537 WARN("(%p) : Call to update surface failed\n", This);
5538 return hr;
5542 break;
5543 case WINED3DRTYPE_CUBETEXTURE:
5545 IWineD3DSurface *srcSurface;
5546 IWineD3DSurface *destSurface;
5547 WINED3DCUBEMAP_FACES faceType;
5549 for (i = 0 ; i < levels ; ++i) {
5550 /* Update each cube face */
5551 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5552 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5553 if (WINED3D_OK != hr) {
5554 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5555 } else {
5556 TRACE("Got srcSurface %p\n", srcSurface);
5558 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5559 if (WINED3D_OK != hr) {
5560 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5561 } else {
5562 TRACE("Got desrSurface %p\n", destSurface);
5564 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5565 IWineD3DSurface_Release(srcSurface);
5566 IWineD3DSurface_Release(destSurface);
5567 if (WINED3D_OK != hr) {
5568 WARN("(%p) : Call to update surface failed\n", This);
5569 return hr;
5574 break;
5576 case WINED3DRTYPE_VOLUMETEXTURE:
5578 IWineD3DVolume *srcVolume = NULL;
5579 IWineD3DVolume *destVolume = NULL;
5581 for (i = 0 ; i < levels ; ++i) {
5582 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5583 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5584 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5585 IWineD3DVolume_Release(srcVolume);
5586 IWineD3DVolume_Release(destVolume);
5587 if (WINED3D_OK != hr) {
5588 WARN("(%p) : Call to update volume failed\n", This);
5589 return hr;
5593 break;
5595 default:
5596 FIXME("(%p) : Unsupported source and destination type\n", This);
5597 hr = WINED3DERR_INVALIDCALL;
5601 return hr;
5604 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5605 IWineD3DSwapChain *swapChain;
5606 HRESULT hr;
5607 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5608 if(hr == WINED3D_OK) {
5609 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5610 IWineD3DSwapChain_Release(swapChain);
5612 return hr;
5615 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5617 IWineD3DBaseTextureImpl *texture;
5618 const GlPixelFormatDesc *gl_info;
5619 DWORD i;
5621 TRACE("(%p) : %p\n", This, pNumPasses);
5623 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5624 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5625 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5626 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5628 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5629 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5630 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5633 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5634 if(!texture) continue;
5635 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5636 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5638 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5639 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5640 return E_FAIL;
5642 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5643 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5644 return E_FAIL;
5646 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5647 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5648 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5649 return E_FAIL;
5653 /* return a sensible default */
5654 *pNumPasses = 1;
5656 TRACE("returning D3D_OK\n");
5657 return WINED3D_OK;
5660 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5662 int i;
5664 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5665 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5666 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5667 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5672 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5674 int j;
5675 UINT NewSize;
5676 PALETTEENTRY **palettes;
5678 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5680 if (PaletteNumber >= MAX_PALETTES) {
5681 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5682 return WINED3DERR_INVALIDCALL;
5685 if (PaletteNumber >= This->NumberOfPalettes) {
5686 NewSize = This->NumberOfPalettes;
5687 do {
5688 NewSize *= 2;
5689 } while(PaletteNumber >= NewSize);
5690 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5691 if (!palettes) {
5692 ERR("Out of memory!\n");
5693 return E_OUTOFMEMORY;
5695 This->palettes = palettes;
5696 This->NumberOfPalettes = NewSize;
5699 if (!This->palettes[PaletteNumber]) {
5700 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5701 if (!This->palettes[PaletteNumber]) {
5702 ERR("Out of memory!\n");
5703 return E_OUTOFMEMORY;
5707 for (j = 0; j < 256; ++j) {
5708 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5709 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5710 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5711 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5713 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5714 TRACE("(%p) : returning\n", This);
5715 return WINED3D_OK;
5718 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5719 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5720 int j;
5721 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5722 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5723 /* What happens in such situation isn't documented; Native seems to silently abort
5724 on such conditions. Return Invalid Call. */
5725 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5726 return WINED3DERR_INVALIDCALL;
5728 for (j = 0; j < 256; ++j) {
5729 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5730 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5731 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5732 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5734 TRACE("(%p) : returning\n", This);
5735 return WINED3D_OK;
5738 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5740 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5741 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5742 (tested with reference rasterizer). Return Invalid Call. */
5743 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5744 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5745 return WINED3DERR_INVALIDCALL;
5747 /*TODO: stateblocks */
5748 if (This->currentPalette != PaletteNumber) {
5749 This->currentPalette = PaletteNumber;
5750 dirtify_p8_texture_samplers(This);
5752 TRACE("(%p) : returning\n", This);
5753 return WINED3D_OK;
5756 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5758 if (PaletteNumber == NULL) {
5759 WARN("(%p) : returning Invalid Call\n", This);
5760 return WINED3DERR_INVALIDCALL;
5762 /*TODO: stateblocks */
5763 *PaletteNumber = This->currentPalette;
5764 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5765 return WINED3D_OK;
5768 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5770 static BOOL showFixmes = TRUE;
5771 if (showFixmes) {
5772 FIXME("(%p) : stub\n", This);
5773 showFixmes = FALSE;
5776 This->softwareVertexProcessing = bSoftware;
5777 return WINED3D_OK;
5781 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5783 static BOOL showFixmes = TRUE;
5784 if (showFixmes) {
5785 FIXME("(%p) : stub\n", This);
5786 showFixmes = FALSE;
5788 return This->softwareVertexProcessing;
5792 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5794 IWineD3DSwapChain *swapChain;
5795 HRESULT hr;
5797 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5799 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5800 if(hr == WINED3D_OK){
5801 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5802 IWineD3DSwapChain_Release(swapChain);
5803 }else{
5804 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5806 return hr;
5810 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5812 static BOOL showfixmes = TRUE;
5813 if(nSegments != 0.0f) {
5814 if( showfixmes) {
5815 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5816 showfixmes = FALSE;
5819 return WINED3D_OK;
5822 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5824 static BOOL showfixmes = TRUE;
5825 if( showfixmes) {
5826 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5827 showfixmes = FALSE;
5829 return 0.0f;
5832 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5834 /** TODO: remove casts to IWineD3DSurfaceImpl
5835 * NOTE: move code to surface to accomplish this
5836 ****************************************/
5837 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5838 int srcWidth, srcHeight;
5839 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5840 WINED3DFORMAT destFormat, srcFormat;
5841 UINT destSize;
5842 int srcLeft, destLeft, destTop;
5843 WINED3DPOOL srcPool, destPool;
5844 int offset = 0;
5845 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5846 glDescriptor *glDescription = NULL;
5847 GLenum dummy;
5848 int sampler;
5849 int bpp;
5850 CONVERT_TYPES convert = NO_CONVERSION;
5852 WINED3DSURFACE_DESC winedesc;
5854 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5855 memset(&winedesc, 0, sizeof(winedesc));
5856 winedesc.Width = &srcSurfaceWidth;
5857 winedesc.Height = &srcSurfaceHeight;
5858 winedesc.Pool = &srcPool;
5859 winedesc.Format = &srcFormat;
5861 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5863 winedesc.Width = &destSurfaceWidth;
5864 winedesc.Height = &destSurfaceHeight;
5865 winedesc.Pool = &destPool;
5866 winedesc.Format = &destFormat;
5867 winedesc.Size = &destSize;
5869 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5871 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5872 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5873 return WINED3DERR_INVALIDCALL;
5876 /* This call loads the opengl surface directly, instead of copying the surface to the
5877 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5878 * copy in sysmem and use regular surface loading.
5880 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5881 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5882 if(convert != NO_CONVERSION) {
5883 return IWineD3DSurface_BltFast(pDestinationSurface,
5884 pDestPoint ? pDestPoint->x : 0,
5885 pDestPoint ? pDestPoint->y : 0,
5886 pSourceSurface, pSourceRect, 0);
5889 if (destFormat == WINED3DFMT_UNKNOWN) {
5890 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5891 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5893 /* Get the update surface description */
5894 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5897 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5899 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5900 ENTER_GL();
5901 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5902 checkGLcall("glActiveTextureARB");
5903 LEAVE_GL();
5906 /* Make sure the surface is loaded and up to date */
5907 IWineD3DSurface_PreLoad(pDestinationSurface);
5908 IWineD3DSurface_BindTexture(pDestinationSurface);
5910 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5912 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5913 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5914 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5915 srcLeft = pSourceRect ? pSourceRect->left : 0;
5916 destLeft = pDestPoint ? pDestPoint->x : 0;
5917 destTop = pDestPoint ? pDestPoint->y : 0;
5920 /* This function doesn't support compressed textures
5921 the pitch is just bytesPerPixel * width */
5922 if(srcWidth != srcSurfaceWidth || srcLeft ){
5923 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5924 offset += srcLeft * pSrcSurface->bytesPerPixel;
5925 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5927 /* TODO DXT formats */
5929 if(pSourceRect != NULL && pSourceRect->top != 0){
5930 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5932 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5933 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat,
5934 glDescription->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5936 /* Sanity check */
5937 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5939 /* need to lock the surface to get the data */
5940 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5943 ENTER_GL();
5945 /* TODO: Cube and volume support */
5946 if(rowoffset != 0){
5947 /* not a whole row so we have to do it a line at a time */
5948 int j;
5950 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5951 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5953 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5955 glTexSubImage2D(glDescription->target
5956 ,glDescription->level
5957 ,destLeft
5959 ,srcWidth
5961 ,glDescription->glFormat
5962 ,glDescription->glType
5963 ,data /* could be quicker using */
5965 data += rowoffset;
5968 } else { /* Full width, so just write out the whole texture */
5969 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5971 if (WINED3DFMT_DXT1 == destFormat ||
5972 WINED3DFMT_DXT2 == destFormat ||
5973 WINED3DFMT_DXT3 == destFormat ||
5974 WINED3DFMT_DXT4 == destFormat ||
5975 WINED3DFMT_DXT5 == destFormat) {
5976 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5977 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5978 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5979 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5980 } if (destFormat != srcFormat) {
5981 FIXME("Updating mixed format compressed texture is not curretly support\n");
5982 } else {
5983 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
5984 glDescription->glFormatInternal, srcWidth, srcHeight, 0, destSize, data));
5986 } else {
5987 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5991 } else {
5992 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
5993 srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, data);
5996 checkGLcall("glTexSubImage2D");
5998 LEAVE_GL();
6000 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6001 sampler = This->rev_tex_unit_map[0];
6002 if (sampler != -1) {
6003 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6006 return WINED3D_OK;
6009 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6011 struct WineD3DRectPatch *patch;
6012 unsigned int i;
6013 struct list *e;
6014 BOOL found;
6015 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6017 if(!(Handle || pRectPatchInfo)) {
6018 /* TODO: Write a test for the return value, thus the FIXME */
6019 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6020 return WINED3DERR_INVALIDCALL;
6023 if(Handle) {
6024 i = PATCHMAP_HASHFUNC(Handle);
6025 found = FALSE;
6026 LIST_FOR_EACH(e, &This->patches[i]) {
6027 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6028 if(patch->Handle == Handle) {
6029 found = TRUE;
6030 break;
6034 if(!found) {
6035 TRACE("Patch does not exist. Creating a new one\n");
6036 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6037 patch->Handle = Handle;
6038 list_add_head(&This->patches[i], &patch->entry);
6039 } else {
6040 TRACE("Found existing patch %p\n", patch);
6042 } else {
6043 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6044 * attributes we have to tesselate, read back, and draw. This needs a patch
6045 * management structure instance. Create one.
6047 * A possible improvement is to check if a vertex shader is used, and if not directly
6048 * draw the patch.
6050 FIXME("Drawing an uncached patch. This is slow\n");
6051 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6054 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6055 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6056 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6057 HRESULT hr;
6058 TRACE("Tesselation density or patch info changed, retesselating\n");
6060 if(pRectPatchInfo) {
6061 patch->RectPatchInfo = *pRectPatchInfo;
6063 patch->numSegs[0] = pNumSegs[0];
6064 patch->numSegs[1] = pNumSegs[1];
6065 patch->numSegs[2] = pNumSegs[2];
6066 patch->numSegs[3] = pNumSegs[3];
6068 hr = tesselate_rectpatch(This, patch);
6069 if(FAILED(hr)) {
6070 WARN("Patch tesselation failed\n");
6072 /* Do not release the handle to store the params of the patch */
6073 if(!Handle) {
6074 HeapFree(GetProcessHeap(), 0, patch);
6076 return hr;
6080 This->currentPatch = patch;
6081 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6082 This->currentPatch = NULL;
6084 /* Destroy uncached patches */
6085 if(!Handle) {
6086 HeapFree(GetProcessHeap(), 0, patch->mem);
6087 HeapFree(GetProcessHeap(), 0, patch);
6089 return WINED3D_OK;
6092 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6094 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6095 FIXME("(%p) : Stub\n", This);
6096 return WINED3D_OK;
6099 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6101 int i;
6102 struct WineD3DRectPatch *patch;
6103 struct list *e;
6104 TRACE("(%p) Handle(%d)\n", This, Handle);
6106 i = PATCHMAP_HASHFUNC(Handle);
6107 LIST_FOR_EACH(e, &This->patches[i]) {
6108 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6109 if(patch->Handle == Handle) {
6110 TRACE("Deleting patch %p\n", patch);
6111 list_remove(&patch->entry);
6112 HeapFree(GetProcessHeap(), 0, patch->mem);
6113 HeapFree(GetProcessHeap(), 0, patch);
6114 return WINED3D_OK;
6118 /* TODO: Write a test for the return value */
6119 FIXME("Attempt to destroy nonexistent patch\n");
6120 return WINED3DERR_INVALIDCALL;
6123 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6124 HRESULT hr;
6125 IWineD3DSwapChain *swapchain;
6127 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6128 if (SUCCEEDED(hr)) {
6129 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6130 return swapchain;
6133 return NULL;
6136 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6138 IWineD3DSwapChain *swapchain;
6140 swapchain = get_swapchain(surface);
6141 if (swapchain) {
6142 GLenum buffer;
6144 TRACE("Surface %p is onscreen\n", surface);
6146 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6147 ENTER_GL();
6148 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6149 buffer = surface_get_gl_buffer(surface, swapchain);
6150 glDrawBuffer(buffer);
6151 checkGLcall("glDrawBuffer()");
6152 } else {
6153 TRACE("Surface %p is offscreen\n", surface);
6155 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6156 ENTER_GL();
6157 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6158 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6159 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6160 checkGLcall("glFramebufferRenderbufferEXT");
6163 if (rect) {
6164 glEnable(GL_SCISSOR_TEST);
6165 if(!swapchain) {
6166 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6167 } else {
6168 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6169 rect->x2 - rect->x1, rect->y2 - rect->y1);
6171 checkGLcall("glScissor");
6172 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6173 } else {
6174 glDisable(GL_SCISSOR_TEST);
6176 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6178 glDisable(GL_BLEND);
6179 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6181 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6182 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6184 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6185 glClear(GL_COLOR_BUFFER_BIT);
6186 checkGLcall("glClear");
6188 if (This->activeContext->current_fbo) {
6189 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6190 } else {
6191 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6192 checkGLcall("glBindFramebuffer()");
6195 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6196 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6197 glDrawBuffer(GL_BACK);
6198 checkGLcall("glDrawBuffer()");
6201 LEAVE_GL();
6204 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6205 unsigned int r, g, b, a;
6206 DWORD ret;
6208 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6209 destfmt == WINED3DFMT_R8G8B8)
6210 return color;
6212 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6214 a = (color & 0xff000000) >> 24;
6215 r = (color & 0x00ff0000) >> 16;
6216 g = (color & 0x0000ff00) >> 8;
6217 b = (color & 0x000000ff) >> 0;
6219 switch(destfmt)
6221 case WINED3DFMT_R5G6B5:
6222 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6223 r = (r * 32) / 256;
6224 g = (g * 64) / 256;
6225 b = (b * 32) / 256;
6226 ret = r << 11;
6227 ret |= g << 5;
6228 ret |= b;
6229 TRACE("Returning %08x\n", ret);
6230 return ret;
6232 case WINED3DFMT_X1R5G5B5:
6233 case WINED3DFMT_A1R5G5B5:
6234 a = (a * 2) / 256;
6235 r = (r * 32) / 256;
6236 g = (g * 32) / 256;
6237 b = (b * 32) / 256;
6238 ret = a << 15;
6239 ret |= r << 10;
6240 ret |= g << 5;
6241 ret |= b << 0;
6242 TRACE("Returning %08x\n", ret);
6243 return ret;
6245 case WINED3DFMT_A8:
6246 TRACE("Returning %08x\n", a);
6247 return a;
6249 case WINED3DFMT_X4R4G4B4:
6250 case WINED3DFMT_A4R4G4B4:
6251 a = (a * 16) / 256;
6252 r = (r * 16) / 256;
6253 g = (g * 16) / 256;
6254 b = (b * 16) / 256;
6255 ret = a << 12;
6256 ret |= r << 8;
6257 ret |= g << 4;
6258 ret |= b << 0;
6259 TRACE("Returning %08x\n", ret);
6260 return ret;
6262 case WINED3DFMT_R3G3B2:
6263 r = (r * 8) / 256;
6264 g = (g * 8) / 256;
6265 b = (b * 4) / 256;
6266 ret = r << 5;
6267 ret |= g << 2;
6268 ret |= b << 0;
6269 TRACE("Returning %08x\n", ret);
6270 return ret;
6272 case WINED3DFMT_X8B8G8R8:
6273 case WINED3DFMT_A8B8G8R8:
6274 ret = a << 24;
6275 ret |= b << 16;
6276 ret |= g << 8;
6277 ret |= r << 0;
6278 TRACE("Returning %08x\n", ret);
6279 return ret;
6281 case WINED3DFMT_A2R10G10B10:
6282 a = (a * 4) / 256;
6283 r = (r * 1024) / 256;
6284 g = (g * 1024) / 256;
6285 b = (b * 1024) / 256;
6286 ret = a << 30;
6287 ret |= r << 20;
6288 ret |= g << 10;
6289 ret |= b << 0;
6290 TRACE("Returning %08x\n", ret);
6291 return ret;
6293 case WINED3DFMT_A2B10G10R10:
6294 a = (a * 4) / 256;
6295 r = (r * 1024) / 256;
6296 g = (g * 1024) / 256;
6297 b = (b * 1024) / 256;
6298 ret = a << 30;
6299 ret |= b << 20;
6300 ret |= g << 10;
6301 ret |= r << 0;
6302 TRACE("Returning %08x\n", ret);
6303 return ret;
6305 default:
6306 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6307 return 0;
6311 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6313 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6314 WINEDDBLTFX BltFx;
6315 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6317 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6318 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6319 return WINED3DERR_INVALIDCALL;
6322 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6323 color_fill_fbo(iface, pSurface, pRect, color);
6324 return WINED3D_OK;
6325 } else {
6326 /* Just forward this to the DirectDraw blitting engine */
6327 memset(&BltFx, 0, sizeof(BltFx));
6328 BltFx.dwSize = sizeof(BltFx);
6329 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6330 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6331 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6335 /* rendertarget and depth stencil functions */
6336 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6339 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6340 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6341 return WINED3DERR_INVALIDCALL;
6344 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6345 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6346 /* Note inc ref on returned surface */
6347 if(*ppRenderTarget != NULL)
6348 IWineD3DSurface_AddRef(*ppRenderTarget);
6349 return WINED3D_OK;
6352 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6353 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6354 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6355 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6356 IWineD3DSwapChainImpl *Swapchain;
6357 HRESULT hr;
6359 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6361 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6362 if(hr != WINED3D_OK) {
6363 ERR("Can't get the swapchain\n");
6364 return hr;
6367 /* Make sure to release the swapchain */
6368 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6370 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6371 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6372 return WINED3DERR_INVALIDCALL;
6374 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6375 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6376 return WINED3DERR_INVALIDCALL;
6379 if(Swapchain->frontBuffer != Front) {
6380 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6382 if(Swapchain->frontBuffer)
6383 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6384 Swapchain->frontBuffer = Front;
6386 if(Swapchain->frontBuffer) {
6387 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6391 if(Back && !Swapchain->backBuffer) {
6392 /* We need memory for the back buffer array - only one back buffer this way */
6393 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6394 if(!Swapchain->backBuffer) {
6395 ERR("Out of memory\n");
6396 return E_OUTOFMEMORY;
6400 if(Swapchain->backBuffer[0] != Back) {
6401 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6403 /* What to do about the context here in the case of multithreading? Not sure.
6404 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6406 ENTER_GL();
6407 if(!Swapchain->backBuffer[0]) {
6408 /* GL was told to draw to the front buffer at creation,
6409 * undo that
6411 glDrawBuffer(GL_BACK);
6412 checkGLcall("glDrawBuffer(GL_BACK)");
6413 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6414 Swapchain->presentParms.BackBufferCount = 1;
6415 } else if (!Back) {
6416 /* That makes problems - disable for now */
6417 /* glDrawBuffer(GL_FRONT); */
6418 checkGLcall("glDrawBuffer(GL_FRONT)");
6419 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6420 Swapchain->presentParms.BackBufferCount = 0;
6422 LEAVE_GL();
6424 if(Swapchain->backBuffer[0])
6425 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6426 Swapchain->backBuffer[0] = Back;
6428 if(Swapchain->backBuffer[0]) {
6429 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6430 } else {
6431 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6432 Swapchain->backBuffer = NULL;
6437 return WINED3D_OK;
6440 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6442 *ppZStencilSurface = This->stencilBufferTarget;
6443 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6445 if(*ppZStencilSurface != NULL) {
6446 /* Note inc ref on returned surface */
6447 IWineD3DSurface_AddRef(*ppZStencilSurface);
6448 return WINED3D_OK;
6449 } else {
6450 return WINED3DERR_NOTFOUND;
6454 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6455 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6458 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6459 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6460 GLenum gl_filter;
6461 POINT offset = {0, 0};
6463 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6464 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6465 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6466 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6468 switch (filter) {
6469 case WINED3DTEXF_LINEAR:
6470 gl_filter = GL_LINEAR;
6471 break;
6473 default:
6474 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6475 case WINED3DTEXF_NONE:
6476 case WINED3DTEXF_POINT:
6477 gl_filter = GL_NEAREST;
6478 break;
6481 /* Attach src surface to src fbo */
6482 src_swapchain = get_swapchain(src_surface);
6483 if (src_swapchain) {
6484 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6486 TRACE("Source surface %p is onscreen\n", src_surface);
6487 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6488 /* Make sure the drawable is up to date. In the offscreen case
6489 * attach_surface_fbo() implicitly takes care of this. */
6490 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6492 if(buffer == GL_FRONT) {
6493 RECT windowsize;
6494 UINT h;
6495 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6496 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6497 h = windowsize.bottom - windowsize.top;
6498 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6499 src_rect->y1 = offset.y + h - src_rect->y1;
6500 src_rect->y2 = offset.y + h - src_rect->y2;
6501 } else {
6502 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6503 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6506 ENTER_GL();
6507 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6508 glReadBuffer(buffer);
6509 checkGLcall("glReadBuffer()");
6510 } else {
6511 TRACE("Source surface %p is offscreen\n", src_surface);
6512 ENTER_GL();
6513 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6514 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6515 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6516 checkGLcall("glReadBuffer()");
6517 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6518 checkGLcall("glFramebufferRenderbufferEXT");
6520 LEAVE_GL();
6522 /* Attach dst surface to dst fbo */
6523 dst_swapchain = get_swapchain(dst_surface);
6524 if (dst_swapchain) {
6525 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6527 TRACE("Destination surface %p is onscreen\n", dst_surface);
6528 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6529 /* Make sure the drawable is up to date. In the offscreen case
6530 * attach_surface_fbo() implicitly takes care of this. */
6531 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6533 if(buffer == GL_FRONT) {
6534 RECT windowsize;
6535 UINT h;
6536 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6537 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6538 h = windowsize.bottom - windowsize.top;
6539 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6540 dst_rect->y1 = offset.y + h - dst_rect->y1;
6541 dst_rect->y2 = offset.y + h - dst_rect->y2;
6542 } else {
6543 /* Screen coords = window coords, surface height = window height */
6544 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6545 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6548 ENTER_GL();
6549 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6550 glDrawBuffer(buffer);
6551 checkGLcall("glDrawBuffer()");
6552 } else {
6553 TRACE("Destination surface %p is offscreen\n", dst_surface);
6555 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6556 if(!src_swapchain) {
6557 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6560 ENTER_GL();
6561 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6562 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6563 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6564 checkGLcall("glDrawBuffer()");
6565 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6566 checkGLcall("glFramebufferRenderbufferEXT");
6568 glDisable(GL_SCISSOR_TEST);
6569 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6571 if (flip) {
6572 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6573 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6574 checkGLcall("glBlitFramebuffer()");
6575 } else {
6576 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6577 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6578 checkGLcall("glBlitFramebuffer()");
6581 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6583 if (This->activeContext->current_fbo) {
6584 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6585 } else {
6586 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6587 checkGLcall("glBindFramebuffer()");
6590 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6591 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6592 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6593 glDrawBuffer(GL_BACK);
6594 checkGLcall("glDrawBuffer()");
6596 LEAVE_GL();
6599 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6601 WINED3DVIEWPORT viewport;
6603 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6605 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6606 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6607 This, RenderTargetIndex, GL_LIMITS(buffers));
6608 return WINED3DERR_INVALIDCALL;
6611 /* MSDN says that null disables the render target
6612 but a device must always be associated with a render target
6613 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6615 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6616 FIXME("Trying to set render target 0 to NULL\n");
6617 return WINED3DERR_INVALIDCALL;
6619 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6620 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);
6621 return WINED3DERR_INVALIDCALL;
6624 /* If we are trying to set what we already have, don't bother */
6625 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6626 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6627 return WINED3D_OK;
6629 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6630 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6631 This->render_targets[RenderTargetIndex] = pRenderTarget;
6633 /* Render target 0 is special */
6634 if(RenderTargetIndex == 0) {
6635 /* Finally, reset the viewport as the MSDN states. */
6636 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6637 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6638 viewport.X = 0;
6639 viewport.Y = 0;
6640 viewport.MaxZ = 1.0f;
6641 viewport.MinZ = 0.0f;
6642 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6643 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6644 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6646 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6648 return WINED3D_OK;
6651 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6653 HRESULT hr = WINED3D_OK;
6654 IWineD3DSurface *tmp;
6656 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6658 if (pNewZStencil == This->stencilBufferTarget) {
6659 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6660 } else {
6661 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6662 * depending on the renter target implementation being used.
6663 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6664 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6665 * stencil buffer and incur an extra memory overhead
6666 ******************************************************/
6668 if (This->stencilBufferTarget) {
6669 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6670 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6671 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6672 } else {
6673 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6674 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6675 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6679 tmp = This->stencilBufferTarget;
6680 This->stencilBufferTarget = pNewZStencil;
6681 /* should we be calling the parent or the wined3d surface? */
6682 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6683 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6684 hr = WINED3D_OK;
6686 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6687 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6688 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6689 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6690 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6694 return hr;
6697 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6698 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6700 /* TODO: the use of Impl is deprecated. */
6701 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6702 WINED3DLOCKED_RECT lockedRect;
6704 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6706 /* some basic validation checks */
6707 if(This->cursorTexture) {
6708 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6709 ENTER_GL();
6710 glDeleteTextures(1, &This->cursorTexture);
6711 LEAVE_GL();
6712 This->cursorTexture = 0;
6715 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6716 This->haveHardwareCursor = TRUE;
6717 else
6718 This->haveHardwareCursor = FALSE;
6720 if(pCursorBitmap) {
6721 WINED3DLOCKED_RECT rect;
6723 /* MSDN: Cursor must be A8R8G8B8 */
6724 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6725 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6726 return WINED3DERR_INVALIDCALL;
6729 /* MSDN: Cursor must be smaller than the display mode */
6730 if(pSur->currentDesc.Width > This->ddraw_width ||
6731 pSur->currentDesc.Height > This->ddraw_height) {
6732 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);
6733 return WINED3DERR_INVALIDCALL;
6736 if (!This->haveHardwareCursor) {
6737 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6739 /* Do not store the surface's pointer because the application may
6740 * release it after setting the cursor image. Windows doesn't
6741 * addref the set surface, so we can't do this either without
6742 * creating circular refcount dependencies. Copy out the gl texture
6743 * instead.
6745 This->cursorWidth = pSur->currentDesc.Width;
6746 This->cursorHeight = pSur->currentDesc.Height;
6747 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6749 const GlPixelFormatDesc *glDesc;
6750 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6751 char *mem, *bits = (char *)rect.pBits;
6752 GLint intfmt = glDesc->glInternal;
6753 GLint format = glDesc->glFormat;
6754 GLint type = glDesc->glType;
6755 INT height = This->cursorHeight;
6756 INT width = This->cursorWidth;
6757 INT bpp = tableEntry->bpp;
6758 INT i, sampler;
6760 /* Reformat the texture memory (pitch and width can be
6761 * different) */
6762 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6763 for(i = 0; i < height; i++)
6764 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6765 IWineD3DSurface_UnlockRect(pCursorBitmap);
6766 ENTER_GL();
6768 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6769 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6770 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6773 /* Make sure that a proper texture unit is selected */
6774 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6775 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6776 checkGLcall("glActiveTextureARB");
6778 sampler = This->rev_tex_unit_map[0];
6779 if (sampler != -1) {
6780 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6782 /* Create a new cursor texture */
6783 glGenTextures(1, &This->cursorTexture);
6784 checkGLcall("glGenTextures");
6785 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6786 checkGLcall("glBindTexture");
6787 /* Copy the bitmap memory into the cursor texture */
6788 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6789 HeapFree(GetProcessHeap(), 0, mem);
6790 checkGLcall("glTexImage2D");
6792 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6793 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6794 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6797 LEAVE_GL();
6799 else
6801 FIXME("A cursor texture was not returned.\n");
6802 This->cursorTexture = 0;
6805 else
6807 /* Draw a hardware cursor */
6808 ICONINFO cursorInfo;
6809 HCURSOR cursor;
6810 /* Create and clear maskBits because it is not needed for
6811 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6812 * chunks. */
6813 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6814 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6815 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6816 WINED3DLOCK_NO_DIRTY_UPDATE |
6817 WINED3DLOCK_READONLY
6819 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6820 pSur->currentDesc.Height);
6822 cursorInfo.fIcon = FALSE;
6823 cursorInfo.xHotspot = XHotSpot;
6824 cursorInfo.yHotspot = YHotSpot;
6825 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6826 pSur->currentDesc.Height, 1,
6827 1, &maskBits);
6828 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6829 pSur->currentDesc.Height, 1,
6830 32, lockedRect.pBits);
6831 IWineD3DSurface_UnlockRect(pCursorBitmap);
6832 /* Create our cursor and clean up. */
6833 cursor = CreateIconIndirect(&cursorInfo);
6834 SetCursor(cursor);
6835 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6836 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6837 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6838 This->hardwareCursor = cursor;
6839 HeapFree(GetProcessHeap(), 0, maskBits);
6843 This->xHotSpot = XHotSpot;
6844 This->yHotSpot = YHotSpot;
6845 return WINED3D_OK;
6848 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6850 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6852 This->xScreenSpace = XScreenSpace;
6853 This->yScreenSpace = YScreenSpace;
6855 return;
6859 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6861 BOOL oldVisible = This->bCursorVisible;
6862 POINT pt;
6864 TRACE("(%p) : visible(%d)\n", This, bShow);
6867 * When ShowCursor is first called it should make the cursor appear at the OS's last
6868 * known cursor position. Because of this, some applications just repetitively call
6869 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6871 GetCursorPos(&pt);
6872 This->xScreenSpace = pt.x;
6873 This->yScreenSpace = pt.y;
6875 if (This->haveHardwareCursor) {
6876 This->bCursorVisible = bShow;
6877 if (bShow)
6878 SetCursor(This->hardwareCursor);
6879 else
6880 SetCursor(NULL);
6882 else
6884 if (This->cursorTexture)
6885 This->bCursorVisible = bShow;
6888 return oldVisible;
6891 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6893 IWineD3DResourceImpl *resource;
6894 TRACE("(%p) : state (%u)\n", This, This->state);
6896 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6897 switch (This->state) {
6898 case WINED3D_OK:
6899 return WINED3D_OK;
6900 case WINED3DERR_DEVICELOST:
6902 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6903 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6904 return WINED3DERR_DEVICENOTRESET;
6906 return WINED3DERR_DEVICELOST;
6908 case WINED3DERR_DRIVERINTERNALERROR:
6909 return WINED3DERR_DRIVERINTERNALERROR;
6912 /* Unknown state */
6913 return WINED3DERR_DRIVERINTERNALERROR;
6917 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6919 /** FIXME: Resource tracking needs to be done,
6920 * The closes we can do to this is set the priorities of all managed textures low
6921 * and then reset them.
6922 ***********************************************************/
6923 FIXME("(%p) : stub\n", This);
6924 return WINED3D_OK;
6927 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6929 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6931 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6932 if(surface->Flags & SFLAG_DIBSECTION) {
6933 /* Release the DC */
6934 SelectObject(surface->hDC, surface->dib.holdbitmap);
6935 DeleteDC(surface->hDC);
6936 /* Release the DIB section */
6937 DeleteObject(surface->dib.DIBsection);
6938 surface->dib.bitmap_data = NULL;
6939 surface->resource.allocatedMemory = NULL;
6940 surface->Flags &= ~SFLAG_DIBSECTION;
6942 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6943 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6944 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6945 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6946 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6947 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6948 } else {
6949 surface->pow2Width = surface->pow2Height = 1;
6950 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6951 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6953 surface->glRect.left = 0;
6954 surface->glRect.top = 0;
6955 surface->glRect.right = surface->pow2Width;
6956 surface->glRect.bottom = surface->pow2Height;
6958 if(surface->glDescription.textureName) {
6959 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6960 ENTER_GL();
6961 glDeleteTextures(1, &surface->glDescription.textureName);
6962 LEAVE_GL();
6963 surface->glDescription.textureName = 0;
6964 surface->Flags &= ~SFLAG_CLIENT;
6966 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6967 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6968 surface->Flags |= SFLAG_NONPOW2;
6969 } else {
6970 surface->Flags &= ~SFLAG_NONPOW2;
6972 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6973 surface->resource.allocatedMemory = NULL;
6974 surface->resource.heapMemory = NULL;
6975 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6976 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6977 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6978 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6979 } else {
6980 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6984 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6985 TRACE("Unloading resource %p\n", resource);
6986 IWineD3DResource_UnLoad(resource);
6987 IWineD3DResource_Release(resource);
6988 return S_OK;
6991 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6993 UINT i, count;
6994 WINED3DDISPLAYMODE m;
6995 HRESULT hr;
6997 /* All Windowed modes are supported, as is leaving the current mode */
6998 if(pp->Windowed) return TRUE;
6999 if(!pp->BackBufferWidth) return TRUE;
7000 if(!pp->BackBufferHeight) return TRUE;
7002 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7003 for(i = 0; i < count; i++) {
7004 memset(&m, 0, sizeof(m));
7005 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7006 if(FAILED(hr)) {
7007 ERR("EnumAdapterModes failed\n");
7009 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7010 /* Mode found, it is supported */
7011 return TRUE;
7014 /* Mode not found -> not supported */
7015 return FALSE;
7018 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7020 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7021 UINT i;
7022 IWineD3DBaseShaderImpl *shader;
7024 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7025 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7026 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7029 ENTER_GL();
7030 if(This->depth_blt_texture) {
7031 glDeleteTextures(1, &This->depth_blt_texture);
7032 This->depth_blt_texture = 0;
7034 if (This->depth_blt_rb) {
7035 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7036 This->depth_blt_rb = 0;
7037 This->depth_blt_rb_w = 0;
7038 This->depth_blt_rb_h = 0;
7040 LEAVE_GL();
7042 This->blitter->free_private(iface);
7043 This->frag_pipe->free_private(iface);
7044 This->shader_backend->shader_free_private(iface);
7046 ENTER_GL();
7047 for (i = 0; i < GL_LIMITS(textures); i++) {
7048 /* Textures are recreated below */
7049 glDeleteTextures(1, &This->dummyTextureName[i]);
7050 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7051 This->dummyTextureName[i] = 0;
7053 LEAVE_GL();
7055 while(This->numContexts) {
7056 DestroyContext(This, This->contexts[0]);
7058 This->activeContext = NULL;
7059 HeapFree(GetProcessHeap(), 0, swapchain->context);
7060 swapchain->context = NULL;
7061 swapchain->num_contexts = 0;
7064 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7066 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7067 HRESULT hr;
7068 IWineD3DSurfaceImpl *target;
7070 /* Recreate the primary swapchain's context */
7071 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7072 if(swapchain->backBuffer) {
7073 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7074 } else {
7075 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7077 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7078 &swapchain->presentParms);
7079 swapchain->num_contexts = 1;
7080 This->activeContext = swapchain->context[0];
7082 create_dummy_textures(This);
7084 hr = This->shader_backend->shader_alloc_private(iface);
7085 if(FAILED(hr)) {
7086 ERR("Failed to recreate shader private data\n");
7087 goto err_out;
7089 hr = This->frag_pipe->alloc_private(iface);
7090 if(FAILED(hr)) {
7091 TRACE("Fragment pipeline private data couldn't be allocated\n");
7092 goto err_out;
7094 hr = This->blitter->alloc_private(iface);
7095 if(FAILED(hr)) {
7096 TRACE("Blitter private data couldn't be allocated\n");
7097 goto err_out;
7100 return WINED3D_OK;
7102 err_out:
7103 This->blitter->free_private(iface);
7104 This->frag_pipe->free_private(iface);
7105 This->shader_backend->shader_free_private(iface);
7106 return hr;
7109 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7111 IWineD3DSwapChainImpl *swapchain;
7112 HRESULT hr;
7113 BOOL DisplayModeChanged = FALSE;
7114 WINED3DDISPLAYMODE mode;
7115 TRACE("(%p)\n", This);
7117 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7118 if(FAILED(hr)) {
7119 ERR("Failed to get the first implicit swapchain\n");
7120 return hr;
7123 if(!is_display_mode_supported(This, pPresentationParameters)) {
7124 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7125 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7126 pPresentationParameters->BackBufferHeight);
7127 return WINED3DERR_INVALIDCALL;
7130 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7131 * on an existing gl context, so there's no real need for recreation.
7133 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7135 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7137 TRACE("New params:\n");
7138 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7139 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7140 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7141 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7142 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7143 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7144 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7145 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7146 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7147 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7148 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7149 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7150 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7152 /* No special treatment of these parameters. Just store them */
7153 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7154 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7155 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7156 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7158 /* What to do about these? */
7159 if(pPresentationParameters->BackBufferCount != 0 &&
7160 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7161 ERR("Cannot change the back buffer count yet\n");
7163 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7164 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7165 ERR("Cannot change the back buffer format yet\n");
7167 if(pPresentationParameters->hDeviceWindow != NULL &&
7168 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7169 ERR("Cannot change the device window yet\n");
7171 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7172 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7173 return WINED3DERR_INVALIDCALL;
7176 /* Reset the depth stencil */
7177 if (pPresentationParameters->EnableAutoDepthStencil)
7178 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7179 else
7180 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7182 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7184 if(pPresentationParameters->Windowed) {
7185 mode.Width = swapchain->orig_width;
7186 mode.Height = swapchain->orig_height;
7187 mode.RefreshRate = 0;
7188 mode.Format = swapchain->presentParms.BackBufferFormat;
7189 } else {
7190 mode.Width = pPresentationParameters->BackBufferWidth;
7191 mode.Height = pPresentationParameters->BackBufferHeight;
7192 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7193 mode.Format = swapchain->presentParms.BackBufferFormat;
7196 /* Should Width == 800 && Height == 0 set 800x600? */
7197 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7198 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7199 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7201 WINED3DVIEWPORT vp;
7202 UINT i;
7204 vp.X = 0;
7205 vp.Y = 0;
7206 vp.Width = pPresentationParameters->BackBufferWidth;
7207 vp.Height = pPresentationParameters->BackBufferHeight;
7208 vp.MinZ = 0;
7209 vp.MaxZ = 1;
7211 if(!pPresentationParameters->Windowed) {
7212 DisplayModeChanged = TRUE;
7214 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7215 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7217 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7218 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7219 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7221 if(This->auto_depth_stencil_buffer) {
7222 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7226 /* Now set the new viewport */
7227 IWineD3DDevice_SetViewport(iface, &vp);
7230 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7231 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7232 DisplayModeChanged) {
7234 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7236 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7237 if(swapchain->presentParms.Windowed) {
7238 /* switch from windowed to fs */
7239 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7240 pPresentationParameters->BackBufferWidth,
7241 pPresentationParameters->BackBufferHeight);
7242 } else {
7243 /* Fullscreen -> fullscreen mode change */
7244 MoveWindow(swapchain->win_handle, 0, 0,
7245 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7246 TRUE);
7248 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7249 /* Fullscreen -> windowed switch */
7250 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7252 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7253 } else if(!pPresentationParameters->Windowed) {
7254 DWORD style = This->style, exStyle = This->exStyle;
7255 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7256 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7257 * Reset to clear up their mess. Guild Wars also loses the device during that.
7259 This->style = 0;
7260 This->exStyle = 0;
7261 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7262 pPresentationParameters->BackBufferWidth,
7263 pPresentationParameters->BackBufferHeight);
7264 This->style = style;
7265 This->exStyle = exStyle;
7268 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7269 if(FAILED(hr)) {
7270 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7273 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7274 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7276 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7277 * first use
7279 return hr;
7282 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7284 /** FIXME: always true at the moment **/
7285 if(!bEnableDialogs) {
7286 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7288 return WINED3D_OK;
7292 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7294 TRACE("(%p) : pParameters %p\n", This, pParameters);
7296 *pParameters = This->createParms;
7297 return WINED3D_OK;
7300 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7301 IWineD3DSwapChain *swapchain;
7303 TRACE("Relaying to swapchain\n");
7305 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7306 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7307 IWineD3DSwapChain_Release(swapchain);
7309 return;
7312 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7313 IWineD3DSwapChain *swapchain;
7315 TRACE("Relaying to swapchain\n");
7317 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7318 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7319 IWineD3DSwapChain_Release(swapchain);
7321 return;
7325 /** ********************************************************
7326 * Notification functions
7327 ** ********************************************************/
7328 /** This function must be called in the release of a resource when ref == 0,
7329 * the contents of resource must still be correct,
7330 * any handles to other resource held by the caller must be closed
7331 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7332 *****************************************************/
7333 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7336 TRACE("(%p) : Adding Resource %p\n", This, resource);
7337 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7340 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7341 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7343 TRACE("(%p) : Removing resource %p\n", This, resource);
7345 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7349 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7351 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7352 int counter;
7354 TRACE("(%p) : resource %p\n", This, resource);
7356 context_resource_released(iface, resource, type);
7358 switch (type) {
7359 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7360 case WINED3DRTYPE_SURFACE: {
7361 unsigned int i;
7363 /* Cleanup any FBO attachments if d3d is enabled */
7364 if(This->d3d_initialized) {
7365 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7366 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7368 TRACE("Last active render target destroyed\n");
7369 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7370 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7371 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7372 * and the lastActiveRenderTarget member shouldn't matter
7374 if(swapchain) {
7375 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7376 TRACE("Activating primary back buffer\n");
7377 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7378 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7379 /* Single buffering environment */
7380 TRACE("Activating primary front buffer\n");
7381 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7382 } else {
7383 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7384 /* Implicit render target destroyed, that means the device is being destroyed
7385 * whatever we set here, it shouldn't matter
7387 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7389 } else {
7390 /* May happen during ddraw uninitialization */
7391 TRACE("Render target set, but swapchain does not exist!\n");
7392 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7396 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7397 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7398 This->render_targets[i] = NULL;
7401 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7402 This->stencilBufferTarget = NULL;
7406 break;
7408 case WINED3DRTYPE_TEXTURE:
7409 case WINED3DRTYPE_CUBETEXTURE:
7410 case WINED3DRTYPE_VOLUMETEXTURE:
7411 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7412 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7413 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7414 This->stateBlock->textures[counter] = NULL;
7416 if (This->updateStateBlock != This->stateBlock ){
7417 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7418 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7419 This->updateStateBlock->textures[counter] = NULL;
7423 break;
7424 case WINED3DRTYPE_VOLUME:
7425 /* TODO: nothing really? */
7426 break;
7427 case WINED3DRTYPE_VERTEXBUFFER:
7428 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7430 int streamNumber;
7431 TRACE("Cleaning up stream pointers\n");
7433 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7434 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7435 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7437 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7438 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7439 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7440 This->updateStateBlock->streamSource[streamNumber] = 0;
7441 /* Set changed flag? */
7444 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) */
7445 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7446 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7447 This->stateBlock->streamSource[streamNumber] = 0;
7452 break;
7453 case WINED3DRTYPE_INDEXBUFFER:
7454 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7455 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7456 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7457 This->updateStateBlock->pIndexData = NULL;
7460 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7461 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7462 This->stateBlock->pIndexData = NULL;
7466 break;
7467 default:
7468 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7469 break;
7473 /* Remove the resource from the resourceStore */
7474 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7476 TRACE("Resource released\n");
7480 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7482 IWineD3DResourceImpl *resource, *cursor;
7483 HRESULT ret;
7484 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7486 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7487 TRACE("enumerating resource %p\n", resource);
7488 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7489 ret = pCallback((IWineD3DResource *) resource, pData);
7490 if(ret == S_FALSE) {
7491 TRACE("Canceling enumeration\n");
7492 break;
7495 return WINED3D_OK;
7498 /**********************************************************
7499 * IWineD3DDevice VTbl follows
7500 **********************************************************/
7502 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7504 /*** IUnknown methods ***/
7505 IWineD3DDeviceImpl_QueryInterface,
7506 IWineD3DDeviceImpl_AddRef,
7507 IWineD3DDeviceImpl_Release,
7508 /*** IWineD3DDevice methods ***/
7509 IWineD3DDeviceImpl_GetParent,
7510 /*** Creation methods**/
7511 IWineD3DDeviceImpl_CreateVertexBuffer,
7512 IWineD3DDeviceImpl_CreateIndexBuffer,
7513 IWineD3DDeviceImpl_CreateStateBlock,
7514 IWineD3DDeviceImpl_CreateSurface,
7515 IWineD3DDeviceImpl_CreateTexture,
7516 IWineD3DDeviceImpl_CreateVolumeTexture,
7517 IWineD3DDeviceImpl_CreateVolume,
7518 IWineD3DDeviceImpl_CreateCubeTexture,
7519 IWineD3DDeviceImpl_CreateQuery,
7520 IWineD3DDeviceImpl_CreateSwapChain,
7521 IWineD3DDeviceImpl_CreateVertexDeclaration,
7522 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7523 IWineD3DDeviceImpl_CreateVertexShader,
7524 IWineD3DDeviceImpl_CreatePixelShader,
7525 IWineD3DDeviceImpl_CreatePalette,
7526 /*** Odd functions **/
7527 IWineD3DDeviceImpl_Init3D,
7528 IWineD3DDeviceImpl_InitGDI,
7529 IWineD3DDeviceImpl_Uninit3D,
7530 IWineD3DDeviceImpl_UninitGDI,
7531 IWineD3DDeviceImpl_SetMultithreaded,
7532 IWineD3DDeviceImpl_EvictManagedResources,
7533 IWineD3DDeviceImpl_GetAvailableTextureMem,
7534 IWineD3DDeviceImpl_GetBackBuffer,
7535 IWineD3DDeviceImpl_GetCreationParameters,
7536 IWineD3DDeviceImpl_GetDeviceCaps,
7537 IWineD3DDeviceImpl_GetDirect3D,
7538 IWineD3DDeviceImpl_GetDisplayMode,
7539 IWineD3DDeviceImpl_SetDisplayMode,
7540 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7541 IWineD3DDeviceImpl_GetRasterStatus,
7542 IWineD3DDeviceImpl_GetSwapChain,
7543 IWineD3DDeviceImpl_Reset,
7544 IWineD3DDeviceImpl_SetDialogBoxMode,
7545 IWineD3DDeviceImpl_SetCursorProperties,
7546 IWineD3DDeviceImpl_SetCursorPosition,
7547 IWineD3DDeviceImpl_ShowCursor,
7548 IWineD3DDeviceImpl_TestCooperativeLevel,
7549 /*** Getters and setters **/
7550 IWineD3DDeviceImpl_SetClipPlane,
7551 IWineD3DDeviceImpl_GetClipPlane,
7552 IWineD3DDeviceImpl_SetClipStatus,
7553 IWineD3DDeviceImpl_GetClipStatus,
7554 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7555 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7556 IWineD3DDeviceImpl_SetDepthStencilSurface,
7557 IWineD3DDeviceImpl_GetDepthStencilSurface,
7558 IWineD3DDeviceImpl_SetFVF,
7559 IWineD3DDeviceImpl_GetFVF,
7560 IWineD3DDeviceImpl_SetGammaRamp,
7561 IWineD3DDeviceImpl_GetGammaRamp,
7562 IWineD3DDeviceImpl_SetIndices,
7563 IWineD3DDeviceImpl_GetIndices,
7564 IWineD3DDeviceImpl_SetBaseVertexIndex,
7565 IWineD3DDeviceImpl_GetBaseVertexIndex,
7566 IWineD3DDeviceImpl_SetLight,
7567 IWineD3DDeviceImpl_GetLight,
7568 IWineD3DDeviceImpl_SetLightEnable,
7569 IWineD3DDeviceImpl_GetLightEnable,
7570 IWineD3DDeviceImpl_SetMaterial,
7571 IWineD3DDeviceImpl_GetMaterial,
7572 IWineD3DDeviceImpl_SetNPatchMode,
7573 IWineD3DDeviceImpl_GetNPatchMode,
7574 IWineD3DDeviceImpl_SetPaletteEntries,
7575 IWineD3DDeviceImpl_GetPaletteEntries,
7576 IWineD3DDeviceImpl_SetPixelShader,
7577 IWineD3DDeviceImpl_GetPixelShader,
7578 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7579 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7580 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7581 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7582 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7583 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7584 IWineD3DDeviceImpl_SetRenderState,
7585 IWineD3DDeviceImpl_GetRenderState,
7586 IWineD3DDeviceImpl_SetRenderTarget,
7587 IWineD3DDeviceImpl_GetRenderTarget,
7588 IWineD3DDeviceImpl_SetFrontBackBuffers,
7589 IWineD3DDeviceImpl_SetSamplerState,
7590 IWineD3DDeviceImpl_GetSamplerState,
7591 IWineD3DDeviceImpl_SetScissorRect,
7592 IWineD3DDeviceImpl_GetScissorRect,
7593 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7594 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7595 IWineD3DDeviceImpl_SetStreamSource,
7596 IWineD3DDeviceImpl_GetStreamSource,
7597 IWineD3DDeviceImpl_SetStreamSourceFreq,
7598 IWineD3DDeviceImpl_GetStreamSourceFreq,
7599 IWineD3DDeviceImpl_SetTexture,
7600 IWineD3DDeviceImpl_GetTexture,
7601 IWineD3DDeviceImpl_SetTextureStageState,
7602 IWineD3DDeviceImpl_GetTextureStageState,
7603 IWineD3DDeviceImpl_SetTransform,
7604 IWineD3DDeviceImpl_GetTransform,
7605 IWineD3DDeviceImpl_SetVertexDeclaration,
7606 IWineD3DDeviceImpl_GetVertexDeclaration,
7607 IWineD3DDeviceImpl_SetVertexShader,
7608 IWineD3DDeviceImpl_GetVertexShader,
7609 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7610 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7611 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7612 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7613 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7614 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7615 IWineD3DDeviceImpl_SetViewport,
7616 IWineD3DDeviceImpl_GetViewport,
7617 IWineD3DDeviceImpl_MultiplyTransform,
7618 IWineD3DDeviceImpl_ValidateDevice,
7619 IWineD3DDeviceImpl_ProcessVertices,
7620 /*** State block ***/
7621 IWineD3DDeviceImpl_BeginStateBlock,
7622 IWineD3DDeviceImpl_EndStateBlock,
7623 /*** Scene management ***/
7624 IWineD3DDeviceImpl_BeginScene,
7625 IWineD3DDeviceImpl_EndScene,
7626 IWineD3DDeviceImpl_Present,
7627 IWineD3DDeviceImpl_Clear,
7628 /*** Drawing ***/
7629 IWineD3DDeviceImpl_DrawPrimitive,
7630 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7631 IWineD3DDeviceImpl_DrawPrimitiveUP,
7632 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7633 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7634 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7635 IWineD3DDeviceImpl_DrawRectPatch,
7636 IWineD3DDeviceImpl_DrawTriPatch,
7637 IWineD3DDeviceImpl_DeletePatch,
7638 IWineD3DDeviceImpl_ColorFill,
7639 IWineD3DDeviceImpl_UpdateTexture,
7640 IWineD3DDeviceImpl_UpdateSurface,
7641 IWineD3DDeviceImpl_GetFrontBufferData,
7642 /*** object tracking ***/
7643 IWineD3DDeviceImpl_ResourceReleased,
7644 IWineD3DDeviceImpl_EnumResources
7647 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7649 /*** IUnknown methods ***/
7650 IWineD3DDeviceImpl_QueryInterface,
7651 IWineD3DDeviceImpl_AddRef,
7652 IWineD3DDeviceImpl_Release,
7653 /*** IWineD3DDevice methods ***/
7654 IWineD3DDeviceImpl_GetParent,
7655 /*** Creation methods**/
7656 IWineD3DDeviceImpl_CreateVertexBuffer,
7657 IWineD3DDeviceImpl_CreateIndexBuffer,
7658 IWineD3DDeviceImpl_CreateStateBlock,
7659 IWineD3DDeviceImpl_CreateSurface,
7660 IWineD3DDeviceImpl_CreateTexture,
7661 IWineD3DDeviceImpl_CreateVolumeTexture,
7662 IWineD3DDeviceImpl_CreateVolume,
7663 IWineD3DDeviceImpl_CreateCubeTexture,
7664 IWineD3DDeviceImpl_CreateQuery,
7665 IWineD3DDeviceImpl_CreateSwapChain,
7666 IWineD3DDeviceImpl_CreateVertexDeclaration,
7667 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7668 IWineD3DDeviceImpl_CreateVertexShader,
7669 IWineD3DDeviceImpl_CreatePixelShader,
7670 IWineD3DDeviceImpl_CreatePalette,
7671 /*** Odd functions **/
7672 IWineD3DDeviceImpl_Init3D,
7673 IWineD3DDeviceImpl_InitGDI,
7674 IWineD3DDeviceImpl_Uninit3D,
7675 IWineD3DDeviceImpl_UninitGDI,
7676 IWineD3DDeviceImpl_SetMultithreaded,
7677 IWineD3DDeviceImpl_EvictManagedResources,
7678 IWineD3DDeviceImpl_GetAvailableTextureMem,
7679 IWineD3DDeviceImpl_GetBackBuffer,
7680 IWineD3DDeviceImpl_GetCreationParameters,
7681 IWineD3DDeviceImpl_GetDeviceCaps,
7682 IWineD3DDeviceImpl_GetDirect3D,
7683 IWineD3DDeviceImpl_GetDisplayMode,
7684 IWineD3DDeviceImpl_SetDisplayMode,
7685 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7686 IWineD3DDeviceImpl_GetRasterStatus,
7687 IWineD3DDeviceImpl_GetSwapChain,
7688 IWineD3DDeviceImpl_Reset,
7689 IWineD3DDeviceImpl_SetDialogBoxMode,
7690 IWineD3DDeviceImpl_SetCursorProperties,
7691 IWineD3DDeviceImpl_SetCursorPosition,
7692 IWineD3DDeviceImpl_ShowCursor,
7693 IWineD3DDeviceImpl_TestCooperativeLevel,
7694 /*** Getters and setters **/
7695 IWineD3DDeviceImpl_SetClipPlane,
7696 IWineD3DDeviceImpl_GetClipPlane,
7697 IWineD3DDeviceImpl_SetClipStatus,
7698 IWineD3DDeviceImpl_GetClipStatus,
7699 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7700 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7701 IWineD3DDeviceImpl_SetDepthStencilSurface,
7702 IWineD3DDeviceImpl_GetDepthStencilSurface,
7703 IWineD3DDeviceImpl_SetFVF,
7704 IWineD3DDeviceImpl_GetFVF,
7705 IWineD3DDeviceImpl_SetGammaRamp,
7706 IWineD3DDeviceImpl_GetGammaRamp,
7707 IWineD3DDeviceImpl_SetIndices,
7708 IWineD3DDeviceImpl_GetIndices,
7709 IWineD3DDeviceImpl_SetBaseVertexIndex,
7710 IWineD3DDeviceImpl_GetBaseVertexIndex,
7711 IWineD3DDeviceImpl_SetLight,
7712 IWineD3DDeviceImpl_GetLight,
7713 IWineD3DDeviceImpl_SetLightEnable,
7714 IWineD3DDeviceImpl_GetLightEnable,
7715 IWineD3DDeviceImpl_SetMaterial,
7716 IWineD3DDeviceImpl_GetMaterial,
7717 IWineD3DDeviceImpl_SetNPatchMode,
7718 IWineD3DDeviceImpl_GetNPatchMode,
7719 IWineD3DDeviceImpl_SetPaletteEntries,
7720 IWineD3DDeviceImpl_GetPaletteEntries,
7721 IWineD3DDeviceImpl_SetPixelShader,
7722 IWineD3DDeviceImpl_GetPixelShader,
7723 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7724 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7725 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7726 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7727 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7728 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7729 IWineD3DDeviceImpl_SetRenderState,
7730 IWineD3DDeviceImpl_GetRenderState,
7731 IWineD3DDeviceImpl_SetRenderTarget,
7732 IWineD3DDeviceImpl_GetRenderTarget,
7733 IWineD3DDeviceImpl_SetFrontBackBuffers,
7734 IWineD3DDeviceImpl_SetSamplerState,
7735 IWineD3DDeviceImpl_GetSamplerState,
7736 IWineD3DDeviceImpl_SetScissorRect,
7737 IWineD3DDeviceImpl_GetScissorRect,
7738 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7739 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7740 IWineD3DDeviceImpl_SetStreamSource,
7741 IWineD3DDeviceImpl_GetStreamSource,
7742 IWineD3DDeviceImpl_SetStreamSourceFreq,
7743 IWineD3DDeviceImpl_GetStreamSourceFreq,
7744 IWineD3DDeviceImpl_SetTexture,
7745 IWineD3DDeviceImpl_GetTexture,
7746 IWineD3DDeviceImpl_SetTextureStageState,
7747 IWineD3DDeviceImpl_GetTextureStageState,
7748 IWineD3DDeviceImpl_SetTransform,
7749 IWineD3DDeviceImpl_GetTransform,
7750 IWineD3DDeviceImpl_SetVertexDeclaration,
7751 IWineD3DDeviceImpl_GetVertexDeclaration,
7752 IWineD3DDeviceImpl_SetVertexShader,
7753 IWineD3DDeviceImpl_GetVertexShader,
7754 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7755 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7756 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7757 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7758 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7759 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7760 IWineD3DDeviceImpl_SetViewport,
7761 IWineD3DDeviceImpl_GetViewport,
7762 IWineD3DDeviceImpl_MultiplyTransform,
7763 IWineD3DDeviceImpl_ValidateDevice,
7764 IWineD3DDeviceImpl_ProcessVertices,
7765 /*** State block ***/
7766 IWineD3DDeviceImpl_BeginStateBlock,
7767 IWineD3DDeviceImpl_EndStateBlock,
7768 /*** Scene management ***/
7769 IWineD3DDeviceImpl_BeginScene,
7770 IWineD3DDeviceImpl_EndScene,
7771 IWineD3DDeviceImpl_Present,
7772 IWineD3DDeviceImpl_Clear,
7773 /*** Drawing ***/
7774 IWineD3DDeviceImpl_DrawPrimitive,
7775 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7776 IWineD3DDeviceImpl_DrawPrimitiveUP,
7777 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7778 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7779 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7780 IWineD3DDeviceImpl_DrawRectPatch,
7781 IWineD3DDeviceImpl_DrawTriPatch,
7782 IWineD3DDeviceImpl_DeletePatch,
7783 IWineD3DDeviceImpl_ColorFill,
7784 IWineD3DDeviceImpl_UpdateTexture,
7785 IWineD3DDeviceImpl_UpdateSurface,
7786 IWineD3DDeviceImpl_GetFrontBufferData,
7787 /*** object tracking ***/
7788 IWineD3DDeviceImpl_ResourceReleased,
7789 IWineD3DDeviceImpl_EnumResources
7792 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7793 WINED3DRS_ALPHABLENDENABLE ,
7794 WINED3DRS_ALPHAFUNC ,
7795 WINED3DRS_ALPHAREF ,
7796 WINED3DRS_ALPHATESTENABLE ,
7797 WINED3DRS_BLENDOP ,
7798 WINED3DRS_COLORWRITEENABLE ,
7799 WINED3DRS_DESTBLEND ,
7800 WINED3DRS_DITHERENABLE ,
7801 WINED3DRS_FILLMODE ,
7802 WINED3DRS_FOGDENSITY ,
7803 WINED3DRS_FOGEND ,
7804 WINED3DRS_FOGSTART ,
7805 WINED3DRS_LASTPIXEL ,
7806 WINED3DRS_SHADEMODE ,
7807 WINED3DRS_SRCBLEND ,
7808 WINED3DRS_STENCILENABLE ,
7809 WINED3DRS_STENCILFAIL ,
7810 WINED3DRS_STENCILFUNC ,
7811 WINED3DRS_STENCILMASK ,
7812 WINED3DRS_STENCILPASS ,
7813 WINED3DRS_STENCILREF ,
7814 WINED3DRS_STENCILWRITEMASK ,
7815 WINED3DRS_STENCILZFAIL ,
7816 WINED3DRS_TEXTUREFACTOR ,
7817 WINED3DRS_WRAP0 ,
7818 WINED3DRS_WRAP1 ,
7819 WINED3DRS_WRAP2 ,
7820 WINED3DRS_WRAP3 ,
7821 WINED3DRS_WRAP4 ,
7822 WINED3DRS_WRAP5 ,
7823 WINED3DRS_WRAP6 ,
7824 WINED3DRS_WRAP7 ,
7825 WINED3DRS_ZENABLE ,
7826 WINED3DRS_ZFUNC ,
7827 WINED3DRS_ZWRITEENABLE
7830 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7831 WINED3DTSS_ADDRESSW ,
7832 WINED3DTSS_ALPHAARG0 ,
7833 WINED3DTSS_ALPHAARG1 ,
7834 WINED3DTSS_ALPHAARG2 ,
7835 WINED3DTSS_ALPHAOP ,
7836 WINED3DTSS_BUMPENVLOFFSET ,
7837 WINED3DTSS_BUMPENVLSCALE ,
7838 WINED3DTSS_BUMPENVMAT00 ,
7839 WINED3DTSS_BUMPENVMAT01 ,
7840 WINED3DTSS_BUMPENVMAT10 ,
7841 WINED3DTSS_BUMPENVMAT11 ,
7842 WINED3DTSS_COLORARG0 ,
7843 WINED3DTSS_COLORARG1 ,
7844 WINED3DTSS_COLORARG2 ,
7845 WINED3DTSS_COLOROP ,
7846 WINED3DTSS_RESULTARG ,
7847 WINED3DTSS_TEXCOORDINDEX ,
7848 WINED3DTSS_TEXTURETRANSFORMFLAGS
7851 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7852 WINED3DSAMP_ADDRESSU ,
7853 WINED3DSAMP_ADDRESSV ,
7854 WINED3DSAMP_ADDRESSW ,
7855 WINED3DSAMP_BORDERCOLOR ,
7856 WINED3DSAMP_MAGFILTER ,
7857 WINED3DSAMP_MINFILTER ,
7858 WINED3DSAMP_MIPFILTER ,
7859 WINED3DSAMP_MIPMAPLODBIAS ,
7860 WINED3DSAMP_MAXMIPLEVEL ,
7861 WINED3DSAMP_MAXANISOTROPY ,
7862 WINED3DSAMP_SRGBTEXTURE ,
7863 WINED3DSAMP_ELEMENTINDEX
7866 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7867 WINED3DRS_AMBIENT ,
7868 WINED3DRS_AMBIENTMATERIALSOURCE ,
7869 WINED3DRS_CLIPPING ,
7870 WINED3DRS_CLIPPLANEENABLE ,
7871 WINED3DRS_COLORVERTEX ,
7872 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7873 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7874 WINED3DRS_FOGDENSITY ,
7875 WINED3DRS_FOGEND ,
7876 WINED3DRS_FOGSTART ,
7877 WINED3DRS_FOGTABLEMODE ,
7878 WINED3DRS_FOGVERTEXMODE ,
7879 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7880 WINED3DRS_LIGHTING ,
7881 WINED3DRS_LOCALVIEWER ,
7882 WINED3DRS_MULTISAMPLEANTIALIAS ,
7883 WINED3DRS_MULTISAMPLEMASK ,
7884 WINED3DRS_NORMALIZENORMALS ,
7885 WINED3DRS_PATCHEDGESTYLE ,
7886 WINED3DRS_POINTSCALE_A ,
7887 WINED3DRS_POINTSCALE_B ,
7888 WINED3DRS_POINTSCALE_C ,
7889 WINED3DRS_POINTSCALEENABLE ,
7890 WINED3DRS_POINTSIZE ,
7891 WINED3DRS_POINTSIZE_MAX ,
7892 WINED3DRS_POINTSIZE_MIN ,
7893 WINED3DRS_POINTSPRITEENABLE ,
7894 WINED3DRS_RANGEFOGENABLE ,
7895 WINED3DRS_SPECULARMATERIALSOURCE ,
7896 WINED3DRS_TWEENFACTOR ,
7897 WINED3DRS_VERTEXBLEND ,
7898 WINED3DRS_CULLMODE ,
7899 WINED3DRS_FOGCOLOR
7902 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7903 WINED3DTSS_TEXCOORDINDEX ,
7904 WINED3DTSS_TEXTURETRANSFORMFLAGS
7907 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7908 WINED3DSAMP_DMAPOFFSET
7911 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7912 DWORD rep = This->StateTable[state].representative;
7913 DWORD idx;
7914 BYTE shift;
7915 UINT i;
7916 WineD3DContext *context;
7918 if(!rep) return;
7919 for(i = 0; i < This->numContexts; i++) {
7920 context = This->contexts[i];
7921 if(isStateDirty(context, rep)) continue;
7923 context->dirtyArray[context->numDirtyEntries++] = rep;
7924 idx = rep >> 5;
7925 shift = rep & 0x1f;
7926 context->isStateDirty[idx] |= (1 << shift);
7930 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7931 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7932 /* The drawable size of a pbuffer render target is the current pbuffer size
7934 *width = dev->pbufferWidth;
7935 *height = dev->pbufferHeight;
7938 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7939 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7941 *width = This->pow2Width;
7942 *height = This->pow2Height;
7945 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7946 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7947 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7948 * current context's drawable, which is the size of the back buffer of the swapchain
7949 * the active context belongs to. The back buffer of the swapchain is stored as the
7950 * surface the context belongs to.
7952 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7953 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;