push 3600ceb9798742c4473b49518e0ae238427fc4b7
[wine/hacks.git] / dlls / wined3d / device.c
blob836ad3bee4c8f2b53363119266379365a28cf711
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 |= (1 << i);
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 |= (1 << i);
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->contained_vs_consts_b[i] = i;
518 object->changed.vertexShaderConstantsB |= (1 << i);
520 object->num_contained_vs_consts_b = MAX_CONST_B;
521 for (i = 0; i < MAX_CONST_I; ++i) {
522 object->contained_vs_consts_i[i] = i;
523 object->changed.vertexShaderConstantsI |= (1 << 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 struct 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 struct 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_color_fixup = glDesc->color_fixup;
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 struct 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 /* Is NP2 support for volumes needed? */
936 object->baseTexture.pow2Matrix[ 0] = 1.0;
937 object->baseTexture.pow2Matrix[ 5] = 1.0;
938 object->baseTexture.pow2Matrix[10] = 1.0;
939 object->baseTexture.pow2Matrix[15] = 1.0;
941 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
942 object->baseTexture.minMipLookup = minMipLookup;
943 object->baseTexture.magLookup = magLookup;
944 } else {
945 object->baseTexture.minMipLookup = minMipLookup_noFilter;
946 object->baseTexture.magLookup = magLookup_noFilter;
949 /* Calculate levels for mip mapping */
950 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
951 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
952 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
953 return WINED3DERR_INVALIDCALL;
955 if(Levels > 1) {
956 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
957 return WINED3DERR_INVALIDCALL;
959 object->baseTexture.levels = 1;
960 } else if (Levels == 0) {
961 object->baseTexture.levels++;
962 tmpW = Width;
963 tmpH = Height;
964 tmpD = Depth;
965 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
966 tmpW = max(1, tmpW >> 1);
967 tmpH = max(1, tmpH >> 1);
968 tmpD = max(1, tmpD >> 1);
969 object->baseTexture.levels++;
971 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
974 /* Generate all the surfaces */
975 tmpW = Width;
976 tmpH = Height;
977 tmpD = Depth;
979 for (i = 0; i < object->baseTexture.levels; i++)
981 HRESULT hr;
982 /* Create the volume */
983 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
984 &object->volumes[i], pSharedHandle);
986 if(FAILED(hr)) {
987 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
988 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
989 *ppVolumeTexture = NULL;
990 return hr;
993 /* Set its container to this object */
994 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
996 /* calculate the next mipmap level */
997 tmpW = max(1, tmpW >> 1);
998 tmpH = max(1, tmpH >> 1);
999 tmpD = max(1, tmpD >> 1);
1001 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
1003 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1004 TRACE("(%p) : Created volume texture %p\n", This, object);
1005 return WINED3D_OK;
1008 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1009 UINT Width, UINT Height, UINT Depth,
1010 DWORD Usage,
1011 WINED3DFORMAT Format, WINED3DPOOL Pool,
1012 IWineD3DVolume** ppVolume,
1013 HANDLE* pSharedHandle, IUnknown *parent) {
1015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1016 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1017 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1019 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1020 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1021 return WINED3DERR_INVALIDCALL;
1024 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1026 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1027 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1029 object->currentDesc.Width = Width;
1030 object->currentDesc.Height = Height;
1031 object->currentDesc.Depth = Depth;
1032 object->bytesPerPixel = formatDesc->bpp;
1034 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1035 object->lockable = TRUE;
1036 object->locked = FALSE;
1037 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1038 object->dirty = TRUE;
1040 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1043 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1044 UINT Levels, DWORD Usage,
1045 WINED3DFORMAT Format, WINED3DPOOL Pool,
1046 IWineD3DCubeTexture **ppCubeTexture,
1047 HANDLE *pSharedHandle, IUnknown *parent,
1048 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1051 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1052 unsigned int i, j;
1053 UINT tmpW;
1054 HRESULT hr;
1055 unsigned int pow2EdgeLength;
1056 const struct GlPixelFormatDesc *glDesc;
1057 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1059 /* TODO: It should only be possible to create textures for formats
1060 that are reported as supported */
1061 if (WINED3DFMT_UNKNOWN >= Format) {
1062 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1063 return WINED3DERR_INVALIDCALL;
1066 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1067 WARN("(%p) : Tried to create not supported cube texture\n", This);
1068 return WINED3DERR_INVALIDCALL;
1071 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1072 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1074 TRACE("(%p) Create Cube Texture\n", This);
1076 /* Find the nearest pow2 match */
1077 pow2EdgeLength = 1;
1078 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1080 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
1081 /* Precalculated scaling for 'faked' non power of two texture coords */
1082 object->baseTexture.pow2Matrix[ 0] = 1.0;
1083 object->baseTexture.pow2Matrix[ 5] = 1.0;
1084 object->baseTexture.pow2Matrix[10] = 1.0;
1085 object->baseTexture.pow2Matrix[15] = 1.0;
1086 } else {
1087 /* Precalculated scaling for 'faked' non power of two texture coords */
1088 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1089 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1090 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1091 object->baseTexture.pow2Matrix[15] = 1.0;
1094 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1095 object->baseTexture.minMipLookup = minMipLookup;
1096 object->baseTexture.magLookup = magLookup;
1097 } else {
1098 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1099 object->baseTexture.magLookup = magLookup_noFilter;
1102 /* Calculate levels for mip mapping */
1103 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1104 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1105 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1106 HeapFree(GetProcessHeap(), 0, object);
1107 *ppCubeTexture = NULL;
1109 return WINED3DERR_INVALIDCALL;
1111 if(Levels > 1) {
1112 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1113 HeapFree(GetProcessHeap(), 0, object);
1114 *ppCubeTexture = NULL;
1116 return WINED3DERR_INVALIDCALL;
1118 object->baseTexture.levels = 1;
1119 } else if (Levels == 0) {
1120 object->baseTexture.levels++;
1121 tmpW = EdgeLength;
1122 while (tmpW > 1) {
1123 tmpW = max(1, tmpW >> 1);
1124 object->baseTexture.levels++;
1126 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1129 /* Generate all the surfaces */
1130 tmpW = EdgeLength;
1131 for (i = 0; i < object->baseTexture.levels; i++) {
1133 /* Create the 6 faces */
1134 for (j = 0; j < 6; j++) {
1135 static const GLenum cube_targets[6] = {
1136 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1137 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1138 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1139 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1140 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1141 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1144 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1145 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1147 if(hr!= WINED3D_OK) {
1148 /* clean up */
1149 unsigned int k;
1150 unsigned int l;
1151 for (l = 0; l < j; l++) {
1152 IWineD3DSurface_Release(object->surfaces[l][i]);
1154 for (k = 0; k < i; k++) {
1155 for (l = 0; l < 6; l++) {
1156 IWineD3DSurface_Release(object->surfaces[l][k]);
1160 FIXME("(%p) Failed to create surface\n",object);
1161 HeapFree(GetProcessHeap(),0,object);
1162 *ppCubeTexture = NULL;
1163 return hr;
1165 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1166 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1167 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1169 tmpW = max(1, tmpW >> 1);
1171 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
1173 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1174 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1175 return WINED3D_OK;
1178 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1180 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1181 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1182 const IWineD3DQueryVtbl *vtable;
1184 /* Just a check to see if we support this type of query */
1185 switch(Type) {
1186 case WINED3DQUERYTYPE_OCCLUSION:
1187 TRACE("(%p) occlusion query\n", This);
1188 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1189 hr = WINED3D_OK;
1190 else
1191 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1193 vtable = &IWineD3DOcclusionQuery_Vtbl;
1194 break;
1196 case WINED3DQUERYTYPE_EVENT:
1197 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1198 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1199 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1201 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1203 vtable = &IWineD3DEventQuery_Vtbl;
1204 hr = WINED3D_OK;
1205 break;
1207 case WINED3DQUERYTYPE_VCACHE:
1208 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1209 case WINED3DQUERYTYPE_VERTEXSTATS:
1210 case WINED3DQUERYTYPE_TIMESTAMP:
1211 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1212 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1213 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1214 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1215 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1216 case WINED3DQUERYTYPE_PIXELTIMINGS:
1217 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1218 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1219 default:
1220 /* Use the base Query vtable until we have a special one for each query */
1221 vtable = &IWineD3DQuery_Vtbl;
1222 FIXME("(%p) Unhandled query type %d\n", This, Type);
1224 if(NULL == ppQuery || hr != WINED3D_OK) {
1225 return hr;
1228 D3DCREATEOBJECTINSTANCE(object, Query)
1229 object->lpVtbl = vtable;
1230 object->type = Type;
1231 object->state = QUERY_CREATED;
1232 /* allocated the 'extended' data based on the type of query requested */
1233 switch(Type){
1234 case WINED3DQUERYTYPE_OCCLUSION:
1235 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1236 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1238 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1239 TRACE("(%p) Allocating data for an occlusion query\n", This);
1241 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1242 ENTER_GL();
1243 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1244 LEAVE_GL();
1245 break;
1247 case WINED3DQUERYTYPE_EVENT:
1248 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1249 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1251 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1252 ENTER_GL();
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 LEAVE_GL();
1261 break;
1263 case WINED3DQUERYTYPE_VCACHE:
1264 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1265 case WINED3DQUERYTYPE_VERTEXSTATS:
1266 case WINED3DQUERYTYPE_TIMESTAMP:
1267 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1268 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1269 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1270 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1271 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1272 case WINED3DQUERYTYPE_PIXELTIMINGS:
1273 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1274 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1275 default:
1276 object->extendedData = 0;
1277 FIXME("(%p) Unhandled query type %d\n",This , Type);
1279 TRACE("(%p) : Created Query %p\n", This, object);
1280 return WINED3D_OK;
1283 /*****************************************************************************
1284 * IWineD3DDeviceImpl_SetupFullscreenWindow
1286 * Helper function that modifies a HWND's Style and ExStyle for proper
1287 * fullscreen use.
1289 * Params:
1290 * iface: Pointer to the IWineD3DDevice interface
1291 * window: Window to setup
1293 *****************************************************************************/
1294 static LONG fullscreen_style(LONG orig_style) {
1295 LONG style = orig_style;
1296 style &= ~WS_CAPTION;
1297 style &= ~WS_THICKFRAME;
1299 /* Make sure the window is managed, otherwise we won't get keyboard input */
1300 style |= WS_POPUP | WS_SYSMENU;
1302 return style;
1305 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1306 LONG exStyle = orig_exStyle;
1308 /* Filter out window decorations */
1309 exStyle &= ~WS_EX_WINDOWEDGE;
1310 exStyle &= ~WS_EX_CLIENTEDGE;
1312 return exStyle;
1315 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1318 LONG style, exStyle;
1319 /* Don't do anything if an original style is stored.
1320 * That shouldn't happen
1322 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1323 if (This->style || This->exStyle) {
1324 ERR("(%p): Want to change the window parameters of HWND %p, but "
1325 "another style is stored for restoration afterwards\n", This, window);
1328 /* Get the parameters and save them */
1329 style = GetWindowLongW(window, GWL_STYLE);
1330 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1331 This->style = style;
1332 This->exStyle = exStyle;
1334 style = fullscreen_style(style);
1335 exStyle = fullscreen_exStyle(exStyle);
1337 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1338 This->style, This->exStyle, style, exStyle);
1340 SetWindowLongW(window, GWL_STYLE, style);
1341 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1343 /* Inform the window about the update. */
1344 SetWindowPos(window, HWND_TOP, 0, 0,
1345 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1348 /*****************************************************************************
1349 * IWineD3DDeviceImpl_RestoreWindow
1351 * Helper function that restores a windows' properties when taking it out
1352 * of fullscreen mode
1354 * Params:
1355 * iface: Pointer to the IWineD3DDevice interface
1356 * window: Window to setup
1358 *****************************************************************************/
1359 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1361 LONG style, exStyle;
1363 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1364 * switch, do nothing
1366 if (!This->style && !This->exStyle) return;
1368 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1369 This, window, This->style, This->exStyle);
1371 style = GetWindowLongW(window, GWL_STYLE);
1372 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1374 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1375 * Some applications change it before calling Reset() when switching between windowed and
1376 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1378 if(style == fullscreen_style(This->style) &&
1379 exStyle == fullscreen_style(This->exStyle)) {
1380 SetWindowLongW(window, GWL_STYLE, This->style);
1381 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1384 /* Delete the old values */
1385 This->style = 0;
1386 This->exStyle = 0;
1388 /* Inform the window about the update */
1389 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1390 0, 0, 0, 0, /* Pos, Size, ignored */
1391 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1394 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1395 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice* iface,
1396 WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1397 IUnknown* parent, D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1398 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil, WINED3DSURFTYPE surface_type)
1400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1402 HDC hDc;
1403 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1404 HRESULT hr;
1405 IUnknown *bufferParent;
1406 BOOL displaymode_set = FALSE;
1407 WINED3DDISPLAYMODE Mode;
1408 const StaticPixelFormatDesc *formatDesc;
1410 TRACE("(%p) : Created Additional Swap Chain\n", This);
1412 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1413 * does a device hold a reference to a swap chain giving them a lifetime of the device
1414 * or does the swap chain notify the device of its destruction.
1415 *******************************/
1417 /* Check the params */
1418 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1419 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1420 return WINED3DERR_INVALIDCALL;
1421 } else if (pPresentationParameters->BackBufferCount > 1) {
1422 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");
1425 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1426 switch(surface_type) {
1427 case SURFACE_GDI:
1428 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1429 break;
1430 case SURFACE_OPENGL:
1431 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1432 break;
1433 case SURFACE_UNKNOWN:
1434 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1435 return WINED3DERR_INVALIDCALL;
1438 /*********************
1439 * Lookup the window Handle and the relating X window handle
1440 ********************/
1442 /* Setup hwnd we are using, plus which display this equates to */
1443 object->win_handle = pPresentationParameters->hDeviceWindow;
1444 if (!object->win_handle) {
1445 object->win_handle = This->createParms.hFocusWindow;
1447 if(!pPresentationParameters->Windowed && object->win_handle) {
1448 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1449 pPresentationParameters->BackBufferWidth,
1450 pPresentationParameters->BackBufferHeight);
1453 hDc = GetDC(object->win_handle);
1454 TRACE("Using hDc %p\n", hDc);
1456 if (NULL == hDc) {
1457 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1458 return WINED3DERR_NOTAVAILABLE;
1461 /* Get info on the current display setup */
1462 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1463 object->orig_width = Mode.Width;
1464 object->orig_height = Mode.Height;
1465 object->orig_fmt = Mode.Format;
1466 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1468 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1469 * then the corresponding dimension of the client area of the hDeviceWindow
1470 * (or the focus window, if hDeviceWindow is NULL) is taken.
1471 **********************/
1473 if (pPresentationParameters->Windowed &&
1474 ((pPresentationParameters->BackBufferWidth == 0) ||
1475 (pPresentationParameters->BackBufferHeight == 0) ||
1476 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1478 RECT Rect;
1479 GetClientRect(object->win_handle, &Rect);
1481 if (pPresentationParameters->BackBufferWidth == 0) {
1482 pPresentationParameters->BackBufferWidth = Rect.right;
1483 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1485 if (pPresentationParameters->BackBufferHeight == 0) {
1486 pPresentationParameters->BackBufferHeight = Rect.bottom;
1487 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1489 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1490 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1491 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1495 /* Put the correct figures in the presentation parameters */
1496 TRACE("Copying across presentation parameters\n");
1497 object->presentParms = *pPresentationParameters;
1499 TRACE("calling rendertarget CB\n");
1500 hr = D3DCB_CreateRenderTarget(This->parent,
1501 parent,
1502 object->presentParms.BackBufferWidth,
1503 object->presentParms.BackBufferHeight,
1504 object->presentParms.BackBufferFormat,
1505 object->presentParms.MultiSampleType,
1506 object->presentParms.MultiSampleQuality,
1507 TRUE /* Lockable */,
1508 &object->frontBuffer,
1509 NULL /* pShared (always null)*/);
1510 if (SUCCEEDED(hr)) {
1511 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1512 if(surface_type == SURFACE_OPENGL) {
1513 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1515 } else {
1516 ERR("Failed to create the front buffer\n");
1517 goto error;
1520 /*********************
1521 * Windowed / Fullscreen
1522 *******************/
1525 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1526 * so we should really check to see if there is a fullscreen swapchain already
1527 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1528 **************************************/
1530 if (!pPresentationParameters->Windowed) {
1531 WINED3DDISPLAYMODE mode;
1534 /* Change the display settings */
1535 mode.Width = pPresentationParameters->BackBufferWidth;
1536 mode.Height = pPresentationParameters->BackBufferHeight;
1537 mode.Format = pPresentationParameters->BackBufferFormat;
1538 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1540 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1541 displaymode_set = TRUE;
1545 * Create an opengl context for the display visual
1546 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1547 * use different properties after that point in time. FIXME: How to handle when requested format
1548 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1549 * it chooses is identical to the one already being used!
1550 **********************************/
1551 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1553 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1554 if(!object->context) {
1555 ERR("Failed to create the context array\n");
1556 hr = E_OUTOFMEMORY;
1557 goto error;
1559 object->num_contexts = 1;
1561 if(surface_type == SURFACE_OPENGL) {
1562 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1563 if (!object->context[0]) {
1564 ERR("Failed to create a new context\n");
1565 hr = WINED3DERR_NOTAVAILABLE;
1566 goto error;
1567 } else {
1568 TRACE("Context created (HWND=%p, glContext=%p)\n",
1569 object->win_handle, object->context[0]->glCtx);
1573 /*********************
1574 * Create the back, front and stencil buffers
1575 *******************/
1576 if(object->presentParms.BackBufferCount > 0) {
1577 UINT i;
1579 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1580 if(!object->backBuffer) {
1581 ERR("Out of memory\n");
1582 hr = E_OUTOFMEMORY;
1583 goto error;
1586 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1587 TRACE("calling rendertarget CB\n");
1588 hr = D3DCB_CreateRenderTarget(This->parent,
1589 parent,
1590 object->presentParms.BackBufferWidth,
1591 object->presentParms.BackBufferHeight,
1592 object->presentParms.BackBufferFormat,
1593 object->presentParms.MultiSampleType,
1594 object->presentParms.MultiSampleQuality,
1595 TRUE /* Lockable */,
1596 &object->backBuffer[i],
1597 NULL /* pShared (always null)*/);
1598 if(SUCCEEDED(hr)) {
1599 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1600 } else {
1601 ERR("Cannot create new back buffer\n");
1602 goto error;
1604 if(surface_type == SURFACE_OPENGL) {
1605 ENTER_GL();
1606 glDrawBuffer(GL_BACK);
1607 checkGLcall("glDrawBuffer(GL_BACK)");
1608 LEAVE_GL();
1611 } else {
1612 object->backBuffer = NULL;
1614 /* Single buffering - draw to front buffer */
1615 if(surface_type == SURFACE_OPENGL) {
1616 ENTER_GL();
1617 glDrawBuffer(GL_FRONT);
1618 checkGLcall("glDrawBuffer(GL_FRONT)");
1619 LEAVE_GL();
1623 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1624 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1625 TRACE("Creating depth stencil buffer\n");
1626 if (This->auto_depth_stencil_buffer == NULL ) {
1627 hr = D3DCB_CreateDepthStencil(This->parent,
1628 parent,
1629 object->presentParms.BackBufferWidth,
1630 object->presentParms.BackBufferHeight,
1631 object->presentParms.AutoDepthStencilFormat,
1632 object->presentParms.MultiSampleType,
1633 object->presentParms.MultiSampleQuality,
1634 FALSE /* FIXME: Discard */,
1635 &This->auto_depth_stencil_buffer,
1636 NULL /* pShared (always null)*/ );
1637 if (SUCCEEDED(hr)) {
1638 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1639 } else {
1640 ERR("Failed to create the auto depth stencil\n");
1641 goto error;
1646 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1648 TRACE("Created swapchain %p\n", object);
1649 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1650 return WINED3D_OK;
1652 error:
1653 if (displaymode_set) {
1654 DEVMODEW devmode;
1655 RECT clip_rc;
1657 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1658 ClipCursor(NULL);
1660 /* Change the display settings */
1661 memset(&devmode, 0, sizeof(devmode));
1662 devmode.dmSize = sizeof(devmode);
1663 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1664 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1665 devmode.dmPelsWidth = object->orig_width;
1666 devmode.dmPelsHeight = object->orig_height;
1667 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1670 if (object->backBuffer) {
1671 UINT i;
1672 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1673 if(object->backBuffer[i]) {
1674 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1675 IUnknown_Release(bufferParent); /* once for the get parent */
1676 if (IUnknown_Release(bufferParent) > 0) {
1677 FIXME("(%p) Something's still holding the back buffer\n",This);
1681 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1682 object->backBuffer = NULL;
1684 if(object->context && object->context[0])
1685 DestroyContext(This, object->context[0]);
1686 if(object->frontBuffer) {
1687 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1688 IUnknown_Release(bufferParent); /* once for the get parent */
1689 if (IUnknown_Release(bufferParent) > 0) {
1690 FIXME("(%p) Something's still holding the front buffer\n",This);
1693 HeapFree(GetProcessHeap(), 0, object);
1694 return hr;
1697 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1698 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1700 TRACE("(%p)\n", This);
1702 return This->NumberOfSwapChains;
1705 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1707 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1709 if(iSwapChain < This->NumberOfSwapChains) {
1710 *pSwapChain = This->swapchains[iSwapChain];
1711 IWineD3DSwapChain_AddRef(*pSwapChain);
1712 TRACE("(%p) returning %p\n", This, *pSwapChain);
1713 return WINED3D_OK;
1714 } else {
1715 TRACE("Swapchain out of range\n");
1716 *pSwapChain = NULL;
1717 return WINED3DERR_INVALIDCALL;
1721 /*****
1722 * Vertex Declaration
1723 *****/
1724 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1725 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1727 IWineD3DVertexDeclarationImpl *object = NULL;
1728 HRESULT hr = WINED3D_OK;
1730 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1731 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1733 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1735 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1736 if(FAILED(hr)) {
1737 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1738 *ppVertexDeclaration = NULL;
1741 return hr;
1744 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1745 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1747 unsigned int idx, idx2;
1748 unsigned int offset;
1749 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1750 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1751 BOOL has_blend_idx = has_blend &&
1752 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1753 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1754 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1755 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1756 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1757 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1758 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1760 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1761 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1763 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1764 WINED3DVERTEXELEMENT *elements = NULL;
1766 unsigned int size;
1767 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1768 if (has_blend_idx) num_blends--;
1770 /* Compute declaration size */
1771 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1772 has_psize + has_diffuse + has_specular + num_textures + 1;
1774 /* convert the declaration */
1775 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1776 if (!elements)
1777 return 0;
1779 elements[size-1] = end_element;
1780 idx = 0;
1781 if (has_pos) {
1782 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1783 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1784 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1786 else {
1787 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1788 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1790 elements[idx].UsageIndex = 0;
1791 idx++;
1793 if (has_blend && (num_blends > 0)) {
1794 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1795 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1796 else {
1797 switch(num_blends) {
1798 case 1: elements[idx].Type = WINED3DDECLTYPE_FLOAT1; break;
1799 case 2: elements[idx].Type = WINED3DDECLTYPE_FLOAT2; break;
1800 case 3: elements[idx].Type = WINED3DDECLTYPE_FLOAT3; break;
1801 case 4: elements[idx].Type = WINED3DDECLTYPE_FLOAT4; break;
1802 default:
1803 ERR("Unexpected amount of blend values: %u\n", num_blends);
1806 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1807 elements[idx].UsageIndex = 0;
1808 idx++;
1810 if (has_blend_idx) {
1811 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1812 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1813 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1814 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1815 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1816 else
1817 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1818 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1819 elements[idx].UsageIndex = 0;
1820 idx++;
1822 if (has_normal) {
1823 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1824 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1825 elements[idx].UsageIndex = 0;
1826 idx++;
1828 if (has_psize) {
1829 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1830 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1831 elements[idx].UsageIndex = 0;
1832 idx++;
1834 if (has_diffuse) {
1835 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1836 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1837 elements[idx].UsageIndex = 0;
1838 idx++;
1840 if (has_specular) {
1841 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1842 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1843 elements[idx].UsageIndex = 1;
1844 idx++;
1846 for (idx2 = 0; idx2 < num_textures; idx2++) {
1847 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1848 switch (numcoords) {
1849 case WINED3DFVF_TEXTUREFORMAT1:
1850 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1851 break;
1852 case WINED3DFVF_TEXTUREFORMAT2:
1853 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1854 break;
1855 case WINED3DFVF_TEXTUREFORMAT3:
1856 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1857 break;
1858 case WINED3DFVF_TEXTUREFORMAT4:
1859 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1860 break;
1862 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1863 elements[idx].UsageIndex = idx2;
1864 idx++;
1867 /* Now compute offsets, and initialize the rest of the fields */
1868 for (idx = 0, offset = 0; idx < size-1; idx++) {
1869 elements[idx].Stream = 0;
1870 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1871 elements[idx].Offset = offset;
1872 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1875 *ppVertexElements = elements;
1876 return size;
1879 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1880 WINED3DVERTEXELEMENT* elements = NULL;
1881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1882 unsigned int size;
1883 DWORD hr;
1885 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1886 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1888 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1889 HeapFree(GetProcessHeap(), 0, elements);
1890 if (hr != S_OK) return hr;
1892 return WINED3D_OK;
1895 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1897 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1898 HRESULT hr = WINED3D_OK;
1899 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1900 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1902 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1904 if (vertex_declaration) {
1905 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1908 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1910 if (WINED3D_OK != hr) {
1911 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1912 IWineD3DVertexShader_Release(*ppVertexShader);
1913 return WINED3DERR_INVALIDCALL;
1915 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1917 return WINED3D_OK;
1920 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1922 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1923 HRESULT hr = WINED3D_OK;
1925 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1926 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1927 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1928 if (WINED3D_OK == hr) {
1929 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1930 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1931 } else {
1932 WARN("(%p) : Failed to create pixel shader\n", This);
1935 return hr;
1938 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1939 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1942 IWineD3DPaletteImpl *object;
1943 HRESULT hr;
1944 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1946 /* Create the new object */
1947 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1948 if(!object) {
1949 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1950 return E_OUTOFMEMORY;
1953 object->lpVtbl = &IWineD3DPalette_Vtbl;
1954 object->ref = 1;
1955 object->Flags = Flags;
1956 object->parent = Parent;
1957 object->wineD3DDevice = This;
1958 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1960 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1962 if(!object->hpal) {
1963 HeapFree( GetProcessHeap(), 0, object);
1964 return E_OUTOFMEMORY;
1967 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1968 if(FAILED(hr)) {
1969 IWineD3DPalette_Release((IWineD3DPalette *) object);
1970 return hr;
1973 *Palette = (IWineD3DPalette *) object;
1975 return WINED3D_OK;
1978 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1979 HBITMAP hbm;
1980 BITMAP bm;
1981 HRESULT hr;
1982 HDC dcb = NULL, dcs = NULL;
1983 WINEDDCOLORKEY colorkey;
1985 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1986 if(hbm)
1988 GetObjectA(hbm, sizeof(BITMAP), &bm);
1989 dcb = CreateCompatibleDC(NULL);
1990 if(!dcb) goto out;
1991 SelectObject(dcb, hbm);
1993 else
1995 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1996 * couldn't be loaded
1998 memset(&bm, 0, sizeof(bm));
1999 bm.bmWidth = 32;
2000 bm.bmHeight = 32;
2003 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2004 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2005 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
2006 if(FAILED(hr)) {
2007 ERR("Wine logo requested, but failed to create surface\n");
2008 goto out;
2011 if(dcb) {
2012 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2013 if(FAILED(hr)) goto out;
2014 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2015 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2017 colorkey.dwColorSpaceLowValue = 0;
2018 colorkey.dwColorSpaceHighValue = 0;
2019 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2020 } else {
2021 /* Fill the surface with a white color to show that wined3d is there */
2022 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2025 out:
2026 if(dcb) {
2027 DeleteDC(dcb);
2029 if(hbm) {
2030 DeleteObject(hbm);
2032 return;
2035 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2036 unsigned int i;
2037 /* Under DirectX you can have texture stage operations even if no texture is
2038 bound, whereas opengl will only do texture operations when a valid texture is
2039 bound. We emulate this by creating dummy textures and binding them to each
2040 texture stage, but disable all stages by default. Hence if a stage is enabled
2041 then the default texture will kick in until replaced by a SetTexture call */
2042 ENTER_GL();
2044 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2045 /* The dummy texture does not have client storage backing */
2046 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2047 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2049 for (i = 0; i < GL_LIMITS(textures); i++) {
2050 GLubyte white = 255;
2052 /* Make appropriate texture active */
2053 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2054 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2055 checkGLcall("glActiveTextureARB");
2056 } else if (i > 0) {
2057 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2060 /* Generate an opengl texture name */
2061 glGenTextures(1, &This->dummyTextureName[i]);
2062 checkGLcall("glGenTextures");
2063 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2065 /* Generate a dummy 2d texture (not using 1d because they cause many
2066 * DRI drivers fall back to sw) */
2067 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2068 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2069 checkGLcall("glBindTexture");
2071 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2072 checkGLcall("glTexImage2D");
2074 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2075 /* Reenable because if supported it is enabled by default */
2076 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2077 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2080 LEAVE_GL();
2083 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2085 IWineD3DSwapChainImpl *swapchain = NULL;
2086 HRESULT hr;
2087 DWORD state;
2088 unsigned int i;
2090 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateSwapChain);
2091 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2092 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2094 /* TODO: Test if OpenGL is compiled in and loaded */
2096 TRACE("(%p) : Creating stateblock\n", This);
2097 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2098 hr = IWineD3DDevice_CreateStateBlock(iface,
2099 WINED3DSBT_INIT,
2100 (IWineD3DStateBlock **)&This->stateBlock,
2101 NULL);
2102 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2103 WARN("Failed to create stateblock\n");
2104 goto err_out;
2106 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2107 This->updateStateBlock = This->stateBlock;
2108 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2110 hr = allocate_shader_constants(This->updateStateBlock);
2111 if (WINED3D_OK != hr) {
2112 goto err_out;
2115 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2116 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2118 This->NumberOfPalettes = 1;
2119 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2120 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2121 ERR("Out of memory!\n");
2122 goto err_out;
2124 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2125 if(!This->palettes[0]) {
2126 ERR("Out of memory!\n");
2127 goto err_out;
2129 for (i = 0; i < 256; ++i) {
2130 This->palettes[0][i].peRed = 0xFF;
2131 This->palettes[0][i].peGreen = 0xFF;
2132 This->palettes[0][i].peBlue = 0xFF;
2133 This->palettes[0][i].peFlags = 0xFF;
2135 This->currentPalette = 0;
2137 /* Initialize the texture unit mapping to a 1:1 mapping */
2138 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2139 if (state < GL_LIMITS(fragment_samplers)) {
2140 This->texUnitMap[state] = state;
2141 This->rev_tex_unit_map[state] = state;
2142 } else {
2143 This->texUnitMap[state] = -1;
2144 This->rev_tex_unit_map[state] = -1;
2148 /* Setup the implicit swapchain */
2149 TRACE("Creating implicit swapchain\n");
2150 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2151 if (FAILED(hr) || !swapchain) {
2152 WARN("Failed to create implicit swapchain\n");
2153 goto err_out;
2156 This->NumberOfSwapChains = 1;
2157 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2158 if(!This->swapchains) {
2159 ERR("Out of memory!\n");
2160 goto err_out;
2162 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2164 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2165 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2166 This->render_targets[0] = swapchain->backBuffer[0];
2167 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2169 else {
2170 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2171 This->render_targets[0] = swapchain->frontBuffer;
2172 This->lastActiveRenderTarget = swapchain->frontBuffer;
2174 IWineD3DSurface_AddRef(This->render_targets[0]);
2175 This->activeContext = swapchain->context[0];
2176 This->lastThread = GetCurrentThreadId();
2178 /* Depth Stencil support */
2179 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2180 if (NULL != This->stencilBufferTarget) {
2181 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2184 hr = This->shader_backend->shader_alloc_private(iface);
2185 if(FAILED(hr)) {
2186 TRACE("Shader private data couldn't be allocated\n");
2187 goto err_out;
2189 hr = This->frag_pipe->alloc_private(iface);
2190 if(FAILED(hr)) {
2191 TRACE("Fragment pipeline private data couldn't be allocated\n");
2192 goto err_out;
2194 hr = This->blitter->alloc_private(iface);
2195 if(FAILED(hr)) {
2196 TRACE("Blitter private data couldn't be allocated\n");
2197 goto err_out;
2200 /* Set up some starting GL setup */
2202 /* Setup all the devices defaults */
2203 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2204 create_dummy_textures(This);
2206 ENTER_GL();
2208 { /* Set a default viewport */
2209 WINED3DVIEWPORT vp;
2210 vp.X = 0;
2211 vp.Y = 0;
2212 vp.Width = pPresentationParameters->BackBufferWidth;
2213 vp.Height = pPresentationParameters->BackBufferHeight;
2214 vp.MinZ = 0.0f;
2215 vp.MaxZ = 1.0f;
2216 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2219 /* Initialize the current view state */
2220 This->view_ident = 1;
2221 This->contexts[0]->last_was_rhw = 0;
2222 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2223 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2225 switch(wined3d_settings.offscreen_rendering_mode) {
2226 case ORM_FBO:
2227 case ORM_PBUFFER:
2228 This->offscreenBuffer = GL_BACK;
2229 break;
2231 case ORM_BACKBUFFER:
2233 if(This->activeContext->aux_buffers > 0) {
2234 TRACE("Using auxilliary buffer for offscreen rendering\n");
2235 This->offscreenBuffer = GL_AUX0;
2236 } else {
2237 TRACE("Using back buffer for offscreen rendering\n");
2238 This->offscreenBuffer = GL_BACK;
2243 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2244 LEAVE_GL();
2246 /* Clear the screen */
2247 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2248 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2249 0x00, 1.0, 0);
2251 This->d3d_initialized = TRUE;
2253 if(wined3d_settings.logo) {
2254 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2256 This->highest_dirty_ps_const = 0;
2257 This->highest_dirty_vs_const = 0;
2258 return WINED3D_OK;
2260 err_out:
2261 HeapFree(GetProcessHeap(), 0, This->render_targets);
2262 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2263 HeapFree(GetProcessHeap(), 0, This->swapchains);
2264 This->NumberOfSwapChains = 0;
2265 if(This->palettes) {
2266 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2267 HeapFree(GetProcessHeap(), 0, This->palettes);
2269 This->NumberOfPalettes = 0;
2270 if(swapchain) {
2271 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2273 if(This->stateBlock) {
2274 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2275 This->stateBlock = NULL;
2277 if (This->blit_priv) {
2278 This->blitter->free_private(iface);
2280 if (This->fragment_priv) {
2281 This->frag_pipe->free_private(iface);
2283 if (This->shader_priv) {
2284 This->shader_backend->shader_free_private(iface);
2286 return hr;
2289 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2291 IWineD3DSwapChainImpl *swapchain = NULL;
2292 HRESULT hr;
2294 /* Setup the implicit swapchain */
2295 TRACE("Creating implicit swapchain\n");
2296 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2297 if (FAILED(hr) || !swapchain) {
2298 WARN("Failed to create implicit swapchain\n");
2299 goto err_out;
2302 This->NumberOfSwapChains = 1;
2303 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2304 if(!This->swapchains) {
2305 ERR("Out of memory!\n");
2306 goto err_out;
2308 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2309 return WINED3D_OK;
2311 err_out:
2312 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2313 return hr;
2316 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2318 int sampler;
2319 UINT i;
2320 TRACE("(%p)\n", This);
2322 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2324 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2325 * it was created. Thus make sure a context is active for the glDelete* calls
2327 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2329 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2331 TRACE("Deleting high order patches\n");
2332 for(i = 0; i < PATCHMAP_SIZE; i++) {
2333 struct list *e1, *e2;
2334 struct WineD3DRectPatch *patch;
2335 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2336 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2337 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2341 /* Delete the palette conversion shader if it is around */
2342 if(This->paletteConversionShader) {
2343 ENTER_GL();
2344 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2345 LEAVE_GL();
2346 This->paletteConversionShader = 0;
2349 /* Delete the pbuffer context if there is any */
2350 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2352 /* Delete the mouse cursor texture */
2353 if(This->cursorTexture) {
2354 ENTER_GL();
2355 glDeleteTextures(1, &This->cursorTexture);
2356 LEAVE_GL();
2357 This->cursorTexture = 0;
2360 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2361 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2363 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2364 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2367 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2368 * private data, it might contain opengl pointers
2370 if(This->depth_blt_texture) {
2371 glDeleteTextures(1, &This->depth_blt_texture);
2372 This->depth_blt_texture = 0;
2374 if (This->depth_blt_rb) {
2375 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2376 This->depth_blt_rb = 0;
2377 This->depth_blt_rb_w = 0;
2378 This->depth_blt_rb_h = 0;
2381 /* Release the update stateblock */
2382 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2383 if(This->updateStateBlock != This->stateBlock)
2384 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2386 This->updateStateBlock = NULL;
2388 { /* because were not doing proper internal refcounts releasing the primary state block
2389 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2390 to set this->stateBlock = NULL; first */
2391 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2392 This->stateBlock = NULL;
2394 /* Release the stateblock */
2395 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2396 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2400 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2401 This->blitter->free_private(iface);
2402 This->frag_pipe->free_private(iface);
2403 This->shader_backend->shader_free_private(iface);
2405 /* Release the buffers (with sanity checks)*/
2406 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2407 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2408 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2409 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2411 This->stencilBufferTarget = NULL;
2413 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2414 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2415 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2417 TRACE("Setting rendertarget to NULL\n");
2418 This->render_targets[0] = NULL;
2420 if (This->auto_depth_stencil_buffer) {
2421 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2422 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2424 This->auto_depth_stencil_buffer = NULL;
2427 for(i=0; i < This->NumberOfSwapChains; i++) {
2428 TRACE("Releasing the implicit swapchain %d\n", i);
2429 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2430 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2434 HeapFree(GetProcessHeap(), 0, This->swapchains);
2435 This->swapchains = NULL;
2436 This->NumberOfSwapChains = 0;
2438 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2439 HeapFree(GetProcessHeap(), 0, This->palettes);
2440 This->palettes = NULL;
2441 This->NumberOfPalettes = 0;
2443 HeapFree(GetProcessHeap(), 0, This->render_targets);
2444 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2445 This->render_targets = NULL;
2446 This->draw_buffers = NULL;
2448 This->d3d_initialized = FALSE;
2449 return WINED3D_OK;
2452 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2454 unsigned int i;
2456 for(i=0; i < This->NumberOfSwapChains; i++) {
2457 TRACE("Releasing the implicit swapchain %d\n", i);
2458 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2459 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2463 HeapFree(GetProcessHeap(), 0, This->swapchains);
2464 This->swapchains = NULL;
2465 This->NumberOfSwapChains = 0;
2466 return WINED3D_OK;
2469 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2470 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2471 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2473 * There is no way to deactivate thread safety once it is enabled.
2475 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2478 /*For now just store the flag(needed in case of ddraw) */
2479 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2481 return;
2484 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2485 const WINED3DDISPLAYMODE* pMode) {
2486 DEVMODEW devmode;
2487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2488 LONG ret;
2489 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2490 RECT clip_rc;
2492 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2494 /* Resize the screen even without a window:
2495 * The app could have unset it with SetCooperativeLevel, but not called
2496 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2497 * but we don't have any hwnd
2500 memset(&devmode, 0, sizeof(devmode));
2501 devmode.dmSize = sizeof(devmode);
2502 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2503 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2504 devmode.dmPelsWidth = pMode->Width;
2505 devmode.dmPelsHeight = pMode->Height;
2507 devmode.dmDisplayFrequency = pMode->RefreshRate;
2508 if (pMode->RefreshRate != 0) {
2509 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2512 /* Only change the mode if necessary */
2513 if( (This->ddraw_width == pMode->Width) &&
2514 (This->ddraw_height == pMode->Height) &&
2515 (This->ddraw_format == pMode->Format) &&
2516 (pMode->RefreshRate == 0) ) {
2517 return WINED3D_OK;
2520 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2521 if (ret != DISP_CHANGE_SUCCESSFUL) {
2522 if(devmode.dmDisplayFrequency != 0) {
2523 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2524 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2525 devmode.dmDisplayFrequency = 0;
2526 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2528 if(ret != DISP_CHANGE_SUCCESSFUL) {
2529 return WINED3DERR_NOTAVAILABLE;
2533 /* Store the new values */
2534 This->ddraw_width = pMode->Width;
2535 This->ddraw_height = pMode->Height;
2536 This->ddraw_format = pMode->Format;
2538 /* And finally clip mouse to our screen */
2539 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2540 ClipCursor(&clip_rc);
2542 return WINED3D_OK;
2545 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2547 *ppD3D= This->wineD3D;
2548 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2549 IWineD3D_AddRef(*ppD3D);
2550 return WINED3D_OK;
2553 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2556 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2557 (This->adapter->TextureRam/(1024*1024)),
2558 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2559 /* return simulated texture memory left */
2560 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2565 /*****
2566 * Get / Set FVF
2567 *****/
2568 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2571 /* Update the current state block */
2572 This->updateStateBlock->changed.fvf = TRUE;
2574 if(This->updateStateBlock->fvf == fvf) {
2575 TRACE("Application is setting the old fvf over, nothing to do\n");
2576 return WINED3D_OK;
2579 This->updateStateBlock->fvf = fvf;
2580 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2581 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2582 return WINED3D_OK;
2586 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2588 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2589 *pfvf = This->stateBlock->fvf;
2590 return WINED3D_OK;
2593 /*****
2594 * Get / Set Stream Source
2595 *****/
2596 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2598 IWineD3DVertexBuffer *oldSrc;
2600 if (StreamNumber >= MAX_STREAMS) {
2601 WARN("Stream out of range %d\n", StreamNumber);
2602 return WINED3DERR_INVALIDCALL;
2603 } else if(OffsetInBytes & 0x3) {
2604 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2605 return WINED3DERR_INVALIDCALL;
2608 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2609 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2611 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2613 if(oldSrc == pStreamData &&
2614 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2615 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2616 TRACE("Application is setting the old values over, nothing to do\n");
2617 return WINED3D_OK;
2620 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2621 if (pStreamData) {
2622 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2623 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2626 /* Handle recording of state blocks */
2627 if (This->isRecordingState) {
2628 TRACE("Recording... not performing anything\n");
2629 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2630 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2631 return WINED3D_OK;
2634 /* Need to do a getParent and pass the references up */
2635 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2636 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2637 so for now, just count internally */
2638 if (pStreamData != NULL) {
2639 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2640 InterlockedIncrement(&vbImpl->bindCount);
2641 IWineD3DVertexBuffer_AddRef(pStreamData);
2643 if (oldSrc != NULL) {
2644 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2645 IWineD3DVertexBuffer_Release(oldSrc);
2648 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2650 return WINED3D_OK;
2653 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2656 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2657 This->stateBlock->streamSource[StreamNumber],
2658 This->stateBlock->streamOffset[StreamNumber],
2659 This->stateBlock->streamStride[StreamNumber]);
2661 if (StreamNumber >= MAX_STREAMS) {
2662 WARN("Stream out of range %d\n", StreamNumber);
2663 return WINED3DERR_INVALIDCALL;
2665 *pStream = This->stateBlock->streamSource[StreamNumber];
2666 *pStride = This->stateBlock->streamStride[StreamNumber];
2667 if (pOffset) {
2668 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2671 if (*pStream != NULL) {
2672 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2674 return WINED3D_OK;
2677 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2679 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2680 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2682 /* Verify input at least in d3d9 this is invalid*/
2683 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2684 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2685 return WINED3DERR_INVALIDCALL;
2687 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2688 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2689 return WINED3DERR_INVALIDCALL;
2691 if( Divider == 0 ){
2692 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2693 return WINED3DERR_INVALIDCALL;
2696 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2697 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2699 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2700 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2702 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2703 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2704 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2707 return WINED3D_OK;
2710 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2713 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2714 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2716 TRACE("(%p) : returning %d\n", This, *Divider);
2718 return WINED3D_OK;
2721 /*****
2722 * Get / Set & Multiply Transform
2723 *****/
2724 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2727 /* Most of this routine, comments included copied from ddraw tree initially: */
2728 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2730 /* Handle recording of state blocks */
2731 if (This->isRecordingState) {
2732 TRACE("Recording... not performing anything\n");
2733 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2734 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2735 return WINED3D_OK;
2739 * If the new matrix is the same as the current one,
2740 * we cut off any further processing. this seems to be a reasonable
2741 * optimization because as was noticed, some apps (warcraft3 for example)
2742 * tend towards setting the same matrix repeatedly for some reason.
2744 * From here on we assume that the new matrix is different, wherever it matters.
2746 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2747 TRACE("The app is setting the same matrix over again\n");
2748 return WINED3D_OK;
2749 } else {
2750 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2754 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2755 where ViewMat = Camera space, WorldMat = world space.
2757 In OpenGL, camera and world space is combined into GL_MODELVIEW
2758 matrix. The Projection matrix stay projection matrix.
2761 /* Capture the times we can just ignore the change for now */
2762 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2763 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2764 /* Handled by the state manager */
2767 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2768 return WINED3D_OK;
2771 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2773 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2774 *pMatrix = This->stateBlock->transforms[State];
2775 return WINED3D_OK;
2778 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2779 const WINED3DMATRIX *mat = NULL;
2780 WINED3DMATRIX temp;
2782 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2783 * below means it will be recorded in a state block change, but it
2784 * works regardless where it is recorded.
2785 * If this is found to be wrong, change to StateBlock.
2787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2788 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2790 if (State < HIGHEST_TRANSFORMSTATE)
2792 mat = &This->updateStateBlock->transforms[State];
2793 } else {
2794 FIXME("Unhandled transform state!!\n");
2797 multiply_matrix(&temp, mat, pMatrix);
2799 /* Apply change via set transform - will reapply to eg. lights this way */
2800 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2803 /*****
2804 * Get / Set Light
2805 *****/
2806 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2807 you can reference any indexes you want as long as that number max are enabled at any
2808 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2809 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2810 but when recording, just build a chain pretty much of commands to be replayed. */
2812 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2813 float rho;
2814 PLIGHTINFOEL *object = NULL;
2815 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2816 struct list *e;
2818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2819 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2821 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2822 * the gl driver.
2824 if(!pLight) {
2825 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2826 return WINED3DERR_INVALIDCALL;
2829 switch(pLight->Type) {
2830 case WINED3DLIGHT_POINT:
2831 case WINED3DLIGHT_SPOT:
2832 case WINED3DLIGHT_PARALLELPOINT:
2833 case WINED3DLIGHT_GLSPOT:
2834 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2835 * most wanted
2837 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2838 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2839 return WINED3DERR_INVALIDCALL;
2841 break;
2843 case WINED3DLIGHT_DIRECTIONAL:
2844 /* Ignores attenuation */
2845 break;
2847 default:
2848 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2849 return WINED3DERR_INVALIDCALL;
2852 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2853 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2854 if(object->OriginalIndex == Index) break;
2855 object = NULL;
2858 if(!object) {
2859 TRACE("Adding new light\n");
2860 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2861 if(!object) {
2862 ERR("Out of memory error when allocating a light\n");
2863 return E_OUTOFMEMORY;
2865 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2866 object->glIndex = -1;
2867 object->OriginalIndex = Index;
2868 object->changed = TRUE;
2871 /* Initialize the object */
2872 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,
2873 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2874 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2875 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2876 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2877 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2878 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2880 /* Save away the information */
2881 object->OriginalParms = *pLight;
2883 switch (pLight->Type) {
2884 case WINED3DLIGHT_POINT:
2885 /* Position */
2886 object->lightPosn[0] = pLight->Position.x;
2887 object->lightPosn[1] = pLight->Position.y;
2888 object->lightPosn[2] = pLight->Position.z;
2889 object->lightPosn[3] = 1.0f;
2890 object->cutoff = 180.0f;
2891 /* FIXME: Range */
2892 break;
2894 case WINED3DLIGHT_DIRECTIONAL:
2895 /* Direction */
2896 object->lightPosn[0] = -pLight->Direction.x;
2897 object->lightPosn[1] = -pLight->Direction.y;
2898 object->lightPosn[2] = -pLight->Direction.z;
2899 object->lightPosn[3] = 0.0;
2900 object->exponent = 0.0f;
2901 object->cutoff = 180.0f;
2902 break;
2904 case WINED3DLIGHT_SPOT:
2905 /* Position */
2906 object->lightPosn[0] = pLight->Position.x;
2907 object->lightPosn[1] = pLight->Position.y;
2908 object->lightPosn[2] = pLight->Position.z;
2909 object->lightPosn[3] = 1.0;
2911 /* Direction */
2912 object->lightDirn[0] = pLight->Direction.x;
2913 object->lightDirn[1] = pLight->Direction.y;
2914 object->lightDirn[2] = pLight->Direction.z;
2915 object->lightDirn[3] = 1.0;
2918 * opengl-ish and d3d-ish spot lights use too different models for the
2919 * light "intensity" as a function of the angle towards the main light direction,
2920 * so we only can approximate very roughly.
2921 * however spot lights are rather rarely used in games (if ever used at all).
2922 * furthermore if still used, probably nobody pays attention to such details.
2924 if (pLight->Falloff == 0) {
2925 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2926 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2927 * will always be 1.0 for both of them, and we don't have to care for the
2928 * rest of the rather complex calculation
2930 object->exponent = 0;
2931 } else {
2932 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2933 if (rho < 0.0001) rho = 0.0001f;
2934 object->exponent = -0.3/log(cos(rho/2));
2936 if (object->exponent > 128.0) {
2937 object->exponent = 128.0;
2939 object->cutoff = pLight->Phi*90/M_PI;
2941 /* FIXME: Range */
2942 break;
2944 default:
2945 FIXME("Unrecognized light type %d\n", pLight->Type);
2948 /* Update the live definitions if the light is currently assigned a glIndex */
2949 if (object->glIndex != -1 && !This->isRecordingState) {
2950 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2952 return WINED3D_OK;
2955 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2956 PLIGHTINFOEL *lightInfo = NULL;
2957 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2958 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2959 struct list *e;
2960 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2962 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2963 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2964 if(lightInfo->OriginalIndex == Index) break;
2965 lightInfo = NULL;
2968 if (lightInfo == NULL) {
2969 TRACE("Light information requested but light not defined\n");
2970 return WINED3DERR_INVALIDCALL;
2973 *pLight = lightInfo->OriginalParms;
2974 return WINED3D_OK;
2977 /*****
2978 * Get / Set Light Enable
2979 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2980 *****/
2981 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2982 PLIGHTINFOEL *lightInfo = NULL;
2983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2984 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2985 struct list *e;
2986 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2988 /* Tests show true = 128...not clear why */
2989 Enable = Enable? 128: 0;
2991 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2992 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2993 if(lightInfo->OriginalIndex == Index) break;
2994 lightInfo = NULL;
2996 TRACE("Found light: %p\n", lightInfo);
2998 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2999 if (lightInfo == NULL) {
3001 TRACE("Light enabled requested but light not defined, so defining one!\n");
3002 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3004 /* Search for it again! Should be fairly quick as near head of list */
3005 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3006 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3007 if(lightInfo->OriginalIndex == Index) break;
3008 lightInfo = NULL;
3010 if (lightInfo == NULL) {
3011 FIXME("Adding default lights has failed dismally\n");
3012 return WINED3DERR_INVALIDCALL;
3016 lightInfo->enabledChanged = TRUE;
3017 if(!Enable) {
3018 if(lightInfo->glIndex != -1) {
3019 if(!This->isRecordingState) {
3020 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3023 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3024 lightInfo->glIndex = -1;
3025 } else {
3026 TRACE("Light already disabled, nothing to do\n");
3028 lightInfo->enabled = FALSE;
3029 } else {
3030 lightInfo->enabled = TRUE;
3031 if (lightInfo->glIndex != -1) {
3032 /* nop */
3033 TRACE("Nothing to do as light was enabled\n");
3034 } else {
3035 int i;
3036 /* Find a free gl light */
3037 for(i = 0; i < This->maxConcurrentLights; i++) {
3038 if(This->updateStateBlock->activeLights[i] == NULL) {
3039 This->updateStateBlock->activeLights[i] = lightInfo;
3040 lightInfo->glIndex = i;
3041 break;
3044 if(lightInfo->glIndex == -1) {
3045 /* Our tests show that Windows returns D3D_OK in this situation, even with
3046 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3047 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3048 * as well for those lights.
3050 * TODO: Test how this affects rendering
3052 FIXME("Too many concurrently active lights\n");
3053 return WINED3D_OK;
3056 /* i == lightInfo->glIndex */
3057 if(!This->isRecordingState) {
3058 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3063 return WINED3D_OK;
3066 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3068 PLIGHTINFOEL *lightInfo = NULL;
3069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3070 struct list *e;
3071 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3072 TRACE("(%p) : for idx(%d)\n", This, Index);
3074 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3075 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3076 if(lightInfo->OriginalIndex == Index) break;
3077 lightInfo = NULL;
3080 if (lightInfo == NULL) {
3081 TRACE("Light enabled state requested but light not defined\n");
3082 return WINED3DERR_INVALIDCALL;
3084 /* true is 128 according to SetLightEnable */
3085 *pEnable = lightInfo->enabled ? 128 : 0;
3086 return WINED3D_OK;
3089 /*****
3090 * Get / Set Clip Planes
3091 *****/
3092 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3094 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3096 /* Validate Index */
3097 if (Index >= GL_LIMITS(clipplanes)) {
3098 TRACE("Application has requested clipplane this device doesn't support\n");
3099 return WINED3DERR_INVALIDCALL;
3102 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3104 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3105 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3106 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3107 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3108 TRACE("Application is setting old values over, nothing to do\n");
3109 return WINED3D_OK;
3112 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3113 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3114 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3115 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3117 /* Handle recording of state blocks */
3118 if (This->isRecordingState) {
3119 TRACE("Recording... not performing anything\n");
3120 return WINED3D_OK;
3123 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3125 return WINED3D_OK;
3128 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3130 TRACE("(%p) : for idx %d\n", This, Index);
3132 /* Validate Index */
3133 if (Index >= GL_LIMITS(clipplanes)) {
3134 TRACE("Application has requested clipplane this device doesn't support\n");
3135 return WINED3DERR_INVALIDCALL;
3138 pPlane[0] = This->stateBlock->clipplane[Index][0];
3139 pPlane[1] = This->stateBlock->clipplane[Index][1];
3140 pPlane[2] = This->stateBlock->clipplane[Index][2];
3141 pPlane[3] = This->stateBlock->clipplane[Index][3];
3142 return WINED3D_OK;
3145 /*****
3146 * Get / Set Clip Plane Status
3147 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3148 *****/
3149 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3151 FIXME("(%p) : stub\n", This);
3152 if (NULL == pClipStatus) {
3153 return WINED3DERR_INVALIDCALL;
3155 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3156 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3157 return WINED3D_OK;
3160 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3162 FIXME("(%p) : stub\n", This);
3163 if (NULL == pClipStatus) {
3164 return WINED3DERR_INVALIDCALL;
3166 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3167 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3168 return WINED3D_OK;
3171 /*****
3172 * Get / Set Material
3173 *****/
3174 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3177 This->updateStateBlock->changed.material = TRUE;
3178 This->updateStateBlock->material = *pMaterial;
3180 /* Handle recording of state blocks */
3181 if (This->isRecordingState) {
3182 TRACE("Recording... not performing anything\n");
3183 return WINED3D_OK;
3186 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3187 return WINED3D_OK;
3190 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3192 *pMaterial = This->updateStateBlock->material;
3193 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3194 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3195 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3196 pMaterial->Ambient.b, pMaterial->Ambient.a);
3197 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3198 pMaterial->Specular.b, pMaterial->Specular.a);
3199 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3200 pMaterial->Emissive.b, pMaterial->Emissive.a);
3201 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3203 return WINED3D_OK;
3206 /*****
3207 * Get / Set Indices
3208 *****/
3209 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3211 IWineD3DIndexBuffer *oldIdxs;
3213 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3214 oldIdxs = This->updateStateBlock->pIndexData;
3216 This->updateStateBlock->changed.indices = TRUE;
3217 This->updateStateBlock->pIndexData = pIndexData;
3219 /* Handle recording of state blocks */
3220 if (This->isRecordingState) {
3221 TRACE("Recording... not performing anything\n");
3222 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3223 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3224 return WINED3D_OK;
3227 if(oldIdxs != pIndexData) {
3228 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3229 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3230 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3232 return WINED3D_OK;
3235 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3238 *ppIndexData = This->stateBlock->pIndexData;
3240 /* up ref count on ppindexdata */
3241 if (*ppIndexData) {
3242 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3243 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3244 }else{
3245 TRACE("(%p) No index data set\n", This);
3247 TRACE("Returning %p\n", *ppIndexData);
3249 return WINED3D_OK;
3252 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3253 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3255 TRACE("(%p)->(%d)\n", This, BaseIndex);
3257 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3258 TRACE("Application is setting the old value over, nothing to do\n");
3259 return WINED3D_OK;
3262 This->updateStateBlock->baseVertexIndex = BaseIndex;
3264 if (This->isRecordingState) {
3265 TRACE("Recording... not performing anything\n");
3266 return WINED3D_OK;
3268 /* The base vertex index affects the stream sources */
3269 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3270 return WINED3D_OK;
3273 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3275 TRACE("(%p) : base_index %p\n", This, base_index);
3277 *base_index = This->stateBlock->baseVertexIndex;
3279 TRACE("Returning %u\n", *base_index);
3281 return WINED3D_OK;
3284 /*****
3285 * Get / Set Viewports
3286 *****/
3287 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3290 TRACE("(%p)\n", This);
3291 This->updateStateBlock->changed.viewport = TRUE;
3292 This->updateStateBlock->viewport = *pViewport;
3294 /* Handle recording of state blocks */
3295 if (This->isRecordingState) {
3296 TRACE("Recording... not performing anything\n");
3297 return WINED3D_OK;
3300 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3301 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3303 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3304 return WINED3D_OK;
3308 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3310 TRACE("(%p)\n", This);
3311 *pViewport = This->stateBlock->viewport;
3312 return WINED3D_OK;
3315 /*****
3316 * Get / Set Render States
3317 * TODO: Verify against dx9 definitions
3318 *****/
3319 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3322 DWORD oldValue = This->stateBlock->renderState[State];
3324 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3326 This->updateStateBlock->changed.renderState[State] = TRUE;
3327 This->updateStateBlock->renderState[State] = Value;
3329 /* Handle recording of state blocks */
3330 if (This->isRecordingState) {
3331 TRACE("Recording... not performing anything\n");
3332 return WINED3D_OK;
3335 /* Compared here and not before the assignment to allow proper stateblock recording */
3336 if(Value == oldValue) {
3337 TRACE("Application is setting the old value over, nothing to do\n");
3338 } else {
3339 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3342 return WINED3D_OK;
3345 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3347 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3348 *pValue = This->stateBlock->renderState[State];
3349 return WINED3D_OK;
3352 /*****
3353 * Get / Set Sampler States
3354 * TODO: Verify against dx9 definitions
3355 *****/
3357 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3359 DWORD oldValue;
3361 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3362 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3364 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3365 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3368 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3369 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3370 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3373 * SetSampler is designed to allow for more than the standard up to 8 textures
3374 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3375 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3377 * http://developer.nvidia.com/object/General_FAQ.html#t6
3379 * There are two new settings for GForce
3380 * the sampler one:
3381 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3382 * and the texture one:
3383 * GL_MAX_TEXTURE_COORDS_ARB.
3384 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3385 ******************/
3387 oldValue = This->stateBlock->samplerState[Sampler][Type];
3388 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3389 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3391 /* Handle recording of state blocks */
3392 if (This->isRecordingState) {
3393 TRACE("Recording... not performing anything\n");
3394 return WINED3D_OK;
3397 if(oldValue == Value) {
3398 TRACE("Application is setting the old value over, nothing to do\n");
3399 return WINED3D_OK;
3402 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3404 return WINED3D_OK;
3407 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3410 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3411 This, Sampler, debug_d3dsamplerstate(Type), Type);
3413 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3414 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3417 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3418 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3419 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3421 *Value = This->stateBlock->samplerState[Sampler][Type];
3422 TRACE("(%p) : Returning %#x\n", This, *Value);
3424 return WINED3D_OK;
3427 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3430 This->updateStateBlock->changed.scissorRect = TRUE;
3431 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3432 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3433 return WINED3D_OK;
3435 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3437 if(This->isRecordingState) {
3438 TRACE("Recording... not performing anything\n");
3439 return WINED3D_OK;
3442 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3444 return WINED3D_OK;
3447 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3450 *pRect = This->updateStateBlock->scissorRect;
3451 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3452 return WINED3D_OK;
3455 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3457 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3459 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3461 This->updateStateBlock->vertexDecl = pDecl;
3462 This->updateStateBlock->changed.vertexDecl = TRUE;
3464 if (This->isRecordingState) {
3465 TRACE("Recording... not performing anything\n");
3466 return WINED3D_OK;
3467 } else if(pDecl == oldDecl) {
3468 /* Checked after the assignment to allow proper stateblock recording */
3469 TRACE("Application is setting the old declaration over, nothing to do\n");
3470 return WINED3D_OK;
3473 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3474 return WINED3D_OK;
3477 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3480 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3482 *ppDecl = This->stateBlock->vertexDecl;
3483 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3484 return WINED3D_OK;
3487 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3489 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3491 This->updateStateBlock->vertexShader = pShader;
3492 This->updateStateBlock->changed.vertexShader = TRUE;
3494 if (This->isRecordingState) {
3495 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3496 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3497 TRACE("Recording... not performing anything\n");
3498 return WINED3D_OK;
3499 } else if(oldShader == pShader) {
3500 /* Checked here to allow proper stateblock recording */
3501 TRACE("App is setting the old shader over, nothing to do\n");
3502 return WINED3D_OK;
3505 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3506 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3507 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3509 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3511 return WINED3D_OK;
3514 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3517 if (NULL == ppShader) {
3518 return WINED3DERR_INVALIDCALL;
3520 *ppShader = This->stateBlock->vertexShader;
3521 if( NULL != *ppShader)
3522 IWineD3DVertexShader_AddRef(*ppShader);
3524 TRACE("(%p) : returning %p\n", This, *ppShader);
3525 return WINED3D_OK;
3528 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3529 IWineD3DDevice *iface,
3530 UINT start,
3531 CONST BOOL *srcData,
3532 UINT count) {
3534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3535 int i, cnt = min(count, MAX_CONST_B - start);
3537 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3538 iface, srcData, start, count);
3540 if (srcData == NULL || cnt < 0)
3541 return WINED3DERR_INVALIDCALL;
3543 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3544 for (i = 0; i < cnt; i++)
3545 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3547 for (i = start; i < cnt + start; ++i) {
3548 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3551 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3553 return WINED3D_OK;
3556 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3557 IWineD3DDevice *iface,
3558 UINT start,
3559 BOOL *dstData,
3560 UINT count) {
3562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3563 int cnt = min(count, MAX_CONST_B - start);
3565 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3566 iface, dstData, start, count);
3568 if (dstData == NULL || cnt < 0)
3569 return WINED3DERR_INVALIDCALL;
3571 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3572 return WINED3D_OK;
3575 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3576 IWineD3DDevice *iface,
3577 UINT start,
3578 CONST int *srcData,
3579 UINT count) {
3581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3582 int i, cnt = min(count, MAX_CONST_I - start);
3584 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3585 iface, srcData, start, count);
3587 if (srcData == NULL || cnt < 0)
3588 return WINED3DERR_INVALIDCALL;
3590 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3591 for (i = 0; i < cnt; i++)
3592 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3593 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3595 for (i = start; i < cnt + start; ++i) {
3596 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3599 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3601 return WINED3D_OK;
3604 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3605 IWineD3DDevice *iface,
3606 UINT start,
3607 int *dstData,
3608 UINT count) {
3610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3611 int cnt = min(count, MAX_CONST_I - start);
3613 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3614 iface, dstData, start, count);
3616 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3617 return WINED3DERR_INVALIDCALL;
3619 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3620 return WINED3D_OK;
3623 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3624 IWineD3DDevice *iface,
3625 UINT start,
3626 CONST float *srcData,
3627 UINT count) {
3629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3630 UINT i;
3632 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3633 iface, srcData, start, count);
3635 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3636 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3637 return WINED3DERR_INVALIDCALL;
3639 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3640 if(TRACE_ON(d3d)) {
3641 for (i = 0; i < count; i++)
3642 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3643 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3646 for (i = start; i < count + start; ++i) {
3647 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3648 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3649 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3650 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3651 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3653 ptr->idx[ptr->count++] = i;
3654 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3658 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3660 return WINED3D_OK;
3663 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3664 IWineD3DDevice *iface,
3665 UINT start,
3666 CONST float *srcData,
3667 UINT count) {
3669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3670 UINT i;
3672 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3673 iface, srcData, start, count);
3675 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3676 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3677 return WINED3DERR_INVALIDCALL;
3679 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3680 if(TRACE_ON(d3d)) {
3681 for (i = 0; i < count; i++)
3682 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3683 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3686 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3687 * context. On a context switch the old context will be fully dirtified
3689 memset(This->activeContext->vshader_const_dirty + start, 1,
3690 sizeof(*This->activeContext->vshader_const_dirty) * count);
3691 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count+1);
3693 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3695 return WINED3D_OK;
3698 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3699 IWineD3DDevice *iface,
3700 UINT start,
3701 float *dstData,
3702 UINT count) {
3704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3705 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3707 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3708 iface, dstData, start, count);
3710 if (dstData == NULL || cnt < 0)
3711 return WINED3DERR_INVALIDCALL;
3713 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3714 return WINED3D_OK;
3717 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3718 DWORD i;
3719 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3720 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3724 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3725 int i = This->rev_tex_unit_map[unit];
3726 int j = This->texUnitMap[stage];
3728 This->texUnitMap[stage] = unit;
3729 if (i != -1 && i != stage) {
3730 This->texUnitMap[i] = -1;
3733 This->rev_tex_unit_map[unit] = stage;
3734 if (j != -1 && j != unit) {
3735 This->rev_tex_unit_map[j] = -1;
3739 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3740 int i;
3742 for (i = 0; i < MAX_TEXTURES; ++i) {
3743 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3744 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3745 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3746 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3747 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3748 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3749 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3750 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3752 if (color_op == WINED3DTOP_DISABLE) {
3753 /* Not used, and disable higher stages */
3754 while (i < MAX_TEXTURES) {
3755 This->fixed_function_usage_map[i] = FALSE;
3756 ++i;
3758 break;
3761 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3762 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3763 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3764 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3765 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3766 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3767 This->fixed_function_usage_map[i] = TRUE;
3768 } else {
3769 This->fixed_function_usage_map[i] = FALSE;
3772 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3773 This->fixed_function_usage_map[i+1] = TRUE;
3778 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3779 int i, tex;
3781 device_update_fixed_function_usage_map(This);
3783 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3784 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3785 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3786 if (!This->fixed_function_usage_map[i]) continue;
3788 if (This->texUnitMap[i] != i) {
3789 device_map_stage(This, i, i);
3790 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3791 markTextureStagesDirty(This, i);
3794 return;
3797 /* Now work out the mapping */
3798 tex = 0;
3799 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3800 if (!This->fixed_function_usage_map[i]) continue;
3802 if (This->texUnitMap[i] != tex) {
3803 device_map_stage(This, i, tex);
3804 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3805 markTextureStagesDirty(This, i);
3808 ++tex;
3812 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3813 const DWORD *sampler_tokens =
3814 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3815 int i;
3817 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3818 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3819 device_map_stage(This, i, i);
3820 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3821 if (i < MAX_TEXTURES) {
3822 markTextureStagesDirty(This, i);
3828 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3829 const DWORD *vshader_sampler_tokens, int unit)
3831 int current_mapping = This->rev_tex_unit_map[unit];
3833 if (current_mapping == -1) {
3834 /* Not currently used */
3835 return TRUE;
3838 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3839 /* Used by a fragment sampler */
3841 if (!pshader_sampler_tokens) {
3842 /* No pixel shader, check fixed function */
3843 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3846 /* Pixel shader, check the shader's sampler map */
3847 return !pshader_sampler_tokens[current_mapping];
3850 /* Used by a vertex sampler */
3851 return !vshader_sampler_tokens[current_mapping];
3854 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3855 const DWORD *vshader_sampler_tokens =
3856 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3857 const DWORD *pshader_sampler_tokens = NULL;
3858 int start = GL_LIMITS(combined_samplers) - 1;
3859 int i;
3861 if (ps) {
3862 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3864 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3865 IWineD3DPixelShader_UpdateSamplers((IWineD3DPixelShader *)pshader);
3866 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3869 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3870 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3871 if (vshader_sampler_tokens[i]) {
3872 if (This->texUnitMap[vsampler_idx] != -1) {
3873 /* Already mapped somewhere */
3874 continue;
3877 while (start >= 0) {
3878 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3879 device_map_stage(This, vsampler_idx, start);
3880 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3882 --start;
3883 break;
3886 --start;
3892 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3893 BOOL vs = use_vs(This);
3894 BOOL ps = use_ps(This);
3896 * Rules are:
3897 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3898 * that would be really messy and require shader recompilation
3899 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3900 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3902 if (ps) {
3903 device_map_psamplers(This);
3904 } else {
3905 device_map_fixed_function_samplers(This);
3908 if (vs) {
3909 device_map_vsamplers(This, ps);
3913 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3915 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3916 This->updateStateBlock->pixelShader = pShader;
3917 This->updateStateBlock->changed.pixelShader = TRUE;
3919 /* Handle recording of state blocks */
3920 if (This->isRecordingState) {
3921 TRACE("Recording... not performing anything\n");
3924 if (This->isRecordingState) {
3925 TRACE("Recording... not performing anything\n");
3926 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3927 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3928 return WINED3D_OK;
3931 if(pShader == oldShader) {
3932 TRACE("App is setting the old pixel shader over, nothing to do\n");
3933 return WINED3D_OK;
3936 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3937 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3939 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3940 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3942 return WINED3D_OK;
3945 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3948 if (NULL == ppShader) {
3949 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3950 return WINED3DERR_INVALIDCALL;
3953 *ppShader = This->stateBlock->pixelShader;
3954 if (NULL != *ppShader) {
3955 IWineD3DPixelShader_AddRef(*ppShader);
3957 TRACE("(%p) : returning %p\n", This, *ppShader);
3958 return WINED3D_OK;
3961 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3962 IWineD3DDevice *iface,
3963 UINT start,
3964 CONST BOOL *srcData,
3965 UINT count) {
3967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3968 int i, cnt = min(count, MAX_CONST_B - start);
3970 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3971 iface, srcData, start, count);
3973 if (srcData == NULL || cnt < 0)
3974 return WINED3DERR_INVALIDCALL;
3976 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3977 for (i = 0; i < cnt; i++)
3978 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3980 for (i = start; i < cnt + start; ++i) {
3981 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3984 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3986 return WINED3D_OK;
3989 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3990 IWineD3DDevice *iface,
3991 UINT start,
3992 BOOL *dstData,
3993 UINT count) {
3995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3996 int cnt = min(count, MAX_CONST_B - start);
3998 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3999 iface, dstData, start, count);
4001 if (dstData == NULL || cnt < 0)
4002 return WINED3DERR_INVALIDCALL;
4004 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4005 return WINED3D_OK;
4008 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4009 IWineD3DDevice *iface,
4010 UINT start,
4011 CONST int *srcData,
4012 UINT count) {
4014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4015 int i, cnt = min(count, MAX_CONST_I - start);
4017 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4018 iface, srcData, start, count);
4020 if (srcData == NULL || cnt < 0)
4021 return WINED3DERR_INVALIDCALL;
4023 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4024 for (i = 0; i < cnt; i++)
4025 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4026 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4028 for (i = start; i < cnt + start; ++i) {
4029 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4032 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4034 return WINED3D_OK;
4037 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4038 IWineD3DDevice *iface,
4039 UINT start,
4040 int *dstData,
4041 UINT count) {
4043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4044 int cnt = min(count, MAX_CONST_I - start);
4046 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4047 iface, dstData, start, count);
4049 if (dstData == NULL || cnt < 0)
4050 return WINED3DERR_INVALIDCALL;
4052 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4053 return WINED3D_OK;
4056 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4057 IWineD3DDevice *iface,
4058 UINT start,
4059 CONST float *srcData,
4060 UINT count) {
4062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4063 UINT i;
4065 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4066 iface, srcData, start, count);
4068 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4069 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4070 return WINED3DERR_INVALIDCALL;
4072 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4073 if(TRACE_ON(d3d)) {
4074 for (i = 0; i < count; i++)
4075 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4076 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4079 for (i = start; i < count + start; ++i) {
4080 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
4081 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
4082 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
4083 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
4084 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
4086 ptr->idx[ptr->count++] = i;
4087 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4091 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4093 return WINED3D_OK;
4096 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4097 IWineD3DDevice *iface,
4098 UINT start,
4099 CONST float *srcData,
4100 UINT count) {
4102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4103 UINT i;
4105 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4106 iface, srcData, start, count);
4108 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4109 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4110 return WINED3DERR_INVALIDCALL;
4112 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4113 if(TRACE_ON(d3d)) {
4114 for (i = 0; i < count; i++)
4115 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4116 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4119 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4120 * context. On a context switch the old context will be fully dirtified
4122 memset(This->activeContext->pshader_const_dirty + start, 1,
4123 sizeof(*This->activeContext->pshader_const_dirty) * count);
4124 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count+1);
4126 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4128 return WINED3D_OK;
4131 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4132 IWineD3DDevice *iface,
4133 UINT start,
4134 float *dstData,
4135 UINT count) {
4137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4138 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4140 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4141 iface, dstData, start, count);
4143 if (dstData == NULL || cnt < 0)
4144 return WINED3DERR_INVALIDCALL;
4146 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4147 return WINED3D_OK;
4150 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4151 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4152 const WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags)
4154 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4155 unsigned int i;
4156 DWORD DestFVF = dest->fvf;
4157 WINED3DVIEWPORT vp;
4158 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4159 BOOL doClip;
4160 DWORD numTextures;
4162 if (lpStrideData->u.s.normal.lpData) {
4163 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4166 if (lpStrideData->u.s.position.lpData == NULL) {
4167 ERR("Source has no position mask\n");
4168 return WINED3DERR_INVALIDCALL;
4171 /* We might access VBOs from this code, so hold the lock */
4172 ENTER_GL();
4174 if (dest->resource.allocatedMemory == NULL) {
4175 /* This may happen if we do direct locking into a vbo. Unlikely,
4176 * but theoretically possible(ddraw processvertices test)
4178 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4179 if(!dest->resource.allocatedMemory) {
4180 LEAVE_GL();
4181 ERR("Out of memory\n");
4182 return E_OUTOFMEMORY;
4184 if(dest->vbo) {
4185 const void *src;
4186 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4187 checkGLcall("glBindBufferARB");
4188 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4189 if(src) {
4190 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4192 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4193 checkGLcall("glUnmapBufferARB");
4197 /* Get a pointer into the destination vbo(create one if none exists) and
4198 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4200 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4201 dest->Flags |= VBFLAG_CREATEVBO;
4202 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4205 if(dest->vbo) {
4206 unsigned char extrabytes = 0;
4207 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4208 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4209 * this may write 4 extra bytes beyond the area that should be written
4211 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4212 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4213 if(!dest_conv_addr) {
4214 ERR("Out of memory\n");
4215 /* Continue without storing converted vertices */
4217 dest_conv = dest_conv_addr;
4220 /* Should I clip?
4221 * a) WINED3DRS_CLIPPING is enabled
4222 * b) WINED3DVOP_CLIP is passed
4224 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4225 static BOOL warned = FALSE;
4227 * The clipping code is not quite correct. Some things need
4228 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4229 * so disable clipping for now.
4230 * (The graphics in Half-Life are broken, and my processvertices
4231 * test crashes with IDirect3DDevice3)
4232 doClip = TRUE;
4234 doClip = FALSE;
4235 if(!warned) {
4236 warned = TRUE;
4237 FIXME("Clipping is broken and disabled for now\n");
4239 } else doClip = FALSE;
4240 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4242 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4243 WINED3DTS_VIEW,
4244 &view_mat);
4245 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4246 WINED3DTS_PROJECTION,
4247 &proj_mat);
4248 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4249 WINED3DTS_WORLDMATRIX(0),
4250 &world_mat);
4252 TRACE("View mat:\n");
4253 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);
4254 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);
4255 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);
4256 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);
4258 TRACE("Proj mat:\n");
4259 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);
4260 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);
4261 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);
4262 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);
4264 TRACE("World mat:\n");
4265 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);
4266 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);
4267 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);
4268 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);
4270 /* Get the viewport */
4271 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4272 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4273 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4275 multiply_matrix(&mat,&view_mat,&world_mat);
4276 multiply_matrix(&mat,&proj_mat,&mat);
4278 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4280 for (i = 0; i < dwCount; i+= 1) {
4281 unsigned int tex_index;
4283 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4284 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4285 /* The position first */
4286 const float *p =
4287 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4288 float x, y, z, rhw;
4289 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4291 /* Multiplication with world, view and projection matrix */
4292 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);
4293 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);
4294 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);
4295 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);
4297 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4299 /* WARNING: The following things are taken from d3d7 and were not yet checked
4300 * against d3d8 or d3d9!
4303 /* Clipping conditions: From msdn
4305 * A vertex is clipped if it does not match the following requirements
4306 * -rhw < x <= rhw
4307 * -rhw < y <= rhw
4308 * 0 < z <= rhw
4309 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4311 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4312 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4316 if( !doClip ||
4317 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4318 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4319 ( rhw > eps ) ) ) {
4321 /* "Normal" viewport transformation (not clipped)
4322 * 1) The values are divided by rhw
4323 * 2) The y axis is negative, so multiply it with -1
4324 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4325 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4326 * 4) Multiply x with Width/2 and add Width/2
4327 * 5) The same for the height
4328 * 6) Add the viewpoint X and Y to the 2D coordinates and
4329 * The minimum Z value to z
4330 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4332 * Well, basically it's simply a linear transformation into viewport
4333 * coordinates
4336 x /= rhw;
4337 y /= rhw;
4338 z /= rhw;
4340 y *= -1;
4342 x *= vp.Width / 2;
4343 y *= vp.Height / 2;
4344 z *= vp.MaxZ - vp.MinZ;
4346 x += vp.Width / 2 + vp.X;
4347 y += vp.Height / 2 + vp.Y;
4348 z += vp.MinZ;
4350 rhw = 1 / rhw;
4351 } else {
4352 /* That vertex got clipped
4353 * Contrary to OpenGL it is not dropped completely, it just
4354 * undergoes a different calculation.
4356 TRACE("Vertex got clipped\n");
4357 x += rhw;
4358 y += rhw;
4360 x /= 2;
4361 y /= 2;
4363 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4364 * outside of the main vertex buffer memory. That needs some more
4365 * investigation...
4369 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4372 ( (float *) dest_ptr)[0] = x;
4373 ( (float *) dest_ptr)[1] = y;
4374 ( (float *) dest_ptr)[2] = z;
4375 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4377 dest_ptr += 3 * sizeof(float);
4379 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4380 dest_ptr += sizeof(float);
4383 if(dest_conv) {
4384 float w = 1 / rhw;
4385 ( (float *) dest_conv)[0] = x * w;
4386 ( (float *) dest_conv)[1] = y * w;
4387 ( (float *) dest_conv)[2] = z * w;
4388 ( (float *) dest_conv)[3] = w;
4390 dest_conv += 3 * sizeof(float);
4392 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4393 dest_conv += sizeof(float);
4397 if (DestFVF & WINED3DFVF_PSIZE) {
4398 dest_ptr += sizeof(DWORD);
4399 if(dest_conv) dest_conv += sizeof(DWORD);
4401 if (DestFVF & WINED3DFVF_NORMAL) {
4402 const float *normal =
4403 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4404 /* AFAIK this should go into the lighting information */
4405 FIXME("Didn't expect the destination to have a normal\n");
4406 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4407 if(dest_conv) {
4408 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4412 if (DestFVF & WINED3DFVF_DIFFUSE) {
4413 const DWORD *color_d =
4414 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4415 if(!color_d) {
4416 static BOOL warned = FALSE;
4418 if(!warned) {
4419 ERR("No diffuse color in source, but destination has one\n");
4420 warned = TRUE;
4423 *( (DWORD *) dest_ptr) = 0xffffffff;
4424 dest_ptr += sizeof(DWORD);
4426 if(dest_conv) {
4427 *( (DWORD *) dest_conv) = 0xffffffff;
4428 dest_conv += sizeof(DWORD);
4431 else {
4432 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4433 if(dest_conv) {
4434 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4435 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4436 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4437 dest_conv += sizeof(DWORD);
4442 if (DestFVF & WINED3DFVF_SPECULAR) {
4443 /* What's the color value in the feedback buffer? */
4444 const DWORD *color_s =
4445 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4446 if(!color_s) {
4447 static BOOL warned = FALSE;
4449 if(!warned) {
4450 ERR("No specular color in source, but destination has one\n");
4451 warned = TRUE;
4454 *( (DWORD *) dest_ptr) = 0xFF000000;
4455 dest_ptr += sizeof(DWORD);
4457 if(dest_conv) {
4458 *( (DWORD *) dest_conv) = 0xFF000000;
4459 dest_conv += sizeof(DWORD);
4462 else {
4463 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4464 if(dest_conv) {
4465 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4466 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4467 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4468 dest_conv += sizeof(DWORD);
4473 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4474 const float *tex_coord =
4475 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4476 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4477 if(!tex_coord) {
4478 ERR("No source texture, but destination requests one\n");
4479 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4480 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4482 else {
4483 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4484 if(dest_conv) {
4485 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4491 if(dest_conv) {
4492 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4493 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4494 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4495 dwCount * get_flexible_vertex_size(DestFVF),
4496 dest_conv_addr));
4497 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4498 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4501 LEAVE_GL();
4503 return WINED3D_OK;
4505 #undef copy_and_next
4507 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4509 WineDirect3DVertexStridedData strided;
4510 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4511 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4513 if(pVertexDecl) {
4514 ERR("Output vertex declaration not implemented yet\n");
4517 /* Need any context to write to the vbo. */
4518 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4520 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4521 * control the streamIsUP flag, thus restore it afterwards.
4523 This->stateBlock->streamIsUP = FALSE;
4524 memset(&strided, 0, sizeof(strided));
4525 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4526 This->stateBlock->streamIsUP = streamWasUP;
4528 if(vbo || SrcStartIndex) {
4529 unsigned int i;
4530 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4531 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4533 * Also get the start index in, but only loop over all elements if there's something to add at all.
4535 #define FIXSRC(type) \
4536 if(strided.u.s.type.VBO) { \
4537 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4538 strided.u.s.type.VBO = 0; \
4539 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4540 ENTER_GL(); \
4541 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4542 vb->vbo = 0; \
4543 LEAVE_GL(); \
4545 if(strided.u.s.type.lpData) { \
4546 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4548 FIXSRC(position);
4549 FIXSRC(blendWeights);
4550 FIXSRC(blendMatrixIndices);
4551 FIXSRC(normal);
4552 FIXSRC(pSize);
4553 FIXSRC(diffuse);
4554 FIXSRC(specular);
4555 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4556 FIXSRC(texCoords[i]);
4558 FIXSRC(position2);
4559 FIXSRC(normal2);
4560 FIXSRC(tangent);
4561 FIXSRC(binormal);
4562 FIXSRC(tessFactor);
4563 FIXSRC(fog);
4564 FIXSRC(depth);
4565 FIXSRC(sample);
4566 #undef FIXSRC
4569 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4572 /*****
4573 * Get / Set Texture Stage States
4574 * TODO: Verify against dx9 definitions
4575 *****/
4576 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4578 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4580 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4582 if (Stage >= MAX_TEXTURES) {
4583 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4584 return WINED3D_OK;
4587 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4588 This->updateStateBlock->textureState[Stage][Type] = Value;
4590 if (This->isRecordingState) {
4591 TRACE("Recording... not performing anything\n");
4592 return WINED3D_OK;
4595 /* Checked after the assignments to allow proper stateblock recording */
4596 if(oldValue == Value) {
4597 TRACE("App is setting the old value over, nothing to do\n");
4598 return WINED3D_OK;
4601 if(Stage > This->stateBlock->lowest_disabled_stage &&
4602 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4603 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4604 * Changes in other states are important on disabled stages too
4606 return WINED3D_OK;
4609 if(Type == WINED3DTSS_COLOROP) {
4610 int i;
4612 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4613 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4614 * they have to be disabled
4616 * The current stage is dirtified below.
4618 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4619 TRACE("Additionally dirtifying stage %d\n", i);
4620 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4622 This->stateBlock->lowest_disabled_stage = Stage;
4623 TRACE("New lowest disabled: %d\n", Stage);
4624 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4625 /* Previously disabled stage enabled. Stages above it may need enabling
4626 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4627 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4629 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4632 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4633 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4634 break;
4636 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4637 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4639 This->stateBlock->lowest_disabled_stage = i;
4640 TRACE("New lowest disabled: %d\n", i);
4644 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4646 return WINED3D_OK;
4649 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4651 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4652 *pValue = This->updateStateBlock->textureState[Stage][Type];
4653 return WINED3D_OK;
4656 /*****
4657 * Get / Set Texture
4658 *****/
4659 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4661 IWineD3DBaseTexture *oldTexture;
4663 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4665 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4666 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4669 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4670 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4671 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4674 oldTexture = This->updateStateBlock->textures[Stage];
4676 if(pTexture != NULL) {
4677 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4679 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4680 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4681 return WINED3DERR_INVALIDCALL;
4683 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4686 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4687 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4689 This->updateStateBlock->changed.textures[Stage] = TRUE;
4690 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4691 This->updateStateBlock->textures[Stage] = pTexture;
4693 /* Handle recording of state blocks */
4694 if (This->isRecordingState) {
4695 TRACE("Recording... not performing anything\n");
4696 return WINED3D_OK;
4699 if(oldTexture == pTexture) {
4700 TRACE("App is setting the same texture again, nothing to do\n");
4701 return WINED3D_OK;
4704 /** NOTE: MSDN says that setTexture increases the reference count,
4705 * and that the application must set the texture back to null (or have a leaky application),
4706 * This means we should pass the refcount up to the parent
4707 *******************************/
4708 if (NULL != This->updateStateBlock->textures[Stage]) {
4709 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4710 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4712 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4713 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4714 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4715 * so the COLOROP and ALPHAOP have to be dirtified.
4717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4718 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4720 if(bindCount == 1) {
4721 new->baseTexture.sampler = Stage;
4723 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4727 if (NULL != oldTexture) {
4728 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4729 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4731 IWineD3DBaseTexture_Release(oldTexture);
4732 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4733 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4734 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4737 if(bindCount && old->baseTexture.sampler == Stage) {
4738 int i;
4739 /* Have to do a search for the other sampler(s) where the texture is bound to
4740 * Shouldn't happen as long as apps bind a texture only to one stage
4742 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4743 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4744 if(This->updateStateBlock->textures[i] == oldTexture) {
4745 old->baseTexture.sampler = i;
4746 break;
4752 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4754 return WINED3D_OK;
4757 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4760 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4762 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4763 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4766 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4767 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4768 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4771 *ppTexture=This->stateBlock->textures[Stage];
4772 if (*ppTexture)
4773 IWineD3DBaseTexture_AddRef(*ppTexture);
4775 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4777 return WINED3D_OK;
4780 /*****
4781 * Get Back Buffer
4782 *****/
4783 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4784 IWineD3DSurface **ppBackBuffer) {
4785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4786 IWineD3DSwapChain *swapChain;
4787 HRESULT hr;
4789 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4791 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4792 if (hr == WINED3D_OK) {
4793 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4794 IWineD3DSwapChain_Release(swapChain);
4795 } else {
4796 *ppBackBuffer = NULL;
4798 return hr;
4801 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4803 WARN("(%p) : stub, calling idirect3d for now\n", This);
4804 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4807 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4809 IWineD3DSwapChain *swapChain;
4810 HRESULT hr;
4812 if(iSwapChain > 0) {
4813 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4814 if (hr == WINED3D_OK) {
4815 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4816 IWineD3DSwapChain_Release(swapChain);
4817 } else {
4818 FIXME("(%p) Error getting display mode\n", This);
4820 } else {
4821 /* Don't read the real display mode,
4822 but return the stored mode instead. X11 can't change the color
4823 depth, and some apps are pretty angry if they SetDisplayMode from
4824 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4826 Also don't relay to the swapchain because with ddraw it's possible
4827 that there isn't a swapchain at all */
4828 pMode->Width = This->ddraw_width;
4829 pMode->Height = This->ddraw_height;
4830 pMode->Format = This->ddraw_format;
4831 pMode->RefreshRate = 0;
4832 hr = WINED3D_OK;
4835 return hr;
4838 /*****
4839 * Stateblock related functions
4840 *****/
4842 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4844 IWineD3DStateBlockImpl *object;
4845 HRESULT temp_result;
4846 int i;
4848 TRACE("(%p)\n", This);
4850 if (This->isRecordingState) {
4851 return WINED3DERR_INVALIDCALL;
4854 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4855 if (NULL == object ) {
4856 FIXME("(%p)Error allocating memory for stateblock\n", This);
4857 return E_OUTOFMEMORY;
4859 TRACE("(%p) created object %p\n", This, object);
4860 object->wineD3DDevice= This;
4861 /** FIXME: object->parent = parent; **/
4862 object->parent = NULL;
4863 object->blockType = WINED3DSBT_RECORDED;
4864 object->ref = 1;
4865 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4867 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4868 list_init(&object->lightMap[i]);
4871 temp_result = allocate_shader_constants(object);
4872 if (WINED3D_OK != temp_result)
4873 return temp_result;
4875 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4876 This->updateStateBlock = object;
4877 This->isRecordingState = TRUE;
4879 TRACE("(%p) recording stateblock %p\n",This , object);
4880 return WINED3D_OK;
4883 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4885 unsigned int i, j;
4886 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4888 if (!This->isRecordingState) {
4889 FIXME("(%p) not recording! returning error\n", This);
4890 *ppStateBlock = NULL;
4891 return WINED3DERR_INVALIDCALL;
4894 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4895 if(object->changed.renderState[i]) {
4896 object->contained_render_states[object->num_contained_render_states] = i;
4897 object->num_contained_render_states++;
4900 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4901 if(object->changed.transform[i]) {
4902 object->contained_transform_states[object->num_contained_transform_states] = i;
4903 object->num_contained_transform_states++;
4906 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4907 if(object->changed.vertexShaderConstantsF[i]) {
4908 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4909 object->num_contained_vs_consts_f++;
4912 for(i = 0; i < MAX_CONST_I; i++) {
4913 if (object->changed.vertexShaderConstantsI & (1 << i))
4915 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4916 object->num_contained_vs_consts_i++;
4919 for(i = 0; i < MAX_CONST_B; i++) {
4920 if (object->changed.vertexShaderConstantsB & (1 << i))
4922 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4923 object->num_contained_vs_consts_b++;
4926 for(i = 0; i < MAX_CONST_I; i++) {
4927 if (object->changed.pixelShaderConstantsI & (1 << i))
4929 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4930 object->num_contained_ps_consts_i++;
4933 for(i = 0; i < MAX_CONST_B; i++) {
4934 if (object->changed.pixelShaderConstantsB & (1 << i))
4936 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4937 object->num_contained_ps_consts_b++;
4940 for(i = 0; i < MAX_TEXTURES; i++) {
4941 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4942 if(object->changed.textureState[i][j]) {
4943 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4944 object->contained_tss_states[object->num_contained_tss_states].state = j;
4945 object->num_contained_tss_states++;
4949 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4950 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4951 if(object->changed.samplerState[i][j]) {
4952 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4953 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4954 object->num_contained_sampler_states++;
4959 *ppStateBlock = (IWineD3DStateBlock*) object;
4960 This->isRecordingState = FALSE;
4961 This->updateStateBlock = This->stateBlock;
4962 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4963 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4964 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4965 return WINED3D_OK;
4968 /*****
4969 * Scene related functions
4970 *****/
4971 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4972 /* At the moment we have no need for any functionality at the beginning
4973 of a scene */
4974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4975 TRACE("(%p)\n", This);
4977 if(This->inScene) {
4978 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4979 return WINED3DERR_INVALIDCALL;
4981 This->inScene = TRUE;
4982 return WINED3D_OK;
4985 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4987 TRACE("(%p)\n", This);
4989 if(!This->inScene) {
4990 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4991 return WINED3DERR_INVALIDCALL;
4994 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4995 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4996 glFlush();
4997 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4998 * fails
5001 This->inScene = FALSE;
5002 return WINED3D_OK;
5005 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5006 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5007 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5009 IWineD3DSwapChain *swapChain = NULL;
5010 int i;
5011 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5013 TRACE("(%p) Presenting the frame\n", This);
5015 for(i = 0 ; i < swapchains ; i ++) {
5017 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5018 TRACE("presentinng chain %d, %p\n", i, swapChain);
5019 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5020 IWineD3DSwapChain_Release(swapChain);
5023 return WINED3D_OK;
5026 /* Not called from the VTable (internal subroutine) */
5027 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5028 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5029 float Z, DWORD Stencil) {
5030 GLbitfield glMask = 0;
5031 unsigned int i;
5032 WINED3DRECT curRect;
5033 RECT vp_rect;
5034 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5035 UINT drawable_width, drawable_height;
5036 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5037 IWineD3DSwapChainImpl *swapchain = NULL;
5039 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5040 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5041 * for the cleared parts, and the untouched parts.
5043 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5044 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5045 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5046 * checking all this if the dest surface is in the drawable anyway.
5048 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5049 while(1) {
5050 if(vp->X != 0 || vp->Y != 0 ||
5051 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5052 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5053 break;
5055 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5056 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5057 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5058 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5059 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5060 break;
5062 if(Count > 0 && pRects && (
5063 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5064 pRects[0].x2 < target->currentDesc.Width ||
5065 pRects[0].y2 < target->currentDesc.Height)) {
5066 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5067 break;
5069 break;
5073 target->get_drawable_size(target, &drawable_width, &drawable_height);
5075 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5076 ENTER_GL();
5078 /* Only set the values up once, as they are not changing */
5079 if (Flags & WINED3DCLEAR_STENCIL) {
5080 glClearStencil(Stencil);
5081 checkGLcall("glClearStencil");
5082 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5083 glStencilMask(0xFFFFFFFF);
5086 if (Flags & WINED3DCLEAR_ZBUFFER) {
5087 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5088 glDepthMask(GL_TRUE);
5089 glClearDepth(Z);
5090 checkGLcall("glClearDepth");
5091 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5092 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5094 if (vp->X != 0 || vp->Y != 0 ||
5095 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5096 surface_load_ds_location(This->stencilBufferTarget, location);
5098 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5099 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5100 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5101 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5102 surface_load_ds_location(This->stencilBufferTarget, location);
5104 else if (Count > 0 && pRects && (
5105 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5106 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5107 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5108 surface_load_ds_location(This->stencilBufferTarget, location);
5112 if (Flags & WINED3DCLEAR_TARGET) {
5113 TRACE("Clearing screen with glClear to color %x\n", Color);
5114 glClearColor(D3DCOLOR_R(Color),
5115 D3DCOLOR_G(Color),
5116 D3DCOLOR_B(Color),
5117 D3DCOLOR_A(Color));
5118 checkGLcall("glClearColor");
5120 /* Clear ALL colors! */
5121 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5122 glMask = glMask | GL_COLOR_BUFFER_BIT;
5125 vp_rect.left = vp->X;
5126 vp_rect.top = vp->Y;
5127 vp_rect.right = vp->X + vp->Width;
5128 vp_rect.bottom = vp->Y + vp->Height;
5129 if (!(Count > 0 && pRects)) {
5130 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5131 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5133 if(This->render_offscreen) {
5134 glScissor(vp_rect.left, vp_rect.top,
5135 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5136 } else {
5137 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5138 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5140 checkGLcall("glScissor");
5141 glClear(glMask);
5142 checkGLcall("glClear");
5143 } else {
5144 /* Now process each rect in turn */
5145 for (i = 0; i < Count; i++) {
5146 /* Note gl uses lower left, width/height */
5147 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5148 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5149 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5151 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5152 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5153 curRect.x1, (target->currentDesc.Height - curRect.y2),
5154 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5156 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5157 * The rectangle is not cleared, no error is returned, but further rectanlges are
5158 * still cleared if they are valid
5160 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5161 TRACE("Rectangle with negative dimensions, ignoring\n");
5162 continue;
5165 if(This->render_offscreen) {
5166 glScissor(curRect.x1, curRect.y1,
5167 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5168 } else {
5169 glScissor(curRect.x1, drawable_height - curRect.y2,
5170 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5172 checkGLcall("glScissor");
5174 glClear(glMask);
5175 checkGLcall("glClear");
5179 /* Restore the old values (why..?) */
5180 if (Flags & WINED3DCLEAR_STENCIL) {
5181 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5183 if (Flags & WINED3DCLEAR_TARGET) {
5184 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5185 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5186 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5187 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5188 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5190 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5191 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5193 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5195 if (Flags & WINED3DCLEAR_ZBUFFER) {
5196 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5197 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5198 surface_modify_ds_location(This->stencilBufferTarget, location);
5201 LEAVE_GL();
5203 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5204 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5205 glFlush();
5207 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5210 return WINED3D_OK;
5213 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5214 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5216 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5218 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5219 Count, pRects, Flags, Color, Z, Stencil);
5221 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5222 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5223 /* TODO: What about depth stencil buffers without stencil bits? */
5224 return WINED3DERR_INVALIDCALL;
5227 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5230 /*****
5231 * Drawing functions
5232 *****/
5233 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5234 UINT PrimitiveCount) {
5236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5238 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5239 debug_d3dprimitivetype(PrimitiveType),
5240 StartVertex, PrimitiveCount);
5242 if(!This->stateBlock->vertexDecl) {
5243 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5244 return WINED3DERR_INVALIDCALL;
5247 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5248 if(This->stateBlock->streamIsUP) {
5249 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5250 This->stateBlock->streamIsUP = FALSE;
5253 if(This->stateBlock->loadBaseVertexIndex != 0) {
5254 This->stateBlock->loadBaseVertexIndex = 0;
5255 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5257 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5258 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5259 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5260 return WINED3D_OK;
5263 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5264 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5265 WINED3DPRIMITIVETYPE PrimitiveType,
5266 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5269 UINT idxStride = 2;
5270 IWineD3DIndexBuffer *pIB;
5271 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5272 GLuint vbo;
5274 pIB = This->stateBlock->pIndexData;
5275 if (!pIB) {
5276 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5277 * without an index buffer set. (The first time at least...)
5278 * D3D8 simply dies, but I doubt it can do much harm to return
5279 * D3DERR_INVALIDCALL there as well. */
5280 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5281 return WINED3DERR_INVALIDCALL;
5284 if(!This->stateBlock->vertexDecl) {
5285 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5286 return WINED3DERR_INVALIDCALL;
5289 if(This->stateBlock->streamIsUP) {
5290 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5291 This->stateBlock->streamIsUP = FALSE;
5293 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5295 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5296 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5297 minIndex, NumVertices, startIndex, primCount);
5299 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5300 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5301 idxStride = 2;
5302 } else {
5303 idxStride = 4;
5306 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5307 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5308 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5311 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5312 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5314 return WINED3D_OK;
5317 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5318 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5319 UINT VertexStreamZeroStride) {
5320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5321 IWineD3DVertexBuffer *vb;
5323 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5324 debug_d3dprimitivetype(PrimitiveType),
5325 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5327 if(!This->stateBlock->vertexDecl) {
5328 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5329 return WINED3DERR_INVALIDCALL;
5332 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5333 vb = This->stateBlock->streamSource[0];
5334 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5335 if(vb) IWineD3DVertexBuffer_Release(vb);
5336 This->stateBlock->streamOffset[0] = 0;
5337 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5338 This->stateBlock->streamIsUP = TRUE;
5339 This->stateBlock->loadBaseVertexIndex = 0;
5341 /* TODO: Only mark dirty if drawing from a different UP address */
5342 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5344 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5345 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5347 /* MSDN specifies stream zero settings must be set to NULL */
5348 This->stateBlock->streamStride[0] = 0;
5349 This->stateBlock->streamSource[0] = NULL;
5351 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5352 * the new stream sources or use UP drawing again
5354 return WINED3D_OK;
5357 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5358 UINT MinVertexIndex, UINT NumVertices,
5359 UINT PrimitiveCount, CONST void* pIndexData,
5360 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5361 UINT VertexStreamZeroStride) {
5362 int idxStride;
5363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5364 IWineD3DVertexBuffer *vb;
5365 IWineD3DIndexBuffer *ib;
5367 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5368 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5369 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5370 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5372 if(!This->stateBlock->vertexDecl) {
5373 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5374 return WINED3DERR_INVALIDCALL;
5377 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5378 idxStride = 2;
5379 } else {
5380 idxStride = 4;
5383 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5384 vb = This->stateBlock->streamSource[0];
5385 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5386 if(vb) IWineD3DVertexBuffer_Release(vb);
5387 This->stateBlock->streamIsUP = TRUE;
5388 This->stateBlock->streamOffset[0] = 0;
5389 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5391 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5392 This->stateBlock->baseVertexIndex = 0;
5393 This->stateBlock->loadBaseVertexIndex = 0;
5394 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5395 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5396 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5398 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5400 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5401 This->stateBlock->streamSource[0] = NULL;
5402 This->stateBlock->streamStride[0] = 0;
5403 ib = This->stateBlock->pIndexData;
5404 if(ib) {
5405 IWineD3DIndexBuffer_Release(ib);
5406 This->stateBlock->pIndexData = NULL;
5408 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5409 * SetStreamSource to specify a vertex buffer
5412 return WINED3D_OK;
5415 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5416 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5417 const WineDirect3DVertexStridedData *DrawPrimStrideData)
5419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5421 /* Mark the state dirty until we have nicer tracking
5422 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5423 * that value.
5425 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5426 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5427 This->stateBlock->baseVertexIndex = 0;
5428 This->up_strided = DrawPrimStrideData;
5429 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5430 This->up_strided = NULL;
5431 return WINED3D_OK;
5434 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5435 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5436 const WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, const void *pIndexData,
5437 WINED3DFORMAT IndexDataFormat)
5439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5440 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5442 /* Mark the state dirty until we have nicer tracking
5443 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5444 * that value.
5446 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5447 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5448 This->stateBlock->streamIsUP = TRUE;
5449 This->stateBlock->baseVertexIndex = 0;
5450 This->up_strided = DrawPrimStrideData;
5451 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5452 This->up_strided = NULL;
5453 return WINED3D_OK;
5456 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5457 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5458 * not callable by the app directly no parameter validation checks are needed here.
5460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5461 WINED3DLOCKED_BOX src;
5462 WINED3DLOCKED_BOX dst;
5463 HRESULT hr;
5464 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5466 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5467 * dirtification to improve loading performance.
5469 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5470 if(FAILED(hr)) return hr;
5471 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5472 if(FAILED(hr)) {
5473 IWineD3DVolume_UnlockBox(pSourceVolume);
5474 return hr;
5477 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5479 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5480 if(FAILED(hr)) {
5481 IWineD3DVolume_UnlockBox(pSourceVolume);
5482 } else {
5483 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5485 return hr;
5488 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5489 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5490 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5491 HRESULT hr = WINED3D_OK;
5492 WINED3DRESOURCETYPE sourceType;
5493 WINED3DRESOURCETYPE destinationType;
5494 int i ,levels;
5496 /* TODO: think about moving the code into IWineD3DBaseTexture */
5498 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5500 /* verify that the source and destination textures aren't NULL */
5501 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5502 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5503 This, pSourceTexture, pDestinationTexture);
5504 hr = WINED3DERR_INVALIDCALL;
5507 if (pSourceTexture == pDestinationTexture) {
5508 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5509 This, pSourceTexture, pDestinationTexture);
5510 hr = WINED3DERR_INVALIDCALL;
5512 /* Verify that the source and destination textures are the same type */
5513 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5514 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5516 if (sourceType != destinationType) {
5517 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5518 This);
5519 hr = WINED3DERR_INVALIDCALL;
5522 /* check that both textures have the identical numbers of levels */
5523 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5524 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5525 hr = WINED3DERR_INVALIDCALL;
5528 if (WINED3D_OK == hr) {
5530 /* Make sure that the destination texture is loaded */
5531 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5533 /* Update every surface level of the texture */
5534 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5536 switch (sourceType) {
5537 case WINED3DRTYPE_TEXTURE:
5539 IWineD3DSurface *srcSurface;
5540 IWineD3DSurface *destSurface;
5542 for (i = 0 ; i < levels ; ++i) {
5543 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5544 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5545 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5546 IWineD3DSurface_Release(srcSurface);
5547 IWineD3DSurface_Release(destSurface);
5548 if (WINED3D_OK != hr) {
5549 WARN("(%p) : Call to update surface failed\n", This);
5550 return hr;
5554 break;
5555 case WINED3DRTYPE_CUBETEXTURE:
5557 IWineD3DSurface *srcSurface;
5558 IWineD3DSurface *destSurface;
5559 WINED3DCUBEMAP_FACES faceType;
5561 for (i = 0 ; i < levels ; ++i) {
5562 /* Update each cube face */
5563 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5564 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5565 if (WINED3D_OK != hr) {
5566 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5567 } else {
5568 TRACE("Got srcSurface %p\n", srcSurface);
5570 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5571 if (WINED3D_OK != hr) {
5572 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5573 } else {
5574 TRACE("Got desrSurface %p\n", destSurface);
5576 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5577 IWineD3DSurface_Release(srcSurface);
5578 IWineD3DSurface_Release(destSurface);
5579 if (WINED3D_OK != hr) {
5580 WARN("(%p) : Call to update surface failed\n", This);
5581 return hr;
5586 break;
5588 case WINED3DRTYPE_VOLUMETEXTURE:
5590 IWineD3DVolume *srcVolume = NULL;
5591 IWineD3DVolume *destVolume = NULL;
5593 for (i = 0 ; i < levels ; ++i) {
5594 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5595 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5596 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5597 IWineD3DVolume_Release(srcVolume);
5598 IWineD3DVolume_Release(destVolume);
5599 if (WINED3D_OK != hr) {
5600 WARN("(%p) : Call to update volume failed\n", This);
5601 return hr;
5605 break;
5607 default:
5608 FIXME("(%p) : Unsupported source and destination type\n", This);
5609 hr = WINED3DERR_INVALIDCALL;
5613 return hr;
5616 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5617 IWineD3DSwapChain *swapChain;
5618 HRESULT hr;
5619 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5620 if(hr == WINED3D_OK) {
5621 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5622 IWineD3DSwapChain_Release(swapChain);
5624 return hr;
5627 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5629 IWineD3DBaseTextureImpl *texture;
5630 const struct GlPixelFormatDesc *gl_info;
5631 DWORD i;
5633 TRACE("(%p) : %p\n", This, pNumPasses);
5635 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5636 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5637 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5638 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5640 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5641 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5642 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5645 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5646 if(!texture) continue;
5647 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5648 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5650 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5651 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5652 return E_FAIL;
5654 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5655 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5656 return E_FAIL;
5658 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5659 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5660 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5661 return E_FAIL;
5665 /* return a sensible default */
5666 *pNumPasses = 1;
5668 TRACE("returning D3D_OK\n");
5669 return WINED3D_OK;
5672 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5674 int i;
5676 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5677 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5678 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5679 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5684 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5686 int j;
5687 UINT NewSize;
5688 PALETTEENTRY **palettes;
5690 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5692 if (PaletteNumber >= MAX_PALETTES) {
5693 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5694 return WINED3DERR_INVALIDCALL;
5697 if (PaletteNumber >= This->NumberOfPalettes) {
5698 NewSize = This->NumberOfPalettes;
5699 do {
5700 NewSize *= 2;
5701 } while(PaletteNumber >= NewSize);
5702 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5703 if (!palettes) {
5704 ERR("Out of memory!\n");
5705 return E_OUTOFMEMORY;
5707 This->palettes = palettes;
5708 This->NumberOfPalettes = NewSize;
5711 if (!This->palettes[PaletteNumber]) {
5712 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5713 if (!This->palettes[PaletteNumber]) {
5714 ERR("Out of memory!\n");
5715 return E_OUTOFMEMORY;
5719 for (j = 0; j < 256; ++j) {
5720 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5721 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5722 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5723 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5725 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5726 TRACE("(%p) : returning\n", This);
5727 return WINED3D_OK;
5730 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5732 int j;
5733 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5734 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5735 /* What happens in such situation isn't documented; Native seems to silently abort
5736 on such conditions. Return Invalid Call. */
5737 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5738 return WINED3DERR_INVALIDCALL;
5740 for (j = 0; j < 256; ++j) {
5741 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5742 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5743 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5744 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5746 TRACE("(%p) : returning\n", This);
5747 return WINED3D_OK;
5750 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5752 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5753 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5754 (tested with reference rasterizer). Return Invalid Call. */
5755 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5756 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5757 return WINED3DERR_INVALIDCALL;
5759 /*TODO: stateblocks */
5760 if (This->currentPalette != PaletteNumber) {
5761 This->currentPalette = PaletteNumber;
5762 dirtify_p8_texture_samplers(This);
5764 TRACE("(%p) : returning\n", This);
5765 return WINED3D_OK;
5768 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5770 if (PaletteNumber == NULL) {
5771 WARN("(%p) : returning Invalid Call\n", This);
5772 return WINED3DERR_INVALIDCALL;
5774 /*TODO: stateblocks */
5775 *PaletteNumber = This->currentPalette;
5776 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5777 return WINED3D_OK;
5780 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5782 static BOOL warned;
5783 if (!warned)
5785 FIXME("(%p) : stub\n", This);
5786 warned = TRUE;
5789 This->softwareVertexProcessing = bSoftware;
5790 return WINED3D_OK;
5794 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5796 static BOOL warned;
5797 if (!warned)
5799 FIXME("(%p) : stub\n", This);
5800 warned = TRUE;
5802 return This->softwareVertexProcessing;
5806 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5808 IWineD3DSwapChain *swapChain;
5809 HRESULT hr;
5811 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5813 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5814 if(hr == WINED3D_OK){
5815 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5816 IWineD3DSwapChain_Release(swapChain);
5817 }else{
5818 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5820 return hr;
5824 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5825 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5826 static BOOL warned;
5827 if(nSegments != 0.0f) {
5828 if (!warned)
5830 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5831 warned = TRUE;
5834 return WINED3D_OK;
5837 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5839 static BOOL warned;
5840 if (!warned)
5842 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5843 warned = TRUE;
5845 return 0.0f;
5848 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5850 /** TODO: remove casts to IWineD3DSurfaceImpl
5851 * NOTE: move code to surface to accomplish this
5852 ****************************************/
5853 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5854 int srcWidth, srcHeight;
5855 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5856 WINED3DFORMAT destFormat, srcFormat;
5857 UINT destSize;
5858 int srcLeft, destLeft, destTop;
5859 WINED3DPOOL srcPool, destPool;
5860 int offset = 0;
5861 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5862 glDescriptor *glDescription = NULL;
5863 GLenum dummy;
5864 int sampler;
5865 int bpp;
5866 CONVERT_TYPES convert = NO_CONVERSION;
5868 WINED3DSURFACE_DESC winedesc;
5870 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5871 memset(&winedesc, 0, sizeof(winedesc));
5872 winedesc.Width = &srcSurfaceWidth;
5873 winedesc.Height = &srcSurfaceHeight;
5874 winedesc.Pool = &srcPool;
5875 winedesc.Format = &srcFormat;
5877 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5879 winedesc.Width = &destSurfaceWidth;
5880 winedesc.Height = &destSurfaceHeight;
5881 winedesc.Pool = &destPool;
5882 winedesc.Format = &destFormat;
5883 winedesc.Size = &destSize;
5885 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5887 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5888 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5889 return WINED3DERR_INVALIDCALL;
5892 /* This call loads the opengl surface directly, instead of copying the surface to the
5893 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5894 * copy in sysmem and use regular surface loading.
5896 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5897 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5898 if(convert != NO_CONVERSION) {
5899 return IWineD3DSurface_BltFast(pDestinationSurface,
5900 pDestPoint ? pDestPoint->x : 0,
5901 pDestPoint ? pDestPoint->y : 0,
5902 pSourceSurface, pSourceRect, 0);
5905 if (destFormat == WINED3DFMT_UNKNOWN) {
5906 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5907 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5909 /* Get the update surface description */
5910 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5913 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5915 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5916 ENTER_GL();
5917 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5918 checkGLcall("glActiveTextureARB");
5919 LEAVE_GL();
5922 /* Make sure the surface is loaded and up to date */
5923 IWineD3DSurface_PreLoad(pDestinationSurface);
5924 IWineD3DSurface_BindTexture(pDestinationSurface);
5926 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5928 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5929 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5930 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5931 srcLeft = pSourceRect ? pSourceRect->left : 0;
5932 destLeft = pDestPoint ? pDestPoint->x : 0;
5933 destTop = pDestPoint ? pDestPoint->y : 0;
5936 /* This function doesn't support compressed textures
5937 the pitch is just bytesPerPixel * width */
5938 if(srcWidth != srcSurfaceWidth || srcLeft ){
5939 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5940 offset += srcLeft * pSrcSurface->bytesPerPixel;
5941 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5943 /* TODO DXT formats */
5945 if(pSourceRect != NULL && pSourceRect->top != 0){
5946 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5948 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5949 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat,
5950 glDescription->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5952 /* Sanity check */
5953 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5955 /* need to lock the surface to get the data */
5956 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5959 ENTER_GL();
5961 /* TODO: Cube and volume support */
5962 if(rowoffset != 0){
5963 /* not a whole row so we have to do it a line at a time */
5964 int j;
5966 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5967 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5969 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5971 glTexSubImage2D(glDescription->target
5972 ,glDescription->level
5973 ,destLeft
5975 ,srcWidth
5977 ,glDescription->glFormat
5978 ,glDescription->glType
5979 ,data /* could be quicker using */
5981 data += rowoffset;
5984 } else { /* Full width, so just write out the whole texture */
5985 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5987 if (WINED3DFMT_DXT1 == destFormat ||
5988 WINED3DFMT_DXT2 == destFormat ||
5989 WINED3DFMT_DXT3 == destFormat ||
5990 WINED3DFMT_DXT4 == destFormat ||
5991 WINED3DFMT_DXT5 == destFormat) {
5992 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5993 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5994 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5995 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5996 } if (destFormat != srcFormat) {
5997 FIXME("Updating mixed format compressed texture is not curretly support\n");
5998 } else {
5999 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6000 glDescription->glFormatInternal, srcWidth, srcHeight, 0, destSize, data));
6002 } else {
6003 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6007 } else {
6008 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6009 srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, data);
6012 checkGLcall("glTexSubImage2D");
6014 LEAVE_GL();
6016 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6017 sampler = This->rev_tex_unit_map[0];
6018 if (sampler != -1) {
6019 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6022 return WINED3D_OK;
6025 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6027 struct WineD3DRectPatch *patch;
6028 unsigned int i;
6029 struct list *e;
6030 BOOL found;
6031 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6033 if(!(Handle || pRectPatchInfo)) {
6034 /* TODO: Write a test for the return value, thus the FIXME */
6035 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6036 return WINED3DERR_INVALIDCALL;
6039 if(Handle) {
6040 i = PATCHMAP_HASHFUNC(Handle);
6041 found = FALSE;
6042 LIST_FOR_EACH(e, &This->patches[i]) {
6043 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6044 if(patch->Handle == Handle) {
6045 found = TRUE;
6046 break;
6050 if(!found) {
6051 TRACE("Patch does not exist. Creating a new one\n");
6052 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6053 patch->Handle = Handle;
6054 list_add_head(&This->patches[i], &patch->entry);
6055 } else {
6056 TRACE("Found existing patch %p\n", patch);
6058 } else {
6059 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6060 * attributes we have to tesselate, read back, and draw. This needs a patch
6061 * management structure instance. Create one.
6063 * A possible improvement is to check if a vertex shader is used, and if not directly
6064 * draw the patch.
6066 FIXME("Drawing an uncached patch. This is slow\n");
6067 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6070 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6071 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6072 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6073 HRESULT hr;
6074 TRACE("Tesselation density or patch info changed, retesselating\n");
6076 if(pRectPatchInfo) {
6077 patch->RectPatchInfo = *pRectPatchInfo;
6079 patch->numSegs[0] = pNumSegs[0];
6080 patch->numSegs[1] = pNumSegs[1];
6081 patch->numSegs[2] = pNumSegs[2];
6082 patch->numSegs[3] = pNumSegs[3];
6084 hr = tesselate_rectpatch(This, patch);
6085 if(FAILED(hr)) {
6086 WARN("Patch tesselation failed\n");
6088 /* Do not release the handle to store the params of the patch */
6089 if(!Handle) {
6090 HeapFree(GetProcessHeap(), 0, patch);
6092 return hr;
6096 This->currentPatch = patch;
6097 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6098 This->currentPatch = NULL;
6100 /* Destroy uncached patches */
6101 if(!Handle) {
6102 HeapFree(GetProcessHeap(), 0, patch->mem);
6103 HeapFree(GetProcessHeap(), 0, patch);
6105 return WINED3D_OK;
6108 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6110 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6111 FIXME("(%p) : Stub\n", This);
6112 return WINED3D_OK;
6115 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6117 int i;
6118 struct WineD3DRectPatch *patch;
6119 struct list *e;
6120 TRACE("(%p) Handle(%d)\n", This, Handle);
6122 i = PATCHMAP_HASHFUNC(Handle);
6123 LIST_FOR_EACH(e, &This->patches[i]) {
6124 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6125 if(patch->Handle == Handle) {
6126 TRACE("Deleting patch %p\n", patch);
6127 list_remove(&patch->entry);
6128 HeapFree(GetProcessHeap(), 0, patch->mem);
6129 HeapFree(GetProcessHeap(), 0, patch);
6130 return WINED3D_OK;
6134 /* TODO: Write a test for the return value */
6135 FIXME("Attempt to destroy nonexistent patch\n");
6136 return WINED3DERR_INVALIDCALL;
6139 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6140 HRESULT hr;
6141 IWineD3DSwapChain *swapchain;
6143 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6144 if (SUCCEEDED(hr)) {
6145 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6146 return swapchain;
6149 return NULL;
6152 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6154 IWineD3DSwapChain *swapchain;
6156 swapchain = get_swapchain(surface);
6157 if (swapchain) {
6158 GLenum buffer;
6160 TRACE("Surface %p is onscreen\n", surface);
6162 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6163 ENTER_GL();
6164 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6165 buffer = surface_get_gl_buffer(surface, swapchain);
6166 glDrawBuffer(buffer);
6167 checkGLcall("glDrawBuffer()");
6168 } else {
6169 TRACE("Surface %p is offscreen\n", surface);
6171 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6172 ENTER_GL();
6173 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6174 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6175 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6176 checkGLcall("glFramebufferRenderbufferEXT");
6179 if (rect) {
6180 glEnable(GL_SCISSOR_TEST);
6181 if(!swapchain) {
6182 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6183 } else {
6184 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6185 rect->x2 - rect->x1, rect->y2 - rect->y1);
6187 checkGLcall("glScissor");
6188 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6189 } else {
6190 glDisable(GL_SCISSOR_TEST);
6192 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6194 glDisable(GL_BLEND);
6195 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6197 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6198 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6200 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6201 glClear(GL_COLOR_BUFFER_BIT);
6202 checkGLcall("glClear");
6204 if (This->activeContext->current_fbo) {
6205 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6206 } else {
6207 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6208 checkGLcall("glBindFramebuffer()");
6211 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6212 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6213 glDrawBuffer(GL_BACK);
6214 checkGLcall("glDrawBuffer()");
6217 LEAVE_GL();
6220 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6221 unsigned int r, g, b, a;
6222 DWORD ret;
6224 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6225 destfmt == WINED3DFMT_R8G8B8)
6226 return color;
6228 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6230 a = (color & 0xff000000) >> 24;
6231 r = (color & 0x00ff0000) >> 16;
6232 g = (color & 0x0000ff00) >> 8;
6233 b = (color & 0x000000ff) >> 0;
6235 switch(destfmt)
6237 case WINED3DFMT_R5G6B5:
6238 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6239 r = (r * 32) / 256;
6240 g = (g * 64) / 256;
6241 b = (b * 32) / 256;
6242 ret = r << 11;
6243 ret |= g << 5;
6244 ret |= b;
6245 TRACE("Returning %08x\n", ret);
6246 return ret;
6248 case WINED3DFMT_X1R5G5B5:
6249 case WINED3DFMT_A1R5G5B5:
6250 a = (a * 2) / 256;
6251 r = (r * 32) / 256;
6252 g = (g * 32) / 256;
6253 b = (b * 32) / 256;
6254 ret = a << 15;
6255 ret |= r << 10;
6256 ret |= g << 5;
6257 ret |= b << 0;
6258 TRACE("Returning %08x\n", ret);
6259 return ret;
6261 case WINED3DFMT_A8:
6262 TRACE("Returning %08x\n", a);
6263 return a;
6265 case WINED3DFMT_X4R4G4B4:
6266 case WINED3DFMT_A4R4G4B4:
6267 a = (a * 16) / 256;
6268 r = (r * 16) / 256;
6269 g = (g * 16) / 256;
6270 b = (b * 16) / 256;
6271 ret = a << 12;
6272 ret |= r << 8;
6273 ret |= g << 4;
6274 ret |= b << 0;
6275 TRACE("Returning %08x\n", ret);
6276 return ret;
6278 case WINED3DFMT_R3G3B2:
6279 r = (r * 8) / 256;
6280 g = (g * 8) / 256;
6281 b = (b * 4) / 256;
6282 ret = r << 5;
6283 ret |= g << 2;
6284 ret |= b << 0;
6285 TRACE("Returning %08x\n", ret);
6286 return ret;
6288 case WINED3DFMT_X8B8G8R8:
6289 case WINED3DFMT_A8B8G8R8:
6290 ret = a << 24;
6291 ret |= b << 16;
6292 ret |= g << 8;
6293 ret |= r << 0;
6294 TRACE("Returning %08x\n", ret);
6295 return ret;
6297 case WINED3DFMT_A2R10G10B10:
6298 a = (a * 4) / 256;
6299 r = (r * 1024) / 256;
6300 g = (g * 1024) / 256;
6301 b = (b * 1024) / 256;
6302 ret = a << 30;
6303 ret |= r << 20;
6304 ret |= g << 10;
6305 ret |= b << 0;
6306 TRACE("Returning %08x\n", ret);
6307 return ret;
6309 case WINED3DFMT_A2B10G10R10:
6310 a = (a * 4) / 256;
6311 r = (r * 1024) / 256;
6312 g = (g * 1024) / 256;
6313 b = (b * 1024) / 256;
6314 ret = a << 30;
6315 ret |= b << 20;
6316 ret |= g << 10;
6317 ret |= r << 0;
6318 TRACE("Returning %08x\n", ret);
6319 return ret;
6321 default:
6322 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6323 return 0;
6327 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6329 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6330 WINEDDBLTFX BltFx;
6331 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6333 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6334 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6335 return WINED3DERR_INVALIDCALL;
6338 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6339 color_fill_fbo(iface, pSurface, pRect, color);
6340 return WINED3D_OK;
6341 } else {
6342 /* Just forward this to the DirectDraw blitting engine */
6343 memset(&BltFx, 0, sizeof(BltFx));
6344 BltFx.dwSize = sizeof(BltFx);
6345 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6346 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6347 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6351 /* rendertarget and depth stencil functions */
6352 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6353 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6355 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6356 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6357 return WINED3DERR_INVALIDCALL;
6360 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6361 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6362 /* Note inc ref on returned surface */
6363 if(*ppRenderTarget != NULL)
6364 IWineD3DSurface_AddRef(*ppRenderTarget);
6365 return WINED3D_OK;
6368 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6370 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6371 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6372 IWineD3DSwapChainImpl *Swapchain;
6373 HRESULT hr;
6375 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6377 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6378 if(hr != WINED3D_OK) {
6379 ERR("Can't get the swapchain\n");
6380 return hr;
6383 /* Make sure to release the swapchain */
6384 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6386 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6387 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6388 return WINED3DERR_INVALIDCALL;
6390 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6391 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6392 return WINED3DERR_INVALIDCALL;
6395 if(Swapchain->frontBuffer != Front) {
6396 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6398 if(Swapchain->frontBuffer)
6399 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6400 Swapchain->frontBuffer = Front;
6402 if(Swapchain->frontBuffer) {
6403 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6407 if(Back && !Swapchain->backBuffer) {
6408 /* We need memory for the back buffer array - only one back buffer this way */
6409 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6410 if(!Swapchain->backBuffer) {
6411 ERR("Out of memory\n");
6412 return E_OUTOFMEMORY;
6416 if(Swapchain->backBuffer[0] != Back) {
6417 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6419 /* What to do about the context here in the case of multithreading? Not sure.
6420 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6422 ENTER_GL();
6423 if(!Swapchain->backBuffer[0]) {
6424 /* GL was told to draw to the front buffer at creation,
6425 * undo that
6427 glDrawBuffer(GL_BACK);
6428 checkGLcall("glDrawBuffer(GL_BACK)");
6429 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6430 Swapchain->presentParms.BackBufferCount = 1;
6431 } else if (!Back) {
6432 /* That makes problems - disable for now */
6433 /* glDrawBuffer(GL_FRONT); */
6434 checkGLcall("glDrawBuffer(GL_FRONT)");
6435 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6436 Swapchain->presentParms.BackBufferCount = 0;
6438 LEAVE_GL();
6440 if(Swapchain->backBuffer[0])
6441 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6442 Swapchain->backBuffer[0] = Back;
6444 if(Swapchain->backBuffer[0]) {
6445 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6446 } else {
6447 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6448 Swapchain->backBuffer = NULL;
6453 return WINED3D_OK;
6456 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6458 *ppZStencilSurface = This->stencilBufferTarget;
6459 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6461 if(*ppZStencilSurface != NULL) {
6462 /* Note inc ref on returned surface */
6463 IWineD3DSurface_AddRef(*ppZStencilSurface);
6464 return WINED3D_OK;
6465 } else {
6466 return WINED3DERR_NOTFOUND;
6470 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6471 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6474 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6475 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6476 GLenum gl_filter;
6477 POINT offset = {0, 0};
6479 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6480 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6481 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6482 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6484 switch (filter) {
6485 case WINED3DTEXF_LINEAR:
6486 gl_filter = GL_LINEAR;
6487 break;
6489 default:
6490 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6491 case WINED3DTEXF_NONE:
6492 case WINED3DTEXF_POINT:
6493 gl_filter = GL_NEAREST;
6494 break;
6497 /* Attach src surface to src fbo */
6498 src_swapchain = get_swapchain(src_surface);
6499 if (src_swapchain) {
6500 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6502 TRACE("Source surface %p is onscreen\n", src_surface);
6503 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6504 /* Make sure the drawable is up to date. In the offscreen case
6505 * attach_surface_fbo() implicitly takes care of this. */
6506 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6508 if(buffer == GL_FRONT) {
6509 RECT windowsize;
6510 UINT h;
6511 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6512 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6513 h = windowsize.bottom - windowsize.top;
6514 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6515 src_rect->y1 = offset.y + h - src_rect->y1;
6516 src_rect->y2 = offset.y + h - src_rect->y2;
6517 } else {
6518 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6519 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6522 ENTER_GL();
6523 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6524 glReadBuffer(buffer);
6525 checkGLcall("glReadBuffer()");
6526 } else {
6527 TRACE("Source surface %p is offscreen\n", src_surface);
6528 ENTER_GL();
6529 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6530 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6531 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6532 checkGLcall("glReadBuffer()");
6533 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6534 checkGLcall("glFramebufferRenderbufferEXT");
6536 LEAVE_GL();
6538 /* Attach dst surface to dst fbo */
6539 dst_swapchain = get_swapchain(dst_surface);
6540 if (dst_swapchain) {
6541 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6543 TRACE("Destination surface %p is onscreen\n", dst_surface);
6544 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6545 /* Make sure the drawable is up to date. In the offscreen case
6546 * attach_surface_fbo() implicitly takes care of this. */
6547 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6549 if(buffer == GL_FRONT) {
6550 RECT windowsize;
6551 UINT h;
6552 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6553 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6554 h = windowsize.bottom - windowsize.top;
6555 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6556 dst_rect->y1 = offset.y + h - dst_rect->y1;
6557 dst_rect->y2 = offset.y + h - dst_rect->y2;
6558 } else {
6559 /* Screen coords = window coords, surface height = window height */
6560 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6561 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6564 ENTER_GL();
6565 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6566 glDrawBuffer(buffer);
6567 checkGLcall("glDrawBuffer()");
6568 } else {
6569 TRACE("Destination surface %p is offscreen\n", dst_surface);
6571 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6572 if(!src_swapchain) {
6573 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6576 ENTER_GL();
6577 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6578 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6579 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6580 checkGLcall("glDrawBuffer()");
6581 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6582 checkGLcall("glFramebufferRenderbufferEXT");
6584 glDisable(GL_SCISSOR_TEST);
6585 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6587 if (flip) {
6588 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6589 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6590 checkGLcall("glBlitFramebuffer()");
6591 } else {
6592 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6593 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6594 checkGLcall("glBlitFramebuffer()");
6597 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6599 if (This->activeContext->current_fbo) {
6600 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6601 } else {
6602 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6603 checkGLcall("glBindFramebuffer()");
6606 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6607 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6608 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6609 glDrawBuffer(GL_BACK);
6610 checkGLcall("glDrawBuffer()");
6612 LEAVE_GL();
6615 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6617 WINED3DVIEWPORT viewport;
6619 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6621 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6622 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6623 This, RenderTargetIndex, GL_LIMITS(buffers));
6624 return WINED3DERR_INVALIDCALL;
6627 /* MSDN says that null disables the render target
6628 but a device must always be associated with a render target
6629 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6631 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6632 FIXME("Trying to set render target 0 to NULL\n");
6633 return WINED3DERR_INVALIDCALL;
6635 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6636 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);
6637 return WINED3DERR_INVALIDCALL;
6640 /* If we are trying to set what we already have, don't bother */
6641 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6642 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6643 return WINED3D_OK;
6645 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6646 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6647 This->render_targets[RenderTargetIndex] = pRenderTarget;
6649 /* Render target 0 is special */
6650 if(RenderTargetIndex == 0) {
6651 /* Finally, reset the viewport as the MSDN states. */
6652 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6653 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6654 viewport.X = 0;
6655 viewport.Y = 0;
6656 viewport.MaxZ = 1.0f;
6657 viewport.MinZ = 0.0f;
6658 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6659 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6660 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6662 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6664 return WINED3D_OK;
6667 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6669 HRESULT hr = WINED3D_OK;
6670 IWineD3DSurface *tmp;
6672 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6674 if (pNewZStencil == This->stencilBufferTarget) {
6675 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6676 } else {
6677 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6678 * depending on the renter target implementation being used.
6679 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6680 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6681 * stencil buffer and incur an extra memory overhead
6682 ******************************************************/
6684 if (This->stencilBufferTarget) {
6685 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6686 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6687 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6688 } else {
6689 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6690 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6691 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6695 tmp = This->stencilBufferTarget;
6696 This->stencilBufferTarget = pNewZStencil;
6697 /* should we be calling the parent or the wined3d surface? */
6698 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6699 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6700 hr = WINED3D_OK;
6702 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6703 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6704 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6705 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6706 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6710 return hr;
6713 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6714 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6716 /* TODO: the use of Impl is deprecated. */
6717 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6718 WINED3DLOCKED_RECT lockedRect;
6720 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6722 /* some basic validation checks */
6723 if(This->cursorTexture) {
6724 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6725 ENTER_GL();
6726 glDeleteTextures(1, &This->cursorTexture);
6727 LEAVE_GL();
6728 This->cursorTexture = 0;
6731 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6732 This->haveHardwareCursor = TRUE;
6733 else
6734 This->haveHardwareCursor = FALSE;
6736 if(pCursorBitmap) {
6737 WINED3DLOCKED_RECT rect;
6739 /* MSDN: Cursor must be A8R8G8B8 */
6740 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6741 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6742 return WINED3DERR_INVALIDCALL;
6745 /* MSDN: Cursor must be smaller than the display mode */
6746 if(pSur->currentDesc.Width > This->ddraw_width ||
6747 pSur->currentDesc.Height > This->ddraw_height) {
6748 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);
6749 return WINED3DERR_INVALIDCALL;
6752 if (!This->haveHardwareCursor) {
6753 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6755 /* Do not store the surface's pointer because the application may
6756 * release it after setting the cursor image. Windows doesn't
6757 * addref the set surface, so we can't do this either without
6758 * creating circular refcount dependencies. Copy out the gl texture
6759 * instead.
6761 This->cursorWidth = pSur->currentDesc.Width;
6762 This->cursorHeight = pSur->currentDesc.Height;
6763 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6765 const struct GlPixelFormatDesc *glDesc;
6766 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6767 char *mem, *bits = (char *)rect.pBits;
6768 GLint intfmt = glDesc->glInternal;
6769 GLint format = glDesc->glFormat;
6770 GLint type = glDesc->glType;
6771 INT height = This->cursorHeight;
6772 INT width = This->cursorWidth;
6773 INT bpp = tableEntry->bpp;
6774 INT i, sampler;
6776 /* Reformat the texture memory (pitch and width can be
6777 * different) */
6778 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6779 for(i = 0; i < height; i++)
6780 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6781 IWineD3DSurface_UnlockRect(pCursorBitmap);
6782 ENTER_GL();
6784 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6785 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6786 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6789 /* Make sure that a proper texture unit is selected */
6790 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6791 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6792 checkGLcall("glActiveTextureARB");
6794 sampler = This->rev_tex_unit_map[0];
6795 if (sampler != -1) {
6796 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6798 /* Create a new cursor texture */
6799 glGenTextures(1, &This->cursorTexture);
6800 checkGLcall("glGenTextures");
6801 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6802 checkGLcall("glBindTexture");
6803 /* Copy the bitmap memory into the cursor texture */
6804 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6805 HeapFree(GetProcessHeap(), 0, mem);
6806 checkGLcall("glTexImage2D");
6808 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6809 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6810 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6813 LEAVE_GL();
6815 else
6817 FIXME("A cursor texture was not returned.\n");
6818 This->cursorTexture = 0;
6821 else
6823 /* Draw a hardware cursor */
6824 ICONINFO cursorInfo;
6825 HCURSOR cursor;
6826 /* Create and clear maskBits because it is not needed for
6827 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6828 * chunks. */
6829 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6830 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6831 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6832 WINED3DLOCK_NO_DIRTY_UPDATE |
6833 WINED3DLOCK_READONLY
6835 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6836 pSur->currentDesc.Height);
6838 cursorInfo.fIcon = FALSE;
6839 cursorInfo.xHotspot = XHotSpot;
6840 cursorInfo.yHotspot = YHotSpot;
6841 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6842 pSur->currentDesc.Height, 1,
6843 1, &maskBits);
6844 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6845 pSur->currentDesc.Height, 1,
6846 32, lockedRect.pBits);
6847 IWineD3DSurface_UnlockRect(pCursorBitmap);
6848 /* Create our cursor and clean up. */
6849 cursor = CreateIconIndirect(&cursorInfo);
6850 SetCursor(cursor);
6851 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6852 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6853 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6854 This->hardwareCursor = cursor;
6855 HeapFree(GetProcessHeap(), 0, maskBits);
6859 This->xHotSpot = XHotSpot;
6860 This->yHotSpot = YHotSpot;
6861 return WINED3D_OK;
6864 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6866 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6868 This->xScreenSpace = XScreenSpace;
6869 This->yScreenSpace = YScreenSpace;
6871 return;
6875 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6877 BOOL oldVisible = This->bCursorVisible;
6878 POINT pt;
6880 TRACE("(%p) : visible(%d)\n", This, bShow);
6883 * When ShowCursor is first called it should make the cursor appear at the OS's last
6884 * known cursor position. Because of this, some applications just repetitively call
6885 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6887 GetCursorPos(&pt);
6888 This->xScreenSpace = pt.x;
6889 This->yScreenSpace = pt.y;
6891 if (This->haveHardwareCursor) {
6892 This->bCursorVisible = bShow;
6893 if (bShow)
6894 SetCursor(This->hardwareCursor);
6895 else
6896 SetCursor(NULL);
6898 else
6900 if (This->cursorTexture)
6901 This->bCursorVisible = bShow;
6904 return oldVisible;
6907 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6909 IWineD3DResourceImpl *resource;
6910 TRACE("(%p) : state (%u)\n", This, This->state);
6912 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6913 switch (This->state) {
6914 case WINED3D_OK:
6915 return WINED3D_OK;
6916 case WINED3DERR_DEVICELOST:
6918 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6919 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6920 return WINED3DERR_DEVICENOTRESET;
6922 return WINED3DERR_DEVICELOST;
6924 case WINED3DERR_DRIVERINTERNALERROR:
6925 return WINED3DERR_DRIVERINTERNALERROR;
6928 /* Unknown state */
6929 return WINED3DERR_DRIVERINTERNALERROR;
6933 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6935 /** FIXME: Resource tracking needs to be done,
6936 * The closes we can do to this is set the priorities of all managed textures low
6937 * and then reset them.
6938 ***********************************************************/
6939 FIXME("(%p) : stub\n", This);
6940 return WINED3D_OK;
6943 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6945 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6947 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6948 if(surface->Flags & SFLAG_DIBSECTION) {
6949 /* Release the DC */
6950 SelectObject(surface->hDC, surface->dib.holdbitmap);
6951 DeleteDC(surface->hDC);
6952 /* Release the DIB section */
6953 DeleteObject(surface->dib.DIBsection);
6954 surface->dib.bitmap_data = NULL;
6955 surface->resource.allocatedMemory = NULL;
6956 surface->Flags &= ~SFLAG_DIBSECTION;
6958 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6959 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6960 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6961 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6962 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6963 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6964 } else {
6965 surface->pow2Width = surface->pow2Height = 1;
6966 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6967 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6969 surface->glRect.left = 0;
6970 surface->glRect.top = 0;
6971 surface->glRect.right = surface->pow2Width;
6972 surface->glRect.bottom = surface->pow2Height;
6974 if(surface->glDescription.textureName) {
6975 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6976 ENTER_GL();
6977 glDeleteTextures(1, &surface->glDescription.textureName);
6978 LEAVE_GL();
6979 surface->glDescription.textureName = 0;
6980 surface->Flags &= ~SFLAG_CLIENT;
6982 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6983 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6984 surface->Flags |= SFLAG_NONPOW2;
6985 } else {
6986 surface->Flags &= ~SFLAG_NONPOW2;
6988 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6989 surface->resource.allocatedMemory = NULL;
6990 surface->resource.heapMemory = NULL;
6991 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6992 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6993 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6994 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6995 } else {
6996 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7000 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7001 TRACE("Unloading resource %p\n", resource);
7002 IWineD3DResource_UnLoad(resource);
7003 IWineD3DResource_Release(resource);
7004 return S_OK;
7007 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7009 UINT i, count;
7010 WINED3DDISPLAYMODE m;
7011 HRESULT hr;
7013 /* All Windowed modes are supported, as is leaving the current mode */
7014 if(pp->Windowed) return TRUE;
7015 if(!pp->BackBufferWidth) return TRUE;
7016 if(!pp->BackBufferHeight) return TRUE;
7018 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7019 for(i = 0; i < count; i++) {
7020 memset(&m, 0, sizeof(m));
7021 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7022 if(FAILED(hr)) {
7023 ERR("EnumAdapterModes failed\n");
7025 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7026 /* Mode found, it is supported */
7027 return TRUE;
7030 /* Mode not found -> not supported */
7031 return FALSE;
7034 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7036 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7037 UINT i;
7038 IWineD3DBaseShaderImpl *shader;
7040 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7041 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7042 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7045 ENTER_GL();
7046 if(This->depth_blt_texture) {
7047 glDeleteTextures(1, &This->depth_blt_texture);
7048 This->depth_blt_texture = 0;
7050 if (This->depth_blt_rb) {
7051 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7052 This->depth_blt_rb = 0;
7053 This->depth_blt_rb_w = 0;
7054 This->depth_blt_rb_h = 0;
7056 LEAVE_GL();
7058 This->blitter->free_private(iface);
7059 This->frag_pipe->free_private(iface);
7060 This->shader_backend->shader_free_private(iface);
7062 ENTER_GL();
7063 for (i = 0; i < GL_LIMITS(textures); i++) {
7064 /* Textures are recreated below */
7065 glDeleteTextures(1, &This->dummyTextureName[i]);
7066 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7067 This->dummyTextureName[i] = 0;
7069 LEAVE_GL();
7071 while(This->numContexts) {
7072 DestroyContext(This, This->contexts[0]);
7074 This->activeContext = NULL;
7075 HeapFree(GetProcessHeap(), 0, swapchain->context);
7076 swapchain->context = NULL;
7077 swapchain->num_contexts = 0;
7080 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7082 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7083 HRESULT hr;
7084 IWineD3DSurfaceImpl *target;
7086 /* Recreate the primary swapchain's context */
7087 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7088 if(swapchain->backBuffer) {
7089 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7090 } else {
7091 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7093 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7094 &swapchain->presentParms);
7095 swapchain->num_contexts = 1;
7096 This->activeContext = swapchain->context[0];
7098 create_dummy_textures(This);
7100 hr = This->shader_backend->shader_alloc_private(iface);
7101 if(FAILED(hr)) {
7102 ERR("Failed to recreate shader private data\n");
7103 goto err_out;
7105 hr = This->frag_pipe->alloc_private(iface);
7106 if(FAILED(hr)) {
7107 TRACE("Fragment pipeline private data couldn't be allocated\n");
7108 goto err_out;
7110 hr = This->blitter->alloc_private(iface);
7111 if(FAILED(hr)) {
7112 TRACE("Blitter private data couldn't be allocated\n");
7113 goto err_out;
7116 return WINED3D_OK;
7118 err_out:
7119 This->blitter->free_private(iface);
7120 This->frag_pipe->free_private(iface);
7121 This->shader_backend->shader_free_private(iface);
7122 return hr;
7125 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7127 IWineD3DSwapChainImpl *swapchain;
7128 HRESULT hr;
7129 BOOL DisplayModeChanged = FALSE;
7130 WINED3DDISPLAYMODE mode;
7131 TRACE("(%p)\n", This);
7133 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7134 if(FAILED(hr)) {
7135 ERR("Failed to get the first implicit swapchain\n");
7136 return hr;
7139 if(!is_display_mode_supported(This, pPresentationParameters)) {
7140 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7141 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7142 pPresentationParameters->BackBufferHeight);
7143 return WINED3DERR_INVALIDCALL;
7146 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7147 * on an existing gl context, so there's no real need for recreation.
7149 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7151 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7153 TRACE("New params:\n");
7154 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7155 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7156 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7157 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7158 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7159 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7160 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7161 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7162 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7163 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7164 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7165 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7166 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7168 /* No special treatment of these parameters. Just store them */
7169 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7170 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7171 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7172 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7174 /* What to do about these? */
7175 if(pPresentationParameters->BackBufferCount != 0 &&
7176 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7177 ERR("Cannot change the back buffer count yet\n");
7179 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7180 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7181 ERR("Cannot change the back buffer format yet\n");
7183 if(pPresentationParameters->hDeviceWindow != NULL &&
7184 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7185 ERR("Cannot change the device window yet\n");
7187 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7188 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7189 return WINED3DERR_INVALIDCALL;
7192 /* Reset the depth stencil */
7193 if (pPresentationParameters->EnableAutoDepthStencil)
7194 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7195 else
7196 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7198 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7200 if(pPresentationParameters->Windowed) {
7201 mode.Width = swapchain->orig_width;
7202 mode.Height = swapchain->orig_height;
7203 mode.RefreshRate = 0;
7204 mode.Format = swapchain->presentParms.BackBufferFormat;
7205 } else {
7206 mode.Width = pPresentationParameters->BackBufferWidth;
7207 mode.Height = pPresentationParameters->BackBufferHeight;
7208 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7209 mode.Format = swapchain->presentParms.BackBufferFormat;
7212 /* Should Width == 800 && Height == 0 set 800x600? */
7213 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7214 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7215 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7217 WINED3DVIEWPORT vp;
7218 UINT i;
7220 vp.X = 0;
7221 vp.Y = 0;
7222 vp.Width = pPresentationParameters->BackBufferWidth;
7223 vp.Height = pPresentationParameters->BackBufferHeight;
7224 vp.MinZ = 0;
7225 vp.MaxZ = 1;
7227 if(!pPresentationParameters->Windowed) {
7228 DisplayModeChanged = TRUE;
7230 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7231 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7233 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7234 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7235 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7237 if(This->auto_depth_stencil_buffer) {
7238 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7242 /* Now set the new viewport */
7243 IWineD3DDevice_SetViewport(iface, &vp);
7246 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7247 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7248 DisplayModeChanged) {
7250 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7252 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7253 if(swapchain->presentParms.Windowed) {
7254 /* switch from windowed to fs */
7255 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7256 pPresentationParameters->BackBufferWidth,
7257 pPresentationParameters->BackBufferHeight);
7258 } else {
7259 /* Fullscreen -> fullscreen mode change */
7260 MoveWindow(swapchain->win_handle, 0, 0,
7261 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7262 TRUE);
7264 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7265 /* Fullscreen -> windowed switch */
7266 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7268 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7269 } else if(!pPresentationParameters->Windowed) {
7270 DWORD style = This->style, exStyle = This->exStyle;
7271 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7272 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7273 * Reset to clear up their mess. Guild Wars also loses the device during that.
7275 This->style = 0;
7276 This->exStyle = 0;
7277 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7278 pPresentationParameters->BackBufferWidth,
7279 pPresentationParameters->BackBufferHeight);
7280 This->style = style;
7281 This->exStyle = exStyle;
7284 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7285 if(FAILED(hr)) {
7286 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7289 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7290 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7292 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7293 * first use
7295 return hr;
7298 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7300 /** FIXME: always true at the moment **/
7301 if(!bEnableDialogs) {
7302 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7304 return WINED3D_OK;
7308 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7310 TRACE("(%p) : pParameters %p\n", This, pParameters);
7312 *pParameters = This->createParms;
7313 return WINED3D_OK;
7316 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7317 IWineD3DSwapChain *swapchain;
7319 TRACE("Relaying to swapchain\n");
7321 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7322 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7323 IWineD3DSwapChain_Release(swapchain);
7325 return;
7328 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7329 IWineD3DSwapChain *swapchain;
7331 TRACE("Relaying to swapchain\n");
7333 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7334 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7335 IWineD3DSwapChain_Release(swapchain);
7337 return;
7341 /** ********************************************************
7342 * Notification functions
7343 ** ********************************************************/
7344 /** This function must be called in the release of a resource when ref == 0,
7345 * the contents of resource must still be correct,
7346 * any handles to other resource held by the caller must be closed
7347 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7348 *****************************************************/
7349 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7352 TRACE("(%p) : Adding Resource %p\n", This, resource);
7353 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7356 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7359 TRACE("(%p) : Removing resource %p\n", This, resource);
7361 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7365 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7367 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7368 int counter;
7370 TRACE("(%p) : resource %p\n", This, resource);
7372 context_resource_released(iface, resource, type);
7374 switch (type) {
7375 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7376 case WINED3DRTYPE_SURFACE: {
7377 unsigned int i;
7379 /* Cleanup any FBO attachments if d3d is enabled */
7380 if(This->d3d_initialized) {
7381 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7382 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7384 TRACE("Last active render target destroyed\n");
7385 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7386 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7387 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7388 * and the lastActiveRenderTarget member shouldn't matter
7390 if(swapchain) {
7391 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7392 TRACE("Activating primary back buffer\n");
7393 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7394 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7395 /* Single buffering environment */
7396 TRACE("Activating primary front buffer\n");
7397 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7398 } else {
7399 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7400 /* Implicit render target destroyed, that means the device is being destroyed
7401 * whatever we set here, it shouldn't matter
7403 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7405 } else {
7406 /* May happen during ddraw uninitialization */
7407 TRACE("Render target set, but swapchain does not exist!\n");
7408 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7412 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7413 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7414 This->render_targets[i] = NULL;
7417 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7418 This->stencilBufferTarget = NULL;
7422 break;
7424 case WINED3DRTYPE_TEXTURE:
7425 case WINED3DRTYPE_CUBETEXTURE:
7426 case WINED3DRTYPE_VOLUMETEXTURE:
7427 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7428 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7429 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7430 This->stateBlock->textures[counter] = NULL;
7432 if (This->updateStateBlock != This->stateBlock ){
7433 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7434 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7435 This->updateStateBlock->textures[counter] = NULL;
7439 break;
7440 case WINED3DRTYPE_VOLUME:
7441 /* TODO: nothing really? */
7442 break;
7443 case WINED3DRTYPE_VERTEXBUFFER:
7444 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7446 int streamNumber;
7447 TRACE("Cleaning up stream pointers\n");
7449 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7450 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7451 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7453 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7454 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7455 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7456 This->updateStateBlock->streamSource[streamNumber] = 0;
7457 /* Set changed flag? */
7460 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) */
7461 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7462 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7463 This->stateBlock->streamSource[streamNumber] = 0;
7468 break;
7469 case WINED3DRTYPE_INDEXBUFFER:
7470 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7471 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7472 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7473 This->updateStateBlock->pIndexData = NULL;
7476 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7477 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7478 This->stateBlock->pIndexData = NULL;
7482 break;
7483 default:
7484 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7485 break;
7489 /* Remove the resource from the resourceStore */
7490 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7492 TRACE("Resource released\n");
7496 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7498 IWineD3DResourceImpl *resource, *cursor;
7499 HRESULT ret;
7500 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7502 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7503 TRACE("enumerating resource %p\n", resource);
7504 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7505 ret = pCallback((IWineD3DResource *) resource, pData);
7506 if(ret == S_FALSE) {
7507 TRACE("Canceling enumeration\n");
7508 break;
7511 return WINED3D_OK;
7514 /**********************************************************
7515 * IWineD3DDevice VTbl follows
7516 **********************************************************/
7518 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7520 /*** IUnknown methods ***/
7521 IWineD3DDeviceImpl_QueryInterface,
7522 IWineD3DDeviceImpl_AddRef,
7523 IWineD3DDeviceImpl_Release,
7524 /*** IWineD3DDevice methods ***/
7525 IWineD3DDeviceImpl_GetParent,
7526 /*** Creation methods**/
7527 IWineD3DDeviceImpl_CreateVertexBuffer,
7528 IWineD3DDeviceImpl_CreateIndexBuffer,
7529 IWineD3DDeviceImpl_CreateStateBlock,
7530 IWineD3DDeviceImpl_CreateSurface,
7531 IWineD3DDeviceImpl_CreateTexture,
7532 IWineD3DDeviceImpl_CreateVolumeTexture,
7533 IWineD3DDeviceImpl_CreateVolume,
7534 IWineD3DDeviceImpl_CreateCubeTexture,
7535 IWineD3DDeviceImpl_CreateQuery,
7536 IWineD3DDeviceImpl_CreateSwapChain,
7537 IWineD3DDeviceImpl_CreateVertexDeclaration,
7538 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7539 IWineD3DDeviceImpl_CreateVertexShader,
7540 IWineD3DDeviceImpl_CreatePixelShader,
7541 IWineD3DDeviceImpl_CreatePalette,
7542 /*** Odd functions **/
7543 IWineD3DDeviceImpl_Init3D,
7544 IWineD3DDeviceImpl_InitGDI,
7545 IWineD3DDeviceImpl_Uninit3D,
7546 IWineD3DDeviceImpl_UninitGDI,
7547 IWineD3DDeviceImpl_SetMultithreaded,
7548 IWineD3DDeviceImpl_EvictManagedResources,
7549 IWineD3DDeviceImpl_GetAvailableTextureMem,
7550 IWineD3DDeviceImpl_GetBackBuffer,
7551 IWineD3DDeviceImpl_GetCreationParameters,
7552 IWineD3DDeviceImpl_GetDeviceCaps,
7553 IWineD3DDeviceImpl_GetDirect3D,
7554 IWineD3DDeviceImpl_GetDisplayMode,
7555 IWineD3DDeviceImpl_SetDisplayMode,
7556 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7557 IWineD3DDeviceImpl_GetRasterStatus,
7558 IWineD3DDeviceImpl_GetSwapChain,
7559 IWineD3DDeviceImpl_Reset,
7560 IWineD3DDeviceImpl_SetDialogBoxMode,
7561 IWineD3DDeviceImpl_SetCursorProperties,
7562 IWineD3DDeviceImpl_SetCursorPosition,
7563 IWineD3DDeviceImpl_ShowCursor,
7564 IWineD3DDeviceImpl_TestCooperativeLevel,
7565 /*** Getters and setters **/
7566 IWineD3DDeviceImpl_SetClipPlane,
7567 IWineD3DDeviceImpl_GetClipPlane,
7568 IWineD3DDeviceImpl_SetClipStatus,
7569 IWineD3DDeviceImpl_GetClipStatus,
7570 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7571 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7572 IWineD3DDeviceImpl_SetDepthStencilSurface,
7573 IWineD3DDeviceImpl_GetDepthStencilSurface,
7574 IWineD3DDeviceImpl_SetFVF,
7575 IWineD3DDeviceImpl_GetFVF,
7576 IWineD3DDeviceImpl_SetGammaRamp,
7577 IWineD3DDeviceImpl_GetGammaRamp,
7578 IWineD3DDeviceImpl_SetIndices,
7579 IWineD3DDeviceImpl_GetIndices,
7580 IWineD3DDeviceImpl_SetBaseVertexIndex,
7581 IWineD3DDeviceImpl_GetBaseVertexIndex,
7582 IWineD3DDeviceImpl_SetLight,
7583 IWineD3DDeviceImpl_GetLight,
7584 IWineD3DDeviceImpl_SetLightEnable,
7585 IWineD3DDeviceImpl_GetLightEnable,
7586 IWineD3DDeviceImpl_SetMaterial,
7587 IWineD3DDeviceImpl_GetMaterial,
7588 IWineD3DDeviceImpl_SetNPatchMode,
7589 IWineD3DDeviceImpl_GetNPatchMode,
7590 IWineD3DDeviceImpl_SetPaletteEntries,
7591 IWineD3DDeviceImpl_GetPaletteEntries,
7592 IWineD3DDeviceImpl_SetPixelShader,
7593 IWineD3DDeviceImpl_GetPixelShader,
7594 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7595 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7596 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7597 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7598 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7599 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7600 IWineD3DDeviceImpl_SetRenderState,
7601 IWineD3DDeviceImpl_GetRenderState,
7602 IWineD3DDeviceImpl_SetRenderTarget,
7603 IWineD3DDeviceImpl_GetRenderTarget,
7604 IWineD3DDeviceImpl_SetFrontBackBuffers,
7605 IWineD3DDeviceImpl_SetSamplerState,
7606 IWineD3DDeviceImpl_GetSamplerState,
7607 IWineD3DDeviceImpl_SetScissorRect,
7608 IWineD3DDeviceImpl_GetScissorRect,
7609 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7610 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7611 IWineD3DDeviceImpl_SetStreamSource,
7612 IWineD3DDeviceImpl_GetStreamSource,
7613 IWineD3DDeviceImpl_SetStreamSourceFreq,
7614 IWineD3DDeviceImpl_GetStreamSourceFreq,
7615 IWineD3DDeviceImpl_SetTexture,
7616 IWineD3DDeviceImpl_GetTexture,
7617 IWineD3DDeviceImpl_SetTextureStageState,
7618 IWineD3DDeviceImpl_GetTextureStageState,
7619 IWineD3DDeviceImpl_SetTransform,
7620 IWineD3DDeviceImpl_GetTransform,
7621 IWineD3DDeviceImpl_SetVertexDeclaration,
7622 IWineD3DDeviceImpl_GetVertexDeclaration,
7623 IWineD3DDeviceImpl_SetVertexShader,
7624 IWineD3DDeviceImpl_GetVertexShader,
7625 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7626 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7627 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7628 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7629 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7630 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7631 IWineD3DDeviceImpl_SetViewport,
7632 IWineD3DDeviceImpl_GetViewport,
7633 IWineD3DDeviceImpl_MultiplyTransform,
7634 IWineD3DDeviceImpl_ValidateDevice,
7635 IWineD3DDeviceImpl_ProcessVertices,
7636 /*** State block ***/
7637 IWineD3DDeviceImpl_BeginStateBlock,
7638 IWineD3DDeviceImpl_EndStateBlock,
7639 /*** Scene management ***/
7640 IWineD3DDeviceImpl_BeginScene,
7641 IWineD3DDeviceImpl_EndScene,
7642 IWineD3DDeviceImpl_Present,
7643 IWineD3DDeviceImpl_Clear,
7644 /*** Drawing ***/
7645 IWineD3DDeviceImpl_DrawPrimitive,
7646 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7647 IWineD3DDeviceImpl_DrawPrimitiveUP,
7648 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7649 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7650 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7651 IWineD3DDeviceImpl_DrawRectPatch,
7652 IWineD3DDeviceImpl_DrawTriPatch,
7653 IWineD3DDeviceImpl_DeletePatch,
7654 IWineD3DDeviceImpl_ColorFill,
7655 IWineD3DDeviceImpl_UpdateTexture,
7656 IWineD3DDeviceImpl_UpdateSurface,
7657 IWineD3DDeviceImpl_GetFrontBufferData,
7658 /*** object tracking ***/
7659 IWineD3DDeviceImpl_ResourceReleased,
7660 IWineD3DDeviceImpl_EnumResources
7663 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7665 /*** IUnknown methods ***/
7666 IWineD3DDeviceImpl_QueryInterface,
7667 IWineD3DDeviceImpl_AddRef,
7668 IWineD3DDeviceImpl_Release,
7669 /*** IWineD3DDevice methods ***/
7670 IWineD3DDeviceImpl_GetParent,
7671 /*** Creation methods**/
7672 IWineD3DDeviceImpl_CreateVertexBuffer,
7673 IWineD3DDeviceImpl_CreateIndexBuffer,
7674 IWineD3DDeviceImpl_CreateStateBlock,
7675 IWineD3DDeviceImpl_CreateSurface,
7676 IWineD3DDeviceImpl_CreateTexture,
7677 IWineD3DDeviceImpl_CreateVolumeTexture,
7678 IWineD3DDeviceImpl_CreateVolume,
7679 IWineD3DDeviceImpl_CreateCubeTexture,
7680 IWineD3DDeviceImpl_CreateQuery,
7681 IWineD3DDeviceImpl_CreateSwapChain,
7682 IWineD3DDeviceImpl_CreateVertexDeclaration,
7683 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7684 IWineD3DDeviceImpl_CreateVertexShader,
7685 IWineD3DDeviceImpl_CreatePixelShader,
7686 IWineD3DDeviceImpl_CreatePalette,
7687 /*** Odd functions **/
7688 IWineD3DDeviceImpl_Init3D,
7689 IWineD3DDeviceImpl_InitGDI,
7690 IWineD3DDeviceImpl_Uninit3D,
7691 IWineD3DDeviceImpl_UninitGDI,
7692 IWineD3DDeviceImpl_SetMultithreaded,
7693 IWineD3DDeviceImpl_EvictManagedResources,
7694 IWineD3DDeviceImpl_GetAvailableTextureMem,
7695 IWineD3DDeviceImpl_GetBackBuffer,
7696 IWineD3DDeviceImpl_GetCreationParameters,
7697 IWineD3DDeviceImpl_GetDeviceCaps,
7698 IWineD3DDeviceImpl_GetDirect3D,
7699 IWineD3DDeviceImpl_GetDisplayMode,
7700 IWineD3DDeviceImpl_SetDisplayMode,
7701 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7702 IWineD3DDeviceImpl_GetRasterStatus,
7703 IWineD3DDeviceImpl_GetSwapChain,
7704 IWineD3DDeviceImpl_Reset,
7705 IWineD3DDeviceImpl_SetDialogBoxMode,
7706 IWineD3DDeviceImpl_SetCursorProperties,
7707 IWineD3DDeviceImpl_SetCursorPosition,
7708 IWineD3DDeviceImpl_ShowCursor,
7709 IWineD3DDeviceImpl_TestCooperativeLevel,
7710 /*** Getters and setters **/
7711 IWineD3DDeviceImpl_SetClipPlane,
7712 IWineD3DDeviceImpl_GetClipPlane,
7713 IWineD3DDeviceImpl_SetClipStatus,
7714 IWineD3DDeviceImpl_GetClipStatus,
7715 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7716 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7717 IWineD3DDeviceImpl_SetDepthStencilSurface,
7718 IWineD3DDeviceImpl_GetDepthStencilSurface,
7719 IWineD3DDeviceImpl_SetFVF,
7720 IWineD3DDeviceImpl_GetFVF,
7721 IWineD3DDeviceImpl_SetGammaRamp,
7722 IWineD3DDeviceImpl_GetGammaRamp,
7723 IWineD3DDeviceImpl_SetIndices,
7724 IWineD3DDeviceImpl_GetIndices,
7725 IWineD3DDeviceImpl_SetBaseVertexIndex,
7726 IWineD3DDeviceImpl_GetBaseVertexIndex,
7727 IWineD3DDeviceImpl_SetLight,
7728 IWineD3DDeviceImpl_GetLight,
7729 IWineD3DDeviceImpl_SetLightEnable,
7730 IWineD3DDeviceImpl_GetLightEnable,
7731 IWineD3DDeviceImpl_SetMaterial,
7732 IWineD3DDeviceImpl_GetMaterial,
7733 IWineD3DDeviceImpl_SetNPatchMode,
7734 IWineD3DDeviceImpl_GetNPatchMode,
7735 IWineD3DDeviceImpl_SetPaletteEntries,
7736 IWineD3DDeviceImpl_GetPaletteEntries,
7737 IWineD3DDeviceImpl_SetPixelShader,
7738 IWineD3DDeviceImpl_GetPixelShader,
7739 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7740 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7741 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7742 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7743 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7744 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7745 IWineD3DDeviceImpl_SetRenderState,
7746 IWineD3DDeviceImpl_GetRenderState,
7747 IWineD3DDeviceImpl_SetRenderTarget,
7748 IWineD3DDeviceImpl_GetRenderTarget,
7749 IWineD3DDeviceImpl_SetFrontBackBuffers,
7750 IWineD3DDeviceImpl_SetSamplerState,
7751 IWineD3DDeviceImpl_GetSamplerState,
7752 IWineD3DDeviceImpl_SetScissorRect,
7753 IWineD3DDeviceImpl_GetScissorRect,
7754 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7755 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7756 IWineD3DDeviceImpl_SetStreamSource,
7757 IWineD3DDeviceImpl_GetStreamSource,
7758 IWineD3DDeviceImpl_SetStreamSourceFreq,
7759 IWineD3DDeviceImpl_GetStreamSourceFreq,
7760 IWineD3DDeviceImpl_SetTexture,
7761 IWineD3DDeviceImpl_GetTexture,
7762 IWineD3DDeviceImpl_SetTextureStageState,
7763 IWineD3DDeviceImpl_GetTextureStageState,
7764 IWineD3DDeviceImpl_SetTransform,
7765 IWineD3DDeviceImpl_GetTransform,
7766 IWineD3DDeviceImpl_SetVertexDeclaration,
7767 IWineD3DDeviceImpl_GetVertexDeclaration,
7768 IWineD3DDeviceImpl_SetVertexShader,
7769 IWineD3DDeviceImpl_GetVertexShader,
7770 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7771 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7772 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7773 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7774 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7775 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7776 IWineD3DDeviceImpl_SetViewport,
7777 IWineD3DDeviceImpl_GetViewport,
7778 IWineD3DDeviceImpl_MultiplyTransform,
7779 IWineD3DDeviceImpl_ValidateDevice,
7780 IWineD3DDeviceImpl_ProcessVertices,
7781 /*** State block ***/
7782 IWineD3DDeviceImpl_BeginStateBlock,
7783 IWineD3DDeviceImpl_EndStateBlock,
7784 /*** Scene management ***/
7785 IWineD3DDeviceImpl_BeginScene,
7786 IWineD3DDeviceImpl_EndScene,
7787 IWineD3DDeviceImpl_Present,
7788 IWineD3DDeviceImpl_Clear,
7789 /*** Drawing ***/
7790 IWineD3DDeviceImpl_DrawPrimitive,
7791 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7792 IWineD3DDeviceImpl_DrawPrimitiveUP,
7793 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7794 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7795 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7796 IWineD3DDeviceImpl_DrawRectPatch,
7797 IWineD3DDeviceImpl_DrawTriPatch,
7798 IWineD3DDeviceImpl_DeletePatch,
7799 IWineD3DDeviceImpl_ColorFill,
7800 IWineD3DDeviceImpl_UpdateTexture,
7801 IWineD3DDeviceImpl_UpdateSurface,
7802 IWineD3DDeviceImpl_GetFrontBufferData,
7803 /*** object tracking ***/
7804 IWineD3DDeviceImpl_ResourceReleased,
7805 IWineD3DDeviceImpl_EnumResources
7808 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7809 WINED3DRS_ALPHABLENDENABLE ,
7810 WINED3DRS_ALPHAFUNC ,
7811 WINED3DRS_ALPHAREF ,
7812 WINED3DRS_ALPHATESTENABLE ,
7813 WINED3DRS_BLENDOP ,
7814 WINED3DRS_COLORWRITEENABLE ,
7815 WINED3DRS_DESTBLEND ,
7816 WINED3DRS_DITHERENABLE ,
7817 WINED3DRS_FILLMODE ,
7818 WINED3DRS_FOGDENSITY ,
7819 WINED3DRS_FOGEND ,
7820 WINED3DRS_FOGSTART ,
7821 WINED3DRS_LASTPIXEL ,
7822 WINED3DRS_SHADEMODE ,
7823 WINED3DRS_SRCBLEND ,
7824 WINED3DRS_STENCILENABLE ,
7825 WINED3DRS_STENCILFAIL ,
7826 WINED3DRS_STENCILFUNC ,
7827 WINED3DRS_STENCILMASK ,
7828 WINED3DRS_STENCILPASS ,
7829 WINED3DRS_STENCILREF ,
7830 WINED3DRS_STENCILWRITEMASK ,
7831 WINED3DRS_STENCILZFAIL ,
7832 WINED3DRS_TEXTUREFACTOR ,
7833 WINED3DRS_WRAP0 ,
7834 WINED3DRS_WRAP1 ,
7835 WINED3DRS_WRAP2 ,
7836 WINED3DRS_WRAP3 ,
7837 WINED3DRS_WRAP4 ,
7838 WINED3DRS_WRAP5 ,
7839 WINED3DRS_WRAP6 ,
7840 WINED3DRS_WRAP7 ,
7841 WINED3DRS_ZENABLE ,
7842 WINED3DRS_ZFUNC ,
7843 WINED3DRS_ZWRITEENABLE
7846 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7847 WINED3DTSS_ADDRESSW ,
7848 WINED3DTSS_ALPHAARG0 ,
7849 WINED3DTSS_ALPHAARG1 ,
7850 WINED3DTSS_ALPHAARG2 ,
7851 WINED3DTSS_ALPHAOP ,
7852 WINED3DTSS_BUMPENVLOFFSET ,
7853 WINED3DTSS_BUMPENVLSCALE ,
7854 WINED3DTSS_BUMPENVMAT00 ,
7855 WINED3DTSS_BUMPENVMAT01 ,
7856 WINED3DTSS_BUMPENVMAT10 ,
7857 WINED3DTSS_BUMPENVMAT11 ,
7858 WINED3DTSS_COLORARG0 ,
7859 WINED3DTSS_COLORARG1 ,
7860 WINED3DTSS_COLORARG2 ,
7861 WINED3DTSS_COLOROP ,
7862 WINED3DTSS_RESULTARG ,
7863 WINED3DTSS_TEXCOORDINDEX ,
7864 WINED3DTSS_TEXTURETRANSFORMFLAGS
7867 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7868 WINED3DSAMP_ADDRESSU ,
7869 WINED3DSAMP_ADDRESSV ,
7870 WINED3DSAMP_ADDRESSW ,
7871 WINED3DSAMP_BORDERCOLOR ,
7872 WINED3DSAMP_MAGFILTER ,
7873 WINED3DSAMP_MINFILTER ,
7874 WINED3DSAMP_MIPFILTER ,
7875 WINED3DSAMP_MIPMAPLODBIAS ,
7876 WINED3DSAMP_MAXMIPLEVEL ,
7877 WINED3DSAMP_MAXANISOTROPY ,
7878 WINED3DSAMP_SRGBTEXTURE ,
7879 WINED3DSAMP_ELEMENTINDEX
7882 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7883 WINED3DRS_AMBIENT ,
7884 WINED3DRS_AMBIENTMATERIALSOURCE ,
7885 WINED3DRS_CLIPPING ,
7886 WINED3DRS_CLIPPLANEENABLE ,
7887 WINED3DRS_COLORVERTEX ,
7888 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7889 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7890 WINED3DRS_FOGDENSITY ,
7891 WINED3DRS_FOGEND ,
7892 WINED3DRS_FOGSTART ,
7893 WINED3DRS_FOGTABLEMODE ,
7894 WINED3DRS_FOGVERTEXMODE ,
7895 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7896 WINED3DRS_LIGHTING ,
7897 WINED3DRS_LOCALVIEWER ,
7898 WINED3DRS_MULTISAMPLEANTIALIAS ,
7899 WINED3DRS_MULTISAMPLEMASK ,
7900 WINED3DRS_NORMALIZENORMALS ,
7901 WINED3DRS_PATCHEDGESTYLE ,
7902 WINED3DRS_POINTSCALE_A ,
7903 WINED3DRS_POINTSCALE_B ,
7904 WINED3DRS_POINTSCALE_C ,
7905 WINED3DRS_POINTSCALEENABLE ,
7906 WINED3DRS_POINTSIZE ,
7907 WINED3DRS_POINTSIZE_MAX ,
7908 WINED3DRS_POINTSIZE_MIN ,
7909 WINED3DRS_POINTSPRITEENABLE ,
7910 WINED3DRS_RANGEFOGENABLE ,
7911 WINED3DRS_SPECULARMATERIALSOURCE ,
7912 WINED3DRS_TWEENFACTOR ,
7913 WINED3DRS_VERTEXBLEND ,
7914 WINED3DRS_CULLMODE ,
7915 WINED3DRS_FOGCOLOR
7918 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7919 WINED3DTSS_TEXCOORDINDEX ,
7920 WINED3DTSS_TEXTURETRANSFORMFLAGS
7923 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7924 WINED3DSAMP_DMAPOFFSET
7927 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7928 DWORD rep = This->StateTable[state].representative;
7929 DWORD idx;
7930 BYTE shift;
7931 UINT i;
7932 WineD3DContext *context;
7934 if(!rep) return;
7935 for(i = 0; i < This->numContexts; i++) {
7936 context = This->contexts[i];
7937 if(isStateDirty(context, rep)) continue;
7939 context->dirtyArray[context->numDirtyEntries++] = rep;
7940 idx = rep >> 5;
7941 shift = rep & 0x1f;
7942 context->isStateDirty[idx] |= (1 << shift);
7946 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7947 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7948 /* The drawable size of a pbuffer render target is the current pbuffer size
7950 *width = dev->pbufferWidth;
7951 *height = dev->pbufferHeight;
7954 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7955 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7957 *width = This->pow2Width;
7958 *height = This->pow2Height;
7961 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7962 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7963 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7964 * current context's drawable, which is the size of the back buffer of the swapchain
7965 * the active context belongs to. The back buffer of the swapchain is stored as the
7966 * surface the context belongs to.
7968 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7969 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;