Spelling fixes.
[wine/multimedia.git] / dlls / wined3d / device.c
blob33f4180eaac5c93d55d8bd6eb40fb4d8be95c915
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /* helper macros */
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
66 object->ref = 1; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
99 *pp##type = NULL; \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 WineD3DAdapterChangeGLRam(This, _size); \
104 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
105 if (object->resource.heapMemory == NULL && _size != 0) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
108 *pp##type = NULL; \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
112 *pp##type = (IWineD3D##type *) object; \
113 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
114 TRACE("(%p) : Created resource %p\n", This, object); \
117 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
118 _basetexture.levels = Levels; \
119 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
120 _basetexture.LOD = 0; \
121 _basetexture.dirty = TRUE; \
122 _basetexture.is_srgb = FALSE; \
123 _basetexture.srgb_mode_change_count = 0; \
126 /**********************************************************
127 * Global variable / Constants follow
128 **********************************************************/
129 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
139 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
140 if (IsEqualGUID(riid, &IID_IUnknown)
141 || IsEqualGUID(riid, &IID_IWineD3DBase)
142 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
143 IUnknown_AddRef(iface);
144 *ppobj = This;
145 return S_OK;
147 *ppobj = NULL;
148 return E_NOINTERFACE;
151 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 ULONG refCount = InterlockedIncrement(&This->ref);
155 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
156 return refCount;
159 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 ULONG refCount = InterlockedDecrement(&This->ref);
163 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
165 if (!refCount) {
166 if (This->fbo) {
167 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
169 if (This->src_fbo) {
170 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
172 if (This->dst_fbo) {
173 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
176 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
178 /* TODO: Clean up all the surfaces and textures! */
179 /* NOTE: You must release the parent if the object was created via a callback
180 ** ***************************/
182 if (!list_empty(&This->resources)) {
183 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
184 dumpResources(&This->resources);
187 if(This->contexts) ERR("Context array not freed!\n");
188 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
189 This->haveHardwareCursor = FALSE;
191 IWineD3D_Release(This->wineD3D);
192 This->wineD3D = NULL;
193 HeapFree(GetProcessHeap(), 0, This);
194 TRACE("Freed device %p\n", This);
195 This = NULL;
197 return refCount;
200 /**********************************************************
201 * IWineD3DDevice implementation follows
202 **********************************************************/
203 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
205 *pParent = This->parent;
206 IUnknown_AddRef(This->parent);
207 return WINED3D_OK;
210 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
211 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
212 IUnknown *parent) {
213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
214 IWineD3DVertexBufferImpl *object;
215 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
216 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
217 BOOL conv;
219 if(Size == 0) {
220 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
221 *ppVertexBuffer = NULL;
222 return WINED3DERR_INVALIDCALL;
223 } else if(Pool == WINED3DPOOL_SCRATCH) {
224 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
225 * anyway, SCRATCH vertex buffers aren't useable anywhere
227 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
228 *ppVertexBuffer = NULL;
229 return WINED3DERR_INVALIDCALL;
232 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
234 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);
235 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
237 object->fvf = FVF;
239 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
240 * drawStridedFast (half-life 2).
242 * Basically converting the vertices in the buffer is quite expensive, and observations
243 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
244 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
246 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
247 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
248 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
249 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
250 * dx7 apps.
251 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
252 * more. In this call we can convert dx7 buffers too.
254 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
255 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
256 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
257 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
258 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
259 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
260 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
261 } else if(dxVersion <= 7 && conv) {
262 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
263 } else {
264 object->Flags |= VBFLAG_CREATEVBO;
266 return WINED3D_OK;
269 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
270 GLenum error, glUsage;
271 TRACE("Creating VBO for Index Buffer %p\n", object);
273 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
274 * restored on the next draw
276 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
278 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
279 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
280 ENTER_GL();
282 while(glGetError());
284 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
285 error = glGetError();
286 if(error != GL_NO_ERROR || object->vbo == 0) {
287 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
288 goto out;
291 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
292 error = glGetError();
293 if(error != GL_NO_ERROR) {
294 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
295 goto out;
298 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
299 * copy no readback will be needed
301 glUsage = GL_STATIC_DRAW_ARB;
302 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
303 error = glGetError();
304 if(error != GL_NO_ERROR) {
305 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
306 goto out;
308 LEAVE_GL();
309 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
310 return;
312 out:
313 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
314 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
315 LEAVE_GL();
316 object->vbo = 0;
319 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
320 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
321 HANDLE *sharedHandle, IUnknown *parent) {
322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
323 IWineD3DIndexBufferImpl *object;
324 TRACE("(%p) Creating index buffer\n", This);
326 /* Allocate the storage for the device */
327 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
329 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
330 CreateIndexBufferVBO(This, object);
333 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
334 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
335 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
337 return WINED3D_OK;
340 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
343 IWineD3DStateBlockImpl *object;
344 int i, j;
345 HRESULT temp_result;
347 D3DCREATEOBJECTINSTANCE(object, StateBlock)
348 object->blockType = Type;
350 for(i = 0; i < LIGHTMAP_SIZE; i++) {
351 list_init(&object->lightMap[i]);
354 /* Special case - Used during initialization to produce a placeholder stateblock
355 so other functions called can update a state block */
356 if (Type == WINED3DSBT_INIT) {
357 /* Don't bother increasing the reference count otherwise a device will never
358 be freed due to circular dependencies */
359 return WINED3D_OK;
362 temp_result = allocate_shader_constants(object);
363 if (WINED3D_OK != temp_result)
364 return temp_result;
366 /* Otherwise, might as well set the whole state block to the appropriate values */
367 if (This->stateBlock != NULL)
368 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
369 else
370 memset(object->streamFreq, 1, sizeof(object->streamFreq));
372 /* Reset the ref and type after kludging it */
373 object->wineD3DDevice = This;
374 object->ref = 1;
375 object->blockType = Type;
377 TRACE("Updating changed flags appropriate for type %d\n", Type);
379 if (Type == WINED3DSBT_ALL) {
381 TRACE("ALL => Pretend everything has changed\n");
382 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
384 /* Lights are not part of the changed / set structure */
385 for(j = 0; j < LIGHTMAP_SIZE; j++) {
386 struct list *e;
387 LIST_FOR_EACH(e, &object->lightMap[j]) {
388 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
389 light->changed = TRUE;
390 light->enabledChanged = TRUE;
393 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
394 object->contained_render_states[j - 1] = j;
396 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
397 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
398 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
399 object->contained_transform_states[j - 1] = j;
401 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
402 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
403 object->contained_vs_consts_f[j] = j;
405 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
406 for(j = 0; j < MAX_CONST_I; j++) {
407 object->contained_vs_consts_i[j] = j;
409 object->num_contained_vs_consts_i = MAX_CONST_I;
410 for(j = 0; j < MAX_CONST_B; j++) {
411 object->contained_vs_consts_b[j] = j;
413 object->num_contained_vs_consts_b = MAX_CONST_B;
414 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
415 object->contained_ps_consts_f[j] = j;
417 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
418 for(j = 0; j < MAX_CONST_I; j++) {
419 object->contained_ps_consts_i[j] = j;
421 object->num_contained_ps_consts_i = MAX_CONST_I;
422 for(j = 0; j < MAX_CONST_B; j++) {
423 object->contained_ps_consts_b[j] = j;
425 object->num_contained_ps_consts_b = MAX_CONST_B;
426 for(i = 0; i < MAX_TEXTURES; i++) {
427 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
428 object->contained_tss_states[object->num_contained_tss_states].stage = i;
429 object->contained_tss_states[object->num_contained_tss_states].state = j;
430 object->num_contained_tss_states++;
433 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
434 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
435 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
436 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
437 object->num_contained_sampler_states++;
441 for(i = 0; i < MAX_STREAMS; i++) {
442 if(object->streamSource[i]) {
443 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
446 if(object->pIndexData) {
447 IWineD3DIndexBuffer_AddRef(object->pIndexData);
449 if(object->vertexShader) {
450 IWineD3DVertexShader_AddRef(object->vertexShader);
452 if(object->pixelShader) {
453 IWineD3DPixelShader_AddRef(object->pixelShader);
456 } else if (Type == WINED3DSBT_PIXELSTATE) {
458 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
459 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
461 object->changed.pixelShader = TRUE;
463 /* Pixel Shader Constants */
464 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
465 object->contained_ps_consts_f[i] = i;
466 object->changed.pixelShaderConstantsF[i] = TRUE;
468 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
469 for (i = 0; i < MAX_CONST_B; ++i) {
470 object->contained_ps_consts_b[i] = i;
471 object->changed.pixelShaderConstantsB[i] = TRUE;
473 object->num_contained_ps_consts_b = MAX_CONST_B;
474 for (i = 0; i < MAX_CONST_I; ++i) {
475 object->contained_ps_consts_i[i] = i;
476 object->changed.pixelShaderConstantsI[i] = TRUE;
478 object->num_contained_ps_consts_i = MAX_CONST_I;
480 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
481 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
482 object->contained_render_states[i] = SavedPixelStates_R[i];
484 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
485 for (j = 0; j < MAX_TEXTURES; j++) {
486 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
487 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
488 object->contained_tss_states[object->num_contained_tss_states].stage = j;
489 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
490 object->num_contained_tss_states++;
493 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
494 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
495 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
496 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
497 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
498 object->num_contained_sampler_states++;
501 if(object->pixelShader) {
502 IWineD3DPixelShader_AddRef(object->pixelShader);
505 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
506 * on them. This makes releasing the buffer easier
508 for(i = 0; i < MAX_STREAMS; i++) {
509 object->streamSource[i] = NULL;
511 object->pIndexData = NULL;
512 object->vertexShader = NULL;
514 } else if (Type == WINED3DSBT_VERTEXSTATE) {
516 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
517 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
519 object->changed.vertexShader = TRUE;
521 /* Vertex Shader Constants */
522 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
523 object->changed.vertexShaderConstantsF[i] = TRUE;
524 object->contained_vs_consts_f[i] = i;
526 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
527 for (i = 0; i < MAX_CONST_B; ++i) {
528 object->changed.vertexShaderConstantsB[i] = TRUE;
529 object->contained_vs_consts_b[i] = i;
531 object->num_contained_vs_consts_b = MAX_CONST_B;
532 for (i = 0; i < MAX_CONST_I; ++i) {
533 object->changed.vertexShaderConstantsI[i] = TRUE;
534 object->contained_vs_consts_i[i] = i;
536 object->num_contained_vs_consts_i = MAX_CONST_I;
537 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
538 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
539 object->contained_render_states[i] = SavedVertexStates_R[i];
541 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
542 for (j = 0; j < MAX_TEXTURES; j++) {
543 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
544 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
545 object->contained_tss_states[object->num_contained_tss_states].stage = j;
546 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
547 object->num_contained_tss_states++;
550 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
551 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
552 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
553 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
554 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
555 object->num_contained_sampler_states++;
559 for(j = 0; j < LIGHTMAP_SIZE; j++) {
560 struct list *e;
561 LIST_FOR_EACH(e, &object->lightMap[j]) {
562 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
563 light->changed = TRUE;
564 light->enabledChanged = TRUE;
568 for(i = 0; i < MAX_STREAMS; i++) {
569 if(object->streamSource[i]) {
570 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
573 if(object->vertexShader) {
574 IWineD3DVertexShader_AddRef(object->vertexShader);
576 object->pIndexData = NULL;
577 object->pixelShader = NULL;
578 } else {
579 FIXME("Unrecognized state block type %d\n", Type);
582 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
583 return WINED3D_OK;
586 /* ************************************
587 MSDN:
588 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
590 Discard
591 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
593 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.
595 ******************************** */
597 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) {
598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
599 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
600 unsigned int Size = 1;
601 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
602 TRACE("(%p) Create surface\n",This);
604 /** FIXME: Check ranges on the inputs are valid
605 * MSDN
606 * MultisampleQuality
607 * [in] Quality level. The valid range is between zero and one less than the level
608 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
609 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
610 * values of paired render targets, depth stencil surfaces, and the MultiSample type
611 * must all match.
612 *******************************/
616 * TODO: Discard MSDN
617 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
619 * If this flag is set, the contents of the depth stencil buffer will be
620 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
621 * with a different depth surface.
623 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
624 ***************************/
626 if(MultisampleQuality > 0) {
627 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
628 MultisampleQuality=0;
631 /** FIXME: Check that the format is supported
632 * by the device.
633 *******************************/
635 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
636 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
637 * space!
638 *********************************/
639 if (WINED3DFMT_UNKNOWN == Format) {
640 Size = 0;
641 } else if (Format == WINED3DFMT_DXT1) {
642 /* DXT1 is half byte per pixel */
643 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
645 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
646 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
647 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
648 } else {
649 /* The pitch is a multiple of 4 bytes */
650 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
651 Size *= Height;
654 /** Create and initialise the surface resource **/
655 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
656 /* "Standalone" surface */
657 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
659 object->currentDesc.Width = Width;
660 object->currentDesc.Height = Height;
661 object->currentDesc.MultiSampleType = MultiSample;
662 object->currentDesc.MultiSampleQuality = MultisampleQuality;
663 object->glDescription.level = Level;
665 /* Flags */
666 object->Flags = 0;
667 object->Flags |= Discard ? SFLAG_DISCARD : 0;
668 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
669 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
672 if (WINED3DFMT_UNKNOWN != Format) {
673 object->bytesPerPixel = tableEntry->bpp;
674 } else {
675 object->bytesPerPixel = 0;
678 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
680 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
682 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
683 * this function is too deep to need to care about things like this.
684 * Levels need to be checked too, and possibly Type since they all affect what can be done.
685 * ****************************************/
686 switch(Pool) {
687 case WINED3DPOOL_SCRATCH:
688 if(!Lockable)
689 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
690 "which are mutually exclusive, setting lockable to TRUE\n");
691 Lockable = TRUE;
692 break;
693 case WINED3DPOOL_SYSTEMMEM:
694 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
695 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
696 case WINED3DPOOL_MANAGED:
697 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
698 "Usage of DYNAMIC which are mutually exclusive, not doing "
699 "anything just telling you.\n");
700 break;
701 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
702 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
703 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
704 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
705 break;
706 default:
707 FIXME("(%p) Unknown pool %d\n", This, Pool);
708 break;
711 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
712 FIXME("Trying to create a render target that isn't in the default pool\n");
715 /* mark the texture as dirty so that it gets loaded first time around*/
716 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
717 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
718 This, Width, Height, Format, debug_d3dformat(Format),
719 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
721 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
722 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
723 This->ddraw_primary = (IWineD3DSurface *) object;
725 /* Look at the implementation and set the correct Vtable */
726 switch(Impl) {
727 case SURFACE_OPENGL:
728 /* Check if a 3D adapter is available when creating gl surfaces */
729 if(!This->adapter) {
730 ERR("OpenGL surfaces are not available without opengl\n");
731 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
732 HeapFree(GetProcessHeap(), 0, object);
733 return WINED3DERR_NOTAVAILABLE;
735 break;
737 case SURFACE_GDI:
738 object->lpVtbl = &IWineGDISurface_Vtbl;
739 break;
741 default:
742 /* To be sure to catch this */
743 ERR("Unknown requested surface implementation %d!\n", Impl);
744 IWineD3DSurface_Release((IWineD3DSurface *) object);
745 return WINED3DERR_INVALIDCALL;
748 list_init(&object->renderbuffers);
750 /* Call the private setup routine */
751 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
755 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
756 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
757 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
758 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
761 IWineD3DTextureImpl *object;
762 unsigned int i;
763 UINT tmpW;
764 UINT tmpH;
765 HRESULT hr;
766 unsigned int pow2Width;
767 unsigned int pow2Height;
768 const GlPixelFormatDesc *glDesc;
769 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
771 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
772 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
773 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
775 if((Usage & (WINED3DUSAGE_AUTOGENMIPMAP | WINED3DUSAGE_RENDERTARGET)) ==
776 (WINED3DUSAGE_AUTOGENMIPMAP | WINED3DUSAGE_RENDERTARGET)) {
777 WARN("Application requests both D3DUSAGE_AUTOGENMIPMAP and D3DUSAGE_RENDERTARGET, which are mutually exclusive\n");
778 return WINED3DERR_INVALIDCALL;
781 /* TODO: It should only be possible to create textures for formats
782 that are reported as supported */
783 if (WINED3DFMT_UNKNOWN >= Format) {
784 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
785 return WINED3DERR_INVALIDCALL;
788 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
789 D3DINITIALIZEBASETEXTURE(object->baseTexture);
790 object->width = Width;
791 object->height = Height;
793 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
794 object->baseTexture.minMipLookup = &minMipLookup;
795 object->baseTexture.magLookup = &magLookup;
796 } else {
797 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
798 object->baseTexture.magLookup = &magLookup_noFilter;
801 /** Non-power2 support **/
802 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
803 pow2Width = Width;
804 pow2Height = Height;
805 } else {
806 /* Find the nearest pow2 match */
807 pow2Width = pow2Height = 1;
808 while (pow2Width < Width) pow2Width <<= 1;
809 while (pow2Height < Height) pow2Height <<= 1;
811 if(pow2Width != Width || pow2Height != Height) {
812 if(Levels > 1) {
813 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
814 HeapFree(GetProcessHeap(), 0, object);
815 *ppTexture = NULL;
816 return WINED3DERR_INVALIDCALL;
817 } else {
818 Levels = 1;
823 /** FIXME: add support for real non-power-two if it's provided by the video card **/
824 /* Precalculated scaling for 'faked' non power of two texture coords.
825 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
826 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
827 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
829 if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
830 (Width != pow2Width || Height != pow2Height) &&
831 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
833 object->baseTexture.pow2Matrix[0] = (float)Width;
834 object->baseTexture.pow2Matrix[5] = (float)Height;
835 object->baseTexture.pow2Matrix[10] = 1.0;
836 object->baseTexture.pow2Matrix[15] = 1.0;
837 object->target = GL_TEXTURE_RECTANGLE_ARB;
838 } else {
839 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
840 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
841 object->baseTexture.pow2Matrix[10] = 1.0;
842 object->baseTexture.pow2Matrix[15] = 1.0;
843 object->target = GL_TEXTURE_2D;
845 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
847 /* Calculate levels for mip mapping */
848 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
849 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
850 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
851 return WINED3DERR_INVALIDCALL;
853 if(Levels > 1) {
854 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
855 return WINED3DERR_INVALIDCALL;
857 object->baseTexture.levels = 1;
858 } else if (Levels == 0) {
859 TRACE("calculating levels %d\n", object->baseTexture.levels);
860 object->baseTexture.levels++;
861 tmpW = Width;
862 tmpH = Height;
863 while (tmpW > 1 || tmpH > 1) {
864 tmpW = max(1, tmpW >> 1);
865 tmpH = max(1, tmpH >> 1);
866 object->baseTexture.levels++;
868 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
871 /* Generate all the surfaces */
872 tmpW = Width;
873 tmpH = Height;
874 for (i = 0; i < object->baseTexture.levels; i++)
876 /* use the callback to create the texture surface */
877 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
878 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
879 FIXME("Failed to create surface %p\n", object);
880 /* clean up */
881 object->surfaces[i] = NULL;
882 IWineD3DTexture_Release((IWineD3DTexture *)object);
884 *ppTexture = NULL;
885 return hr;
888 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
889 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
890 /* calculate the next mipmap level */
891 tmpW = max(1, tmpW >> 1);
892 tmpH = max(1, tmpH >> 1);
894 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
896 TRACE("(%p) : Created texture %p\n", This, object);
897 return WINED3D_OK;
900 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
901 UINT Width, UINT Height, UINT Depth,
902 UINT Levels, DWORD Usage,
903 WINED3DFORMAT Format, WINED3DPOOL Pool,
904 IWineD3DVolumeTexture **ppVolumeTexture,
905 HANDLE *pSharedHandle, IUnknown *parent,
906 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
909 IWineD3DVolumeTextureImpl *object;
910 unsigned int i;
911 UINT tmpW;
912 UINT tmpH;
913 UINT tmpD;
914 const GlPixelFormatDesc *glDesc;
916 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
918 /* TODO: It should only be possible to create textures for formats
919 that are reported as supported */
920 if (WINED3DFMT_UNKNOWN >= Format) {
921 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
922 return WINED3DERR_INVALIDCALL;
924 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
925 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
926 return WINED3DERR_INVALIDCALL;
929 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
930 D3DINITIALIZEBASETEXTURE(object->baseTexture);
932 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
933 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
935 object->width = Width;
936 object->height = Height;
937 object->depth = Depth;
939 /* Is NP2 support for volumes needed? */
940 object->baseTexture.pow2Matrix[ 0] = 1.0;
941 object->baseTexture.pow2Matrix[ 5] = 1.0;
942 object->baseTexture.pow2Matrix[10] = 1.0;
943 object->baseTexture.pow2Matrix[15] = 1.0;
945 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
946 object->baseTexture.minMipLookup = &minMipLookup;
947 object->baseTexture.magLookup = &magLookup;
948 } else {
949 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
950 object->baseTexture.magLookup = &magLookup_noFilter;
953 /* Calculate levels for mip mapping */
954 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
955 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
956 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
957 return WINED3DERR_INVALIDCALL;
959 if(Levels > 1) {
960 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
961 return WINED3DERR_INVALIDCALL;
963 Levels = 1;
964 } else if (Levels == 0) {
965 object->baseTexture.levels++;
966 tmpW = Width;
967 tmpH = Height;
968 tmpD = Depth;
969 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
970 tmpW = max(1, tmpW >> 1);
971 tmpH = max(1, tmpH >> 1);
972 tmpD = max(1, tmpD >> 1);
973 object->baseTexture.levels++;
975 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
978 /* Generate all the surfaces */
979 tmpW = Width;
980 tmpH = Height;
981 tmpD = Depth;
983 for (i = 0; i < object->baseTexture.levels; i++)
985 HRESULT hr;
986 /* Create the volume */
987 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
988 &object->volumes[i], pSharedHandle);
990 if(FAILED(hr)) {
991 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
992 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
993 *ppVolumeTexture = NULL;
994 return hr;
997 /* Set its container to this object */
998 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1000 /* calculate the next mipmap level */
1001 tmpW = max(1, tmpW >> 1);
1002 tmpH = max(1, tmpH >> 1);
1003 tmpD = max(1, tmpD >> 1);
1005 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1007 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1008 TRACE("(%p) : Created volume texture %p\n", This, object);
1009 return WINED3D_OK;
1012 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1013 UINT Width, UINT Height, UINT Depth,
1014 DWORD Usage,
1015 WINED3DFORMAT Format, WINED3DPOOL Pool,
1016 IWineD3DVolume** ppVolume,
1017 HANDLE* pSharedHandle, IUnknown *parent) {
1019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1020 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1021 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1023 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1024 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1025 return WINED3DERR_INVALIDCALL;
1028 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1030 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1031 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1033 object->currentDesc.Width = Width;
1034 object->currentDesc.Height = Height;
1035 object->currentDesc.Depth = Depth;
1036 object->bytesPerPixel = formatDesc->bpp;
1038 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1039 object->lockable = TRUE;
1040 object->locked = FALSE;
1041 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1042 object->dirty = TRUE;
1044 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1047 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1048 UINT Levels, DWORD Usage,
1049 WINED3DFORMAT Format, WINED3DPOOL Pool,
1050 IWineD3DCubeTexture **ppCubeTexture,
1051 HANDLE *pSharedHandle, IUnknown *parent,
1052 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1055 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1056 unsigned int i, j;
1057 UINT tmpW;
1058 HRESULT hr;
1059 unsigned int pow2EdgeLength = EdgeLength;
1060 const GlPixelFormatDesc *glDesc;
1061 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1063 if((Usage & (WINED3DUSAGE_AUTOGENMIPMAP | WINED3DUSAGE_RENDERTARGET)) ==
1064 (WINED3DUSAGE_AUTOGENMIPMAP | WINED3DUSAGE_RENDERTARGET)) {
1065 WARN("Application requests both D3DUSAGE_AUTOGENMIPMAP and D3DUSAGE_RENDERTARGET, which are mutually exclusive\n");
1066 return WINED3DERR_INVALIDCALL;
1069 /* TODO: It should only be possible to create textures for formats
1070 that are reported as supported */
1071 if (WINED3DFMT_UNKNOWN >= Format) {
1072 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1073 return WINED3DERR_INVALIDCALL;
1076 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1077 WARN("(%p) : Tried to create not supported cube texture\n", This);
1078 return WINED3DERR_INVALIDCALL;
1081 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1082 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1084 TRACE("(%p) Create Cube Texture\n", This);
1086 /** Non-power2 support **/
1088 /* Find the nearest pow2 match */
1089 pow2EdgeLength = 1;
1090 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1092 object->edgeLength = EdgeLength;
1093 /* TODO: support for native non-power 2 */
1094 /* Precalculated scaling for 'faked' non power of two texture coords */
1095 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1096 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1097 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1098 object->baseTexture.pow2Matrix[15] = 1.0;
1100 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1101 object->baseTexture.minMipLookup = &minMipLookup;
1102 object->baseTexture.magLookup = &magLookup;
1103 } else {
1104 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
1105 object->baseTexture.magLookup = &magLookup_noFilter;
1108 /* Calculate levels for mip mapping */
1109 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1110 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1111 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1112 HeapFree(GetProcessHeap(), 0, object);
1113 *ppCubeTexture = NULL;
1115 return WINED3DERR_INVALIDCALL;
1117 if(Levels > 1) {
1118 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1119 HeapFree(GetProcessHeap(), 0, object);
1120 *ppCubeTexture = NULL;
1122 return WINED3DERR_INVALIDCALL;
1124 Levels = 1;
1125 } else if (Levels == 0) {
1126 object->baseTexture.levels++;
1127 tmpW = EdgeLength;
1128 while (tmpW > 1) {
1129 tmpW = max(1, tmpW >> 1);
1130 object->baseTexture.levels++;
1132 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1135 /* Generate all the surfaces */
1136 tmpW = EdgeLength;
1137 for (i = 0; i < object->baseTexture.levels; i++) {
1139 /* Create the 6 faces */
1140 for (j = 0; j < 6; j++) {
1142 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1143 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1145 if(hr!= WINED3D_OK) {
1146 /* clean up */
1147 int k;
1148 int l;
1149 for (l = 0; l < j; l++) {
1150 IWineD3DSurface_Release(object->surfaces[l][i]);
1152 for (k = 0; k < i; k++) {
1153 for (l = 0; l < 6; l++) {
1154 IWineD3DSurface_Release(object->surfaces[l][k]);
1158 FIXME("(%p) Failed to create surface\n",object);
1159 HeapFree(GetProcessHeap(),0,object);
1160 *ppCubeTexture = NULL;
1161 return hr;
1163 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1164 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1166 tmpW = max(1, tmpW >> 1);
1168 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1170 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1171 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1172 return WINED3D_OK;
1175 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1177 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1178 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1179 const IWineD3DQueryVtbl *vtable;
1181 /* Just a check to see if we support this type of query */
1182 switch(Type) {
1183 case WINED3DQUERYTYPE_OCCLUSION:
1184 TRACE("(%p) occlusion query\n", This);
1185 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1186 hr = WINED3D_OK;
1187 else
1188 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1190 vtable = &IWineD3DOcclusionQuery_Vtbl;
1191 break;
1193 case WINED3DQUERYTYPE_EVENT:
1194 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1195 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1196 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1198 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1200 vtable = &IWineD3DEventQuery_Vtbl;
1201 hr = WINED3D_OK;
1202 break;
1204 case WINED3DQUERYTYPE_VCACHE:
1205 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1206 case WINED3DQUERYTYPE_VERTEXSTATS:
1207 case WINED3DQUERYTYPE_TIMESTAMP:
1208 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1209 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1210 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1211 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1212 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1213 case WINED3DQUERYTYPE_PIXELTIMINGS:
1214 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1215 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1216 default:
1217 /* Use the base Query vtable until we have a special one for each query */
1218 vtable = &IWineD3DQuery_Vtbl;
1219 FIXME("(%p) Unhandled query type %d\n", This, Type);
1221 if(NULL == ppQuery || hr != WINED3D_OK) {
1222 return hr;
1225 D3DCREATEOBJECTINSTANCE(object, Query)
1226 object->lpVtbl = vtable;
1227 object->type = Type;
1228 object->state = QUERY_CREATED;
1229 /* allocated the 'extended' data based on the type of query requested */
1230 switch(Type){
1231 case WINED3DQUERYTYPE_OCCLUSION:
1232 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1233 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1235 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1236 TRACE("(%p) Allocating data for an occlusion query\n", This);
1237 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1238 break;
1240 case WINED3DQUERYTYPE_EVENT:
1241 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1242 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1244 if(GL_SUPPORT(APPLE_FENCE)) {
1245 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1246 checkGLcall("glGenFencesAPPLE");
1247 } else if(GL_SUPPORT(NV_FENCE)) {
1248 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1249 checkGLcall("glGenFencesNV");
1251 break;
1253 case WINED3DQUERYTYPE_VCACHE:
1254 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1255 case WINED3DQUERYTYPE_VERTEXSTATS:
1256 case WINED3DQUERYTYPE_TIMESTAMP:
1257 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1258 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1259 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1260 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1261 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1262 case WINED3DQUERYTYPE_PIXELTIMINGS:
1263 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1264 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1265 default:
1266 object->extendedData = 0;
1267 FIXME("(%p) Unhandled query type %d\n",This , Type);
1269 TRACE("(%p) : Created Query %p\n", This, object);
1270 return WINED3D_OK;
1273 /*****************************************************************************
1274 * IWineD3DDeviceImpl_SetupFullscreenWindow
1276 * Helper function that modifies a HWND's Style and ExStyle for proper
1277 * fullscreen use.
1279 * Params:
1280 * iface: Pointer to the IWineD3DDevice interface
1281 * window: Window to setup
1283 *****************************************************************************/
1284 static LONG fullscreen_style(LONG orig_style) {
1285 LONG style = orig_style;
1286 style &= ~WS_CAPTION;
1287 style &= ~WS_THICKFRAME;
1289 /* Make sure the window is managed, otherwise we won't get keyboard input */
1290 style |= WS_POPUP | WS_SYSMENU;
1292 return style;
1295 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1296 LONG exStyle = orig_exStyle;
1298 /* Filter out window decorations */
1299 exStyle &= ~WS_EX_WINDOWEDGE;
1300 exStyle &= ~WS_EX_CLIENTEDGE;
1302 return exStyle;
1305 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1308 LONG style, exStyle;
1309 /* Don't do anything if an original style is stored.
1310 * That shouldn't happen
1312 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1313 if (This->style || This->exStyle) {
1314 ERR("(%p): Want to change the window parameters of HWND %p, but "
1315 "another style is stored for restoration afterwards\n", This, window);
1318 /* Get the parameters and save them */
1319 style = GetWindowLongW(window, GWL_STYLE);
1320 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1321 This->style = style;
1322 This->exStyle = exStyle;
1324 style = fullscreen_style(style);
1325 exStyle = fullscreen_exStyle(exStyle);
1327 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1328 This->style, This->exStyle, style, exStyle);
1330 SetWindowLongW(window, GWL_STYLE, style);
1331 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1333 /* Inform the window about the update. */
1334 SetWindowPos(window, HWND_TOP, 0, 0,
1335 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1336 ShowWindow(window, SW_NORMAL);
1339 /*****************************************************************************
1340 * IWineD3DDeviceImpl_RestoreWindow
1342 * Helper function that restores a windows' properties when taking it out
1343 * of fullscreen mode
1345 * Params:
1346 * iface: Pointer to the IWineD3DDevice interface
1347 * window: Window to setup
1349 *****************************************************************************/
1350 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1352 LONG style, exStyle;
1354 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1355 * switch, do nothing
1357 if (!This->style && !This->exStyle) return;
1359 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1360 This, window, This->style, This->exStyle);
1362 style = GetWindowLongW(window, GWL_STYLE);
1363 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1365 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1366 * Some applications change it before calling Reset() when switching between windowed and
1367 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1369 if(style == fullscreen_style(This->style) &&
1370 exStyle == fullscreen_style(This->exStyle)) {
1371 SetWindowLongW(window, GWL_STYLE, This->style);
1372 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1375 /* Delete the old values */
1376 This->style = 0;
1377 This->exStyle = 0;
1379 /* Inform the window about the update */
1380 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1381 0, 0, 0, 0, /* Pos, Size, ignored */
1382 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1385 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1386 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1387 IUnknown* parent,
1388 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1389 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1392 HDC hDc;
1393 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1394 HRESULT hr = WINED3D_OK;
1395 IUnknown *bufferParent;
1396 BOOL displaymode_set = FALSE;
1397 WINED3DDISPLAYMODE Mode;
1398 const StaticPixelFormatDesc *formatDesc;
1400 TRACE("(%p) : Created Additional Swap Chain\n", This);
1402 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1403 * does a device hold a reference to a swap chain giving them a lifetime of the device
1404 * or does the swap chain notify the device of its destruction.
1405 *******************************/
1407 /* Check the params */
1408 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1409 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1410 return WINED3DERR_INVALIDCALL;
1411 } else if (pPresentationParameters->BackBufferCount > 1) {
1412 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");
1415 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1417 /*********************
1418 * Lookup the window Handle and the relating X window handle
1419 ********************/
1421 /* Setup hwnd we are using, plus which display this equates to */
1422 object->win_handle = pPresentationParameters->hDeviceWindow;
1423 if (!object->win_handle) {
1424 object->win_handle = This->createParms.hFocusWindow;
1426 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1428 hDc = GetDC(object->win_handle);
1429 TRACE("Using hDc %p\n", hDc);
1431 if (NULL == hDc) {
1432 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1433 return WINED3DERR_NOTAVAILABLE;
1436 /* Get info on the current display setup */
1437 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1438 object->orig_width = Mode.Width;
1439 object->orig_height = Mode.Height;
1440 object->orig_fmt = Mode.Format;
1441 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1443 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1444 * then the corresponding dimension of the client area of the hDeviceWindow
1445 * (or the focus window, if hDeviceWindow is NULL) is taken.
1446 **********************/
1448 if (pPresentationParameters->Windowed &&
1449 ((pPresentationParameters->BackBufferWidth == 0) ||
1450 (pPresentationParameters->BackBufferHeight == 0) ||
1451 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1453 RECT Rect;
1454 GetClientRect(object->win_handle, &Rect);
1456 if (pPresentationParameters->BackBufferWidth == 0) {
1457 pPresentationParameters->BackBufferWidth = Rect.right;
1458 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1460 if (pPresentationParameters->BackBufferHeight == 0) {
1461 pPresentationParameters->BackBufferHeight = Rect.bottom;
1462 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1464 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1465 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1466 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1470 /* Put the correct figures in the presentation parameters */
1471 TRACE("Copying across presentation parameters\n");
1472 object->presentParms = *pPresentationParameters;
1474 TRACE("calling rendertarget CB\n");
1475 hr = D3DCB_CreateRenderTarget(This->parent,
1476 parent,
1477 object->presentParms.BackBufferWidth,
1478 object->presentParms.BackBufferHeight,
1479 object->presentParms.BackBufferFormat,
1480 object->presentParms.MultiSampleType,
1481 object->presentParms.MultiSampleQuality,
1482 TRUE /* Lockable */,
1483 &object->frontBuffer,
1484 NULL /* pShared (always null)*/);
1485 if (object->frontBuffer != NULL) {
1486 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1487 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1488 } else {
1489 ERR("Failed to create the front buffer\n");
1490 goto error;
1493 /*********************
1494 * Windowed / Fullscreen
1495 *******************/
1498 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1499 * so we should really check to see if there is a fullscreen swapchain already
1500 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1501 **************************************/
1503 if (!pPresentationParameters->Windowed) {
1504 WINED3DDISPLAYMODE mode;
1507 /* Change the display settings */
1508 mode.Width = pPresentationParameters->BackBufferWidth;
1509 mode.Height = pPresentationParameters->BackBufferHeight;
1510 mode.Format = pPresentationParameters->BackBufferFormat;
1511 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1513 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1514 displaymode_set = TRUE;
1515 IWineD3DDevice_SetFullscreen(iface, TRUE);
1519 * Create an opengl context for the display visual
1520 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1521 * use different properties after that point in time. FIXME: How to handle when requested format
1522 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1523 * it chooses is identical to the one already being used!
1524 **********************************/
1525 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1527 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1528 if(!object->context)
1529 return E_OUTOFMEMORY;
1530 object->num_contexts = 1;
1532 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1533 if (!object->context[0]) {
1534 ERR("Failed to create a new context\n");
1535 hr = WINED3DERR_NOTAVAILABLE;
1536 goto error;
1537 } else {
1538 TRACE("Context created (HWND=%p, glContext=%p)\n",
1539 object->win_handle, object->context[0]->glCtx);
1542 /*********************
1543 * Create the back, front and stencil buffers
1544 *******************/
1545 if(object->presentParms.BackBufferCount > 0) {
1546 int i;
1548 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1549 if(!object->backBuffer) {
1550 ERR("Out of memory\n");
1551 hr = E_OUTOFMEMORY;
1552 goto error;
1555 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1556 TRACE("calling rendertarget CB\n");
1557 hr = D3DCB_CreateRenderTarget(This->parent,
1558 parent,
1559 object->presentParms.BackBufferWidth,
1560 object->presentParms.BackBufferHeight,
1561 object->presentParms.BackBufferFormat,
1562 object->presentParms.MultiSampleType,
1563 object->presentParms.MultiSampleQuality,
1564 TRUE /* Lockable */,
1565 &object->backBuffer[i],
1566 NULL /* pShared (always null)*/);
1567 if(hr == WINED3D_OK && object->backBuffer[i]) {
1568 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1569 } else {
1570 ERR("Cannot create new back buffer\n");
1571 goto error;
1573 ENTER_GL();
1574 glDrawBuffer(GL_BACK);
1575 checkGLcall("glDrawBuffer(GL_BACK)");
1576 LEAVE_GL();
1578 } else {
1579 object->backBuffer = NULL;
1581 /* Single buffering - draw to front buffer */
1582 ENTER_GL();
1583 glDrawBuffer(GL_FRONT);
1584 checkGLcall("glDrawBuffer(GL_FRONT)");
1585 LEAVE_GL();
1588 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1589 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1590 TRACE("Creating depth stencil buffer\n");
1591 if (This->auto_depth_stencil_buffer == NULL ) {
1592 hr = D3DCB_CreateDepthStencil(This->parent,
1593 parent,
1594 object->presentParms.BackBufferWidth,
1595 object->presentParms.BackBufferHeight,
1596 object->presentParms.AutoDepthStencilFormat,
1597 object->presentParms.MultiSampleType,
1598 object->presentParms.MultiSampleQuality,
1599 FALSE /* FIXME: Discard */,
1600 &This->auto_depth_stencil_buffer,
1601 NULL /* pShared (always null)*/ );
1602 if (This->auto_depth_stencil_buffer != NULL)
1603 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1606 /** TODO: A check on width, height and multisample types
1607 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1608 ****************************/
1609 object->wantsDepthStencilBuffer = TRUE;
1610 } else {
1611 object->wantsDepthStencilBuffer = FALSE;
1614 TRACE("Created swapchain %p\n", object);
1615 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1616 return WINED3D_OK;
1618 error:
1619 if (displaymode_set) {
1620 DEVMODEW devmode;
1621 RECT clip_rc;
1623 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1624 ClipCursor(NULL);
1626 /* Change the display settings */
1627 memset(&devmode, 0, sizeof(devmode));
1628 devmode.dmSize = sizeof(devmode);
1629 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1630 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1631 devmode.dmPelsWidth = object->orig_width;
1632 devmode.dmPelsHeight = object->orig_height;
1633 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1636 if (object->backBuffer) {
1637 int i;
1638 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1639 if(object->backBuffer[i]) {
1640 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1641 IUnknown_Release(bufferParent); /* once for the get parent */
1642 if (IUnknown_Release(bufferParent) > 0) {
1643 FIXME("(%p) Something's still holding the back buffer\n",This);
1647 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1648 object->backBuffer = NULL;
1650 if(object->context[0])
1651 DestroyContext(This, object->context[0]);
1652 if(object->frontBuffer) {
1653 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1654 IUnknown_Release(bufferParent); /* once for the get parent */
1655 if (IUnknown_Release(bufferParent) > 0) {
1656 FIXME("(%p) Something's still holding the front buffer\n",This);
1659 HeapFree(GetProcessHeap(), 0, object);
1660 return hr;
1663 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1664 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1666 TRACE("(%p)\n", This);
1668 return This->NumberOfSwapChains;
1671 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1673 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1675 if(iSwapChain < This->NumberOfSwapChains) {
1676 *pSwapChain = This->swapchains[iSwapChain];
1677 IWineD3DSwapChain_AddRef(*pSwapChain);
1678 TRACE("(%p) returning %p\n", This, *pSwapChain);
1679 return WINED3D_OK;
1680 } else {
1681 TRACE("Swapchain out of range\n");
1682 *pSwapChain = NULL;
1683 return WINED3DERR_INVALIDCALL;
1687 /*****
1688 * Vertex Declaration
1689 *****/
1690 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1691 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1693 IWineD3DVertexDeclarationImpl *object = NULL;
1694 HRESULT hr = WINED3D_OK;
1696 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1697 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1699 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1701 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1702 if(FAILED(hr)) {
1703 *ppVertexDeclaration = NULL;
1704 HeapFree(GetProcessHeap(), 0, object);
1707 return hr;
1710 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1711 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1713 unsigned int idx, idx2;
1714 unsigned int offset;
1715 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1716 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1717 BOOL has_blend_idx = has_blend &&
1718 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1719 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1720 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1721 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1722 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1723 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1724 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1726 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1727 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1729 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1730 WINED3DVERTEXELEMENT *elements = NULL;
1732 unsigned int size;
1733 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1734 if (has_blend_idx) num_blends--;
1736 /* Compute declaration size */
1737 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1738 has_psize + has_diffuse + has_specular + num_textures + 1;
1740 /* convert the declaration */
1741 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1742 if (!elements)
1743 return 0;
1745 elements[size-1] = end_element;
1746 idx = 0;
1747 if (has_pos) {
1748 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1749 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1750 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1752 else {
1753 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1754 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1756 elements[idx].UsageIndex = 0;
1757 idx++;
1759 if (has_blend && (num_blends > 0)) {
1760 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1761 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1762 else
1763 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1764 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1765 elements[idx].UsageIndex = 0;
1766 idx++;
1768 if (has_blend_idx) {
1769 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1770 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1771 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1772 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1773 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1774 else
1775 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1776 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1777 elements[idx].UsageIndex = 0;
1778 idx++;
1780 if (has_normal) {
1781 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1782 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1783 elements[idx].UsageIndex = 0;
1784 idx++;
1786 if (has_psize) {
1787 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1788 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1789 elements[idx].UsageIndex = 0;
1790 idx++;
1792 if (has_diffuse) {
1793 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1794 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1795 elements[idx].UsageIndex = 0;
1796 idx++;
1798 if (has_specular) {
1799 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1800 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1801 elements[idx].UsageIndex = 1;
1802 idx++;
1804 for (idx2 = 0; idx2 < num_textures; idx2++) {
1805 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1806 switch (numcoords) {
1807 case WINED3DFVF_TEXTUREFORMAT1:
1808 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1809 break;
1810 case WINED3DFVF_TEXTUREFORMAT2:
1811 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1812 break;
1813 case WINED3DFVF_TEXTUREFORMAT3:
1814 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1815 break;
1816 case WINED3DFVF_TEXTUREFORMAT4:
1817 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1818 break;
1820 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1821 elements[idx].UsageIndex = idx2;
1822 idx++;
1825 /* Now compute offsets, and initialize the rest of the fields */
1826 for (idx = 0, offset = 0; idx < size-1; idx++) {
1827 elements[idx].Stream = 0;
1828 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1829 elements[idx].Offset = offset;
1830 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1833 *ppVertexElements = elements;
1834 return size;
1837 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1838 WINED3DVERTEXELEMENT* elements = NULL;
1839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1840 unsigned int size;
1841 DWORD hr;
1843 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1844 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1846 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1847 HeapFree(GetProcessHeap(), 0, elements);
1848 if (hr != S_OK) return hr;
1850 return WINED3D_OK;
1853 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1854 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1855 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1856 HRESULT hr = WINED3D_OK;
1857 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1858 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1860 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1862 if (vertex_declaration) {
1863 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1866 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1868 if (WINED3D_OK != hr) {
1869 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1870 IWineD3DVertexShader_Release(*ppVertexShader);
1871 return WINED3DERR_INVALIDCALL;
1873 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1875 return WINED3D_OK;
1878 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1880 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1881 HRESULT hr = WINED3D_OK;
1883 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1884 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1885 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1886 if (WINED3D_OK == hr) {
1887 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1888 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1889 } else {
1890 WARN("(%p) : Failed to create pixel shader\n", This);
1893 return hr;
1896 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1898 IWineD3DPaletteImpl *object;
1899 HRESULT hr;
1900 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1902 /* Create the new object */
1903 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1904 if(!object) {
1905 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1906 return E_OUTOFMEMORY;
1909 object->lpVtbl = &IWineD3DPalette_Vtbl;
1910 object->ref = 1;
1911 object->Flags = Flags;
1912 object->parent = Parent;
1913 object->wineD3DDevice = This;
1914 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1916 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1918 if(!object->hpal) {
1919 HeapFree( GetProcessHeap(), 0, object);
1920 return E_OUTOFMEMORY;
1923 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1924 if(FAILED(hr)) {
1925 IWineD3DPalette_Release((IWineD3DPalette *) object);
1926 return hr;
1929 *Palette = (IWineD3DPalette *) object;
1931 return WINED3D_OK;
1934 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1935 HBITMAP hbm;
1936 BITMAP bm;
1937 HRESULT hr;
1938 HDC dcb = NULL, dcs = NULL;
1939 WINEDDCOLORKEY colorkey;
1941 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1942 if(hbm)
1944 GetObjectA(hbm, sizeof(BITMAP), &bm);
1945 dcb = CreateCompatibleDC(NULL);
1946 if(!dcb) goto out;
1947 SelectObject(dcb, hbm);
1949 else
1951 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1952 * couldn't be loaded
1954 memset(&bm, 0, sizeof(bm));
1955 bm.bmWidth = 32;
1956 bm.bmHeight = 32;
1959 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1960 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1961 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1962 if(FAILED(hr)) {
1963 ERR("Wine logo requested, but failed to create surface\n");
1964 goto out;
1967 if(dcb) {
1968 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1969 if(FAILED(hr)) goto out;
1970 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1971 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1973 colorkey.dwColorSpaceLowValue = 0;
1974 colorkey.dwColorSpaceHighValue = 0;
1975 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1976 } else {
1977 /* Fill the surface with a white color to show that wined3d is there */
1978 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1981 out:
1982 if(dcb) {
1983 DeleteDC(dcb);
1985 if(hbm) {
1986 DeleteObject(hbm);
1988 return;
1991 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1992 unsigned int i;
1993 /* Under DirectX you can have texture stage operations even if no texture is
1994 bound, whereas opengl will only do texture operations when a valid texture is
1995 bound. We emulate this by creating dummy textures and binding them to each
1996 texture stage, but disable all stages by default. Hence if a stage is enabled
1997 then the default texture will kick in until replaced by a SetTexture call */
1998 ENTER_GL();
2000 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2001 /* The dummy texture does not have client storage backing */
2002 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2003 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2005 for (i = 0; i < GL_LIMITS(textures); i++) {
2006 GLubyte white = 255;
2008 /* Make appropriate texture active */
2009 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2010 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2011 checkGLcall("glActiveTextureARB");
2012 } else if (i > 0) {
2013 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2016 /* Generate an opengl texture name */
2017 glGenTextures(1, &This->dummyTextureName[i]);
2018 checkGLcall("glGenTextures");
2019 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2021 /* Generate a dummy 2d texture (not using 1d because they cause many
2022 * DRI drivers fall back to sw) */
2023 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2024 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2025 checkGLcall("glBindTexture");
2027 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2028 checkGLcall("glTexImage2D");
2030 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2031 /* Reenable because if supported it is enabled by default */
2032 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2033 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2036 LEAVE_GL();
2039 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2041 IWineD3DSwapChainImpl *swapchain = NULL;
2042 HRESULT hr;
2043 DWORD state;
2044 unsigned int i;
2046 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2047 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2048 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2050 /* TODO: Test if OpenGL is compiled in and loaded */
2052 TRACE("(%p) : Creating stateblock\n", This);
2053 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2054 hr = IWineD3DDevice_CreateStateBlock(iface,
2055 WINED3DSBT_INIT,
2056 (IWineD3DStateBlock **)&This->stateBlock,
2057 NULL);
2058 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2059 WARN("Failed to create stateblock\n");
2060 goto err_out;
2062 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2063 This->updateStateBlock = This->stateBlock;
2064 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2066 hr = allocate_shader_constants(This->updateStateBlock);
2067 if (WINED3D_OK != hr) {
2068 goto err_out;
2071 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2072 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2073 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2075 This->NumberOfPalettes = 1;
2076 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2077 if(!This->palettes || !This->render_targets || !This->fbo_color_attachments || !This->draw_buffers) {
2078 ERR("Out of memory!\n");
2079 goto err_out;
2081 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2082 if(!This->palettes[0]) {
2083 ERR("Out of memory!\n");
2084 goto err_out;
2086 for (i = 0; i < 256; ++i) {
2087 This->palettes[0][i].peRed = 0xFF;
2088 This->palettes[0][i].peGreen = 0xFF;
2089 This->palettes[0][i].peBlue = 0xFF;
2090 This->palettes[0][i].peFlags = 0xFF;
2092 This->currentPalette = 0;
2094 /* Initialize the texture unit mapping to a 1:1 mapping */
2095 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2096 if (state < GL_LIMITS(fragment_samplers)) {
2097 This->texUnitMap[state] = state;
2098 This->rev_tex_unit_map[state] = state;
2099 } else {
2100 This->texUnitMap[state] = -1;
2101 This->rev_tex_unit_map[state] = -1;
2105 /* Setup the implicit swapchain */
2106 TRACE("Creating implicit swapchain\n");
2107 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2108 if (FAILED(hr) || !swapchain) {
2109 WARN("Failed to create implicit swapchain\n");
2110 goto err_out;
2113 This->NumberOfSwapChains = 1;
2114 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2115 if(!This->swapchains) {
2116 ERR("Out of memory!\n");
2117 goto err_out;
2119 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2121 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2122 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2123 This->render_targets[0] = swapchain->backBuffer[0];
2124 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2126 else {
2127 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2128 This->render_targets[0] = swapchain->frontBuffer;
2129 This->lastActiveRenderTarget = swapchain->frontBuffer;
2131 IWineD3DSurface_AddRef(This->render_targets[0]);
2132 This->activeContext = swapchain->context[0];
2133 This->lastThread = GetCurrentThreadId();
2135 /* Depth Stencil support */
2136 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2137 if (NULL != This->stencilBufferTarget) {
2138 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2141 hr = This->shader_backend->shader_alloc_private(iface);
2142 if(FAILED(hr)) {
2143 TRACE("Shader private data couldn't be allocated\n");
2144 goto err_out;
2147 /* Set up some starting GL setup */
2149 /* Setup all the devices defaults */
2150 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2151 create_dummy_textures(This);
2153 ENTER_GL();
2155 #if 0
2156 IWineD3DImpl_CheckGraphicsMemory();
2157 #endif
2159 { /* Set a default viewport */
2160 WINED3DVIEWPORT vp;
2161 vp.X = 0;
2162 vp.Y = 0;
2163 vp.Width = pPresentationParameters->BackBufferWidth;
2164 vp.Height = pPresentationParameters->BackBufferHeight;
2165 vp.MinZ = 0.0f;
2166 vp.MaxZ = 1.0f;
2167 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2170 /* Initialize the current view state */
2171 This->view_ident = 1;
2172 This->contexts[0]->last_was_rhw = 0;
2173 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2174 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2176 switch(wined3d_settings.offscreen_rendering_mode) {
2177 case ORM_FBO:
2178 case ORM_PBUFFER:
2179 This->offscreenBuffer = GL_BACK;
2180 break;
2182 case ORM_BACKBUFFER:
2184 if(This->activeContext->aux_buffers > 0) {
2185 TRACE("Using auxilliary buffer for offscreen rendering\n");
2186 This->offscreenBuffer = GL_AUX0;
2187 } else {
2188 TRACE("Using back buffer for offscreen rendering\n");
2189 This->offscreenBuffer = GL_BACK;
2194 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2195 LEAVE_GL();
2197 /* Clear the screen */
2198 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2199 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2200 0x00, 1.0, 0);
2202 This->d3d_initialized = TRUE;
2204 if(wined3d_settings.logo) {
2205 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2207 This->highest_dirty_ps_const = 0;
2208 This->highest_dirty_vs_const = 0;
2209 return WINED3D_OK;
2211 err_out:
2212 This->shader_backend->shader_free_private(iface);
2213 HeapFree(GetProcessHeap(), 0, This->render_targets);
2214 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2215 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2216 HeapFree(GetProcessHeap(), 0, This->swapchains);
2217 This->NumberOfSwapChains = 0;
2218 if(This->palettes) {
2219 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2220 HeapFree(GetProcessHeap(), 0, This->palettes);
2222 This->NumberOfPalettes = 0;
2223 if(swapchain) {
2224 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2226 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2227 if(This->stateBlock) {
2228 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2229 This->stateBlock = NULL;
2231 return hr;
2234 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2236 int sampler;
2237 UINT i;
2238 TRACE("(%p)\n", This);
2240 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2242 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2243 * it was created. Thus make sure a context is active for the glDelete* calls
2245 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2247 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2249 TRACE("Deleting high order patches\n");
2250 for(i = 0; i < PATCHMAP_SIZE; i++) {
2251 struct list *e1, *e2;
2252 struct WineD3DRectPatch *patch;
2253 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2254 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2255 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2259 /* Delete the palette conversion shader if it is around */
2260 if(This->paletteConversionShader) {
2261 ENTER_GL();
2262 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2263 LEAVE_GL();
2264 This->paletteConversionShader = 0;
2267 /* Delete the pbuffer context if there is any */
2268 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2270 /* Delete the mouse cursor texture */
2271 if(This->cursorTexture) {
2272 ENTER_GL();
2273 glDeleteTextures(1, &This->cursorTexture);
2274 LEAVE_GL();
2275 This->cursorTexture = 0;
2278 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2279 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2281 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2282 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2285 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2286 * private data, it might contain opengl pointers
2288 This->shader_backend->shader_destroy_depth_blt(iface);
2289 This->shader_backend->shader_free_private(iface);
2291 /* Release the update stateblock */
2292 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2293 if(This->updateStateBlock != This->stateBlock)
2294 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2296 This->updateStateBlock = NULL;
2298 { /* because were not doing proper internal refcounts releasing the primary state block
2299 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2300 to set this->stateBlock = NULL; first */
2301 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2302 This->stateBlock = NULL;
2304 /* Release the stateblock */
2305 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2306 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2310 /* Release the buffers (with sanity checks)*/
2311 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2312 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2313 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2314 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2316 This->stencilBufferTarget = NULL;
2318 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2319 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2320 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2322 TRACE("Setting rendertarget to NULL\n");
2323 This->render_targets[0] = NULL;
2325 if (This->auto_depth_stencil_buffer) {
2326 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2327 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2329 This->auto_depth_stencil_buffer = NULL;
2332 for(i=0; i < This->NumberOfSwapChains; i++) {
2333 TRACE("Releasing the implicit swapchain %d\n", i);
2334 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2335 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2339 HeapFree(GetProcessHeap(), 0, This->swapchains);
2340 This->swapchains = NULL;
2341 This->NumberOfSwapChains = 0;
2343 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2344 HeapFree(GetProcessHeap(), 0, This->palettes);
2345 This->palettes = NULL;
2346 This->NumberOfPalettes = 0;
2348 HeapFree(GetProcessHeap(), 0, This->render_targets);
2349 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2350 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2351 This->render_targets = NULL;
2352 This->fbo_color_attachments = NULL;
2353 This->draw_buffers = NULL;
2355 This->d3d_initialized = FALSE;
2356 return WINED3D_OK;
2359 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2361 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2363 /* Setup the window for fullscreen mode */
2364 if(fullscreen && !This->ddraw_fullscreen) {
2365 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2366 } else if(!fullscreen && This->ddraw_fullscreen) {
2367 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2370 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2371 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2372 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2373 * separately.
2375 This->ddraw_fullscreen = fullscreen;
2378 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2379 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2380 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2382 * There is no way to deactivate thread safety once it is enabled.
2384 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2387 /*For now just store the flag(needed in case of ddraw) */
2388 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2390 return;
2393 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2394 DEVMODEW devmode;
2395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2396 LONG ret;
2397 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2398 RECT clip_rc;
2400 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2402 /* Resize the screen even without a window:
2403 * The app could have unset it with SetCooperativeLevel, but not called
2404 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2405 * but we don't have any hwnd
2408 memset(&devmode, 0, sizeof(devmode));
2409 devmode.dmSize = sizeof(devmode);
2410 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2411 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2412 devmode.dmPelsWidth = pMode->Width;
2413 devmode.dmPelsHeight = pMode->Height;
2415 devmode.dmDisplayFrequency = pMode->RefreshRate;
2416 if (pMode->RefreshRate != 0) {
2417 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2420 /* Only change the mode if necessary */
2421 if( (This->ddraw_width == pMode->Width) &&
2422 (This->ddraw_height == pMode->Height) &&
2423 (This->ddraw_format == pMode->Format) &&
2424 (pMode->RefreshRate == 0) ) {
2425 return WINED3D_OK;
2428 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2429 if (ret != DISP_CHANGE_SUCCESSFUL) {
2430 if(devmode.dmDisplayFrequency != 0) {
2431 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2432 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2433 devmode.dmDisplayFrequency = 0;
2434 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2436 if(ret != DISP_CHANGE_SUCCESSFUL) {
2437 return WINED3DERR_NOTAVAILABLE;
2441 /* Store the new values */
2442 This->ddraw_width = pMode->Width;
2443 This->ddraw_height = pMode->Height;
2444 This->ddraw_format = pMode->Format;
2446 /* Only do this with a window of course, and only if we're fullscreened */
2447 if(This->ddraw_window && This->ddraw_fullscreen)
2448 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2450 /* And finally clip mouse to our screen */
2451 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2452 ClipCursor(&clip_rc);
2454 return WINED3D_OK;
2457 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2459 *ppD3D= This->wineD3D;
2460 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2461 IWineD3D_AddRef(*ppD3D);
2462 return WINED3D_OK;
2465 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2468 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2469 (This->adapter->TextureRam/(1024*1024)),
2470 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2471 /* return simulated texture memory left */
2472 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2477 /*****
2478 * Get / Set FVF
2479 *****/
2480 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2483 /* Update the current state block */
2484 This->updateStateBlock->changed.fvf = TRUE;
2486 if(This->updateStateBlock->fvf == fvf) {
2487 TRACE("Application is setting the old fvf over, nothing to do\n");
2488 return WINED3D_OK;
2491 This->updateStateBlock->fvf = fvf;
2492 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2493 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2494 return WINED3D_OK;
2498 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2499 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2500 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2501 *pfvf = This->stateBlock->fvf;
2502 return WINED3D_OK;
2505 /*****
2506 * Get / Set Stream Source
2507 *****/
2508 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2510 IWineD3DVertexBuffer *oldSrc;
2512 if (StreamNumber >= MAX_STREAMS) {
2513 WARN("Stream out of range %d\n", StreamNumber);
2514 return WINED3DERR_INVALIDCALL;
2515 } else if(OffsetInBytes & 0x3) {
2516 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2517 return WINED3DERR_INVALIDCALL;
2520 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2521 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2523 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2525 if(oldSrc == pStreamData &&
2526 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2527 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2528 TRACE("Application is setting the old values over, nothing to do\n");
2529 return WINED3D_OK;
2532 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2533 if (pStreamData) {
2534 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2535 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2538 /* Handle recording of state blocks */
2539 if (This->isRecordingState) {
2540 TRACE("Recording... not performing anything\n");
2541 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2542 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2543 return WINED3D_OK;
2546 /* Need to do a getParent and pass the references up */
2547 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2548 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2549 so for now, just count internally */
2550 if (pStreamData != NULL) {
2551 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2552 InterlockedIncrement(&vbImpl->bindCount);
2553 IWineD3DVertexBuffer_AddRef(pStreamData);
2555 if (oldSrc != NULL) {
2556 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2557 IWineD3DVertexBuffer_Release(oldSrc);
2560 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2562 return WINED3D_OK;
2565 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2566 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2568 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2569 This->stateBlock->streamSource[StreamNumber],
2570 This->stateBlock->streamOffset[StreamNumber],
2571 This->stateBlock->streamStride[StreamNumber]);
2573 if (StreamNumber >= MAX_STREAMS) {
2574 WARN("Stream out of range %d\n", StreamNumber);
2575 return WINED3DERR_INVALIDCALL;
2577 *pStream = This->stateBlock->streamSource[StreamNumber];
2578 *pStride = This->stateBlock->streamStride[StreamNumber];
2579 if (pOffset) {
2580 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2583 if (*pStream != NULL) {
2584 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2586 return WINED3D_OK;
2589 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2591 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2592 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2594 /* Verify input at least in d3d9 this is invalid*/
2595 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2596 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2597 return WINED3DERR_INVALIDCALL;
2599 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2600 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2601 return WINED3DERR_INVALIDCALL;
2603 if( Divider == 0 ){
2604 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2605 return WINED3DERR_INVALIDCALL;
2608 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2609 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2611 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2612 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2614 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2615 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2616 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2619 return WINED3D_OK;
2622 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2625 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2626 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2628 TRACE("(%p) : returning %d\n", This, *Divider);
2630 return WINED3D_OK;
2633 /*****
2634 * Get / Set & Multiply Transform
2635 *****/
2636 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2639 /* Most of this routine, comments included copied from ddraw tree initially: */
2640 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2642 /* Handle recording of state blocks */
2643 if (This->isRecordingState) {
2644 TRACE("Recording... not performing anything\n");
2645 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2646 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2647 return WINED3D_OK;
2651 * If the new matrix is the same as the current one,
2652 * we cut off any further processing. this seems to be a reasonable
2653 * optimization because as was noticed, some apps (warcraft3 for example)
2654 * tend towards setting the same matrix repeatedly for some reason.
2656 * From here on we assume that the new matrix is different, wherever it matters.
2658 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2659 TRACE("The app is setting the same matrix over again\n");
2660 return WINED3D_OK;
2661 } else {
2662 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2666 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2667 where ViewMat = Camera space, WorldMat = world space.
2669 In OpenGL, camera and world space is combined into GL_MODELVIEW
2670 matrix. The Projection matrix stay projection matrix.
2673 /* Capture the times we can just ignore the change for now */
2674 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2675 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2676 /* Handled by the state manager */
2679 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2680 return WINED3D_OK;
2683 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2685 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2686 *pMatrix = This->stateBlock->transforms[State];
2687 return WINED3D_OK;
2690 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2691 WINED3DMATRIX *mat = NULL;
2692 WINED3DMATRIX temp;
2694 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2695 * below means it will be recorded in a state block change, but it
2696 * works regardless where it is recorded.
2697 * If this is found to be wrong, change to StateBlock.
2699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2700 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2702 if (State < HIGHEST_TRANSFORMSTATE)
2704 mat = &This->updateStateBlock->transforms[State];
2705 } else {
2706 FIXME("Unhandled transform state!!\n");
2709 multiply_matrix(&temp, mat, pMatrix);
2711 /* Apply change via set transform - will reapply to eg. lights this way */
2712 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2715 /*****
2716 * Get / Set Light
2717 *****/
2718 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2719 you can reference any indexes you want as long as that number max are enabled at any
2720 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2721 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2722 but when recording, just build a chain pretty much of commands to be replayed. */
2724 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2725 float rho;
2726 PLIGHTINFOEL *object = NULL;
2727 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2728 struct list *e;
2730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2731 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2733 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2734 * the gl driver.
2736 if(!pLight) {
2737 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2738 return WINED3DERR_INVALIDCALL;
2741 switch(pLight->Type) {
2742 case WINED3DLIGHT_POINT:
2743 case WINED3DLIGHT_SPOT:
2744 case WINED3DLIGHT_PARALLELPOINT:
2745 case WINED3DLIGHT_GLSPOT:
2746 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2747 * most wanted
2749 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2750 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2751 return WINED3DERR_INVALIDCALL;
2753 break;
2755 case WINED3DLIGHT_DIRECTIONAL:
2756 /* Ignores attenuation */
2757 break;
2759 default:
2760 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2761 return WINED3DERR_INVALIDCALL;
2764 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2765 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2766 if(object->OriginalIndex == Index) break;
2767 object = NULL;
2770 if(!object) {
2771 TRACE("Adding new light\n");
2772 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2773 if(!object) {
2774 ERR("Out of memory error when allocating a light\n");
2775 return E_OUTOFMEMORY;
2777 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2778 object->glIndex = -1;
2779 object->OriginalIndex = Index;
2780 object->changed = TRUE;
2783 /* Initialize the object */
2784 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,
2785 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2786 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2787 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2788 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2789 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2790 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2792 /* Save away the information */
2793 object->OriginalParms = *pLight;
2795 switch (pLight->Type) {
2796 case WINED3DLIGHT_POINT:
2797 /* Position */
2798 object->lightPosn[0] = pLight->Position.x;
2799 object->lightPosn[1] = pLight->Position.y;
2800 object->lightPosn[2] = pLight->Position.z;
2801 object->lightPosn[3] = 1.0f;
2802 object->cutoff = 180.0f;
2803 /* FIXME: Range */
2804 break;
2806 case WINED3DLIGHT_DIRECTIONAL:
2807 /* Direction */
2808 object->lightPosn[0] = -pLight->Direction.x;
2809 object->lightPosn[1] = -pLight->Direction.y;
2810 object->lightPosn[2] = -pLight->Direction.z;
2811 object->lightPosn[3] = 0.0;
2812 object->exponent = 0.0f;
2813 object->cutoff = 180.0f;
2814 break;
2816 case WINED3DLIGHT_SPOT:
2817 /* Position */
2818 object->lightPosn[0] = pLight->Position.x;
2819 object->lightPosn[1] = pLight->Position.y;
2820 object->lightPosn[2] = pLight->Position.z;
2821 object->lightPosn[3] = 1.0;
2823 /* Direction */
2824 object->lightDirn[0] = pLight->Direction.x;
2825 object->lightDirn[1] = pLight->Direction.y;
2826 object->lightDirn[2] = pLight->Direction.z;
2827 object->lightDirn[3] = 1.0;
2830 * opengl-ish and d3d-ish spot lights use too different models for the
2831 * light "intensity" as a function of the angle towards the main light direction,
2832 * so we only can approximate very roughly.
2833 * however spot lights are rather rarely used in games (if ever used at all).
2834 * furthermore if still used, probably nobody pays attention to such details.
2836 if (pLight->Falloff == 0) {
2837 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2838 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2839 * will always be 1.0 for both of them, and we don't have to care for the
2840 * rest of the rather complex calculation
2842 object->exponent = 0;
2843 } else {
2844 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2845 if (rho < 0.0001) rho = 0.0001f;
2846 object->exponent = -0.3/log(cos(rho/2));
2848 if (object->exponent > 128.0) {
2849 object->exponent = 128.0;
2851 object->cutoff = pLight->Phi*90/M_PI;
2853 /* FIXME: Range */
2854 break;
2856 default:
2857 FIXME("Unrecognized light type %d\n", pLight->Type);
2860 /* Update the live definitions if the light is currently assigned a glIndex */
2861 if (object->glIndex != -1 && !This->isRecordingState) {
2862 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2864 return WINED3D_OK;
2867 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2868 PLIGHTINFOEL *lightInfo = NULL;
2869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2870 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2871 struct list *e;
2872 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2874 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2875 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2876 if(lightInfo->OriginalIndex == Index) break;
2877 lightInfo = NULL;
2880 if (lightInfo == NULL) {
2881 TRACE("Light information requested but light not defined\n");
2882 return WINED3DERR_INVALIDCALL;
2885 *pLight = lightInfo->OriginalParms;
2886 return WINED3D_OK;
2889 /*****
2890 * Get / Set Light Enable
2891 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2892 *****/
2893 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2894 PLIGHTINFOEL *lightInfo = NULL;
2895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2896 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2897 struct list *e;
2898 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2900 /* Tests show true = 128...not clear why */
2901 Enable = Enable? 128: 0;
2903 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2904 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2905 if(lightInfo->OriginalIndex == Index) break;
2906 lightInfo = NULL;
2908 TRACE("Found light: %p\n", lightInfo);
2910 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2911 if (lightInfo == NULL) {
2913 TRACE("Light enabled requested but light not defined, so defining one!\n");
2914 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2916 /* Search for it again! Should be fairly quick as near head of list */
2917 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2918 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2919 if(lightInfo->OriginalIndex == Index) break;
2920 lightInfo = NULL;
2922 if (lightInfo == NULL) {
2923 FIXME("Adding default lights has failed dismally\n");
2924 return WINED3DERR_INVALIDCALL;
2928 lightInfo->enabledChanged = TRUE;
2929 if(!Enable) {
2930 if(lightInfo->glIndex != -1) {
2931 if(!This->isRecordingState) {
2932 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2935 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2936 lightInfo->glIndex = -1;
2937 } else {
2938 TRACE("Light already disabled, nothing to do\n");
2940 lightInfo->enabled = FALSE;
2941 } else {
2942 lightInfo->enabled = TRUE;
2943 if (lightInfo->glIndex != -1) {
2944 /* nop */
2945 TRACE("Nothing to do as light was enabled\n");
2946 } else {
2947 int i;
2948 /* Find a free gl light */
2949 for(i = 0; i < This->maxConcurrentLights; i++) {
2950 if(This->stateBlock->activeLights[i] == NULL) {
2951 This->stateBlock->activeLights[i] = lightInfo;
2952 lightInfo->glIndex = i;
2953 break;
2956 if(lightInfo->glIndex == -1) {
2957 /* Our tests show that Windows returns D3D_OK in this situation, even with
2958 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2959 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2960 * as well for those lights.
2962 * TODO: Test how this affects rendering
2964 FIXME("Too many concurrently active lights\n");
2965 return WINED3D_OK;
2968 /* i == lightInfo->glIndex */
2969 if(!This->isRecordingState) {
2970 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2975 return WINED3D_OK;
2978 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2980 PLIGHTINFOEL *lightInfo = NULL;
2981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2982 struct list *e;
2983 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2984 TRACE("(%p) : for idx(%d)\n", This, Index);
2986 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2987 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2988 if(lightInfo->OriginalIndex == Index) break;
2989 lightInfo = NULL;
2992 if (lightInfo == NULL) {
2993 TRACE("Light enabled state requested but light not defined\n");
2994 return WINED3DERR_INVALIDCALL;
2996 /* true is 128 according to SetLightEnable */
2997 *pEnable = lightInfo->enabled ? 128 : 0;
2998 return WINED3D_OK;
3001 /*****
3002 * Get / Set Clip Planes
3003 *****/
3004 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3006 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3008 /* Validate Index */
3009 if (Index >= GL_LIMITS(clipplanes)) {
3010 TRACE("Application has requested clipplane this device doesn't support\n");
3011 return WINED3DERR_INVALIDCALL;
3014 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3016 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3017 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3018 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3019 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3020 TRACE("Application is setting old values over, nothing to do\n");
3021 return WINED3D_OK;
3024 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3025 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3026 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3027 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3029 /* Handle recording of state blocks */
3030 if (This->isRecordingState) {
3031 TRACE("Recording... not performing anything\n");
3032 return WINED3D_OK;
3035 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3037 return WINED3D_OK;
3040 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3042 TRACE("(%p) : for idx %d\n", This, Index);
3044 /* Validate Index */
3045 if (Index >= GL_LIMITS(clipplanes)) {
3046 TRACE("Application has requested clipplane this device doesn't support\n");
3047 return WINED3DERR_INVALIDCALL;
3050 pPlane[0] = This->stateBlock->clipplane[Index][0];
3051 pPlane[1] = This->stateBlock->clipplane[Index][1];
3052 pPlane[2] = This->stateBlock->clipplane[Index][2];
3053 pPlane[3] = This->stateBlock->clipplane[Index][3];
3054 return WINED3D_OK;
3057 /*****
3058 * Get / Set Clip Plane Status
3059 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3060 *****/
3061 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3063 FIXME("(%p) : stub\n", This);
3064 if (NULL == pClipStatus) {
3065 return WINED3DERR_INVALIDCALL;
3067 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3068 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3069 return WINED3D_OK;
3072 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3073 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3074 FIXME("(%p) : stub\n", This);
3075 if (NULL == pClipStatus) {
3076 return WINED3DERR_INVALIDCALL;
3078 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3079 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3080 return WINED3D_OK;
3083 /*****
3084 * Get / Set Material
3085 *****/
3086 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3089 if (!pMaterial) return WINED3DERR_INVALIDCALL;
3091 This->updateStateBlock->changed.material = TRUE;
3092 This->updateStateBlock->material = *pMaterial;
3094 /* Handle recording of state blocks */
3095 if (This->isRecordingState) {
3096 TRACE("Recording... not performing anything\n");
3097 return WINED3D_OK;
3100 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3101 return WINED3D_OK;
3104 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3106 *pMaterial = This->updateStateBlock->material;
3107 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3108 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3109 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3110 pMaterial->Ambient.b, pMaterial->Ambient.a);
3111 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3112 pMaterial->Specular.b, pMaterial->Specular.a);
3113 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3114 pMaterial->Emissive.b, pMaterial->Emissive.a);
3115 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3117 return WINED3D_OK;
3120 /*****
3121 * Get / Set Indices
3122 *****/
3123 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3125 IWineD3DIndexBuffer *oldIdxs;
3127 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3128 oldIdxs = This->updateStateBlock->pIndexData;
3130 This->updateStateBlock->changed.indices = TRUE;
3131 This->updateStateBlock->pIndexData = pIndexData;
3133 /* Handle recording of state blocks */
3134 if (This->isRecordingState) {
3135 TRACE("Recording... not performing anything\n");
3136 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3137 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3138 return WINED3D_OK;
3141 if(oldIdxs != pIndexData) {
3142 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3143 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3144 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3146 return WINED3D_OK;
3149 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3152 *ppIndexData = This->stateBlock->pIndexData;
3154 /* up ref count on ppindexdata */
3155 if (*ppIndexData) {
3156 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3157 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3158 }else{
3159 TRACE("(%p) No index data set\n", This);
3161 TRACE("Returning %p\n", *ppIndexData);
3163 return WINED3D_OK;
3166 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3167 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3169 TRACE("(%p)->(%d)\n", This, BaseIndex);
3171 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3172 TRACE("Application is setting the old value over, nothing to do\n");
3173 return WINED3D_OK;
3176 This->updateStateBlock->baseVertexIndex = BaseIndex;
3178 if (This->isRecordingState) {
3179 TRACE("Recording... not performing anything\n");
3180 return WINED3D_OK;
3182 /* The base vertex index affects the stream sources */
3183 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3184 return WINED3D_OK;
3187 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3189 TRACE("(%p) : base_index %p\n", This, base_index);
3191 *base_index = This->stateBlock->baseVertexIndex;
3193 TRACE("Returning %u\n", *base_index);
3195 return WINED3D_OK;
3198 /*****
3199 * Get / Set Viewports
3200 *****/
3201 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3204 TRACE("(%p)\n", This);
3205 This->updateStateBlock->changed.viewport = TRUE;
3206 This->updateStateBlock->viewport = *pViewport;
3208 /* Handle recording of state blocks */
3209 if (This->isRecordingState) {
3210 TRACE("Recording... not performing anything\n");
3211 return WINED3D_OK;
3214 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3215 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3217 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3218 return WINED3D_OK;
3222 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3224 TRACE("(%p)\n", This);
3225 *pViewport = This->stateBlock->viewport;
3226 return WINED3D_OK;
3229 /*****
3230 * Get / Set Render States
3231 * TODO: Verify against dx9 definitions
3232 *****/
3233 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3236 DWORD oldValue = This->stateBlock->renderState[State];
3238 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3240 This->updateStateBlock->changed.renderState[State] = TRUE;
3241 This->updateStateBlock->renderState[State] = Value;
3243 /* Handle recording of state blocks */
3244 if (This->isRecordingState) {
3245 TRACE("Recording... not performing anything\n");
3246 return WINED3D_OK;
3249 /* Compared here and not before the assignment to allow proper stateblock recording */
3250 if(Value == oldValue) {
3251 TRACE("Application is setting the old value over, nothing to do\n");
3252 } else {
3253 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3256 return WINED3D_OK;
3259 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3261 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3262 *pValue = This->stateBlock->renderState[State];
3263 return WINED3D_OK;
3266 /*****
3267 * Get / Set Sampler States
3268 * TODO: Verify against dx9 definitions
3269 *****/
3271 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3273 DWORD oldValue;
3275 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3276 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3278 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3279 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3282 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3283 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3284 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3287 * SetSampler is designed to allow for more than the standard up to 8 textures
3288 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3289 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3291 * http://developer.nvidia.com/object/General_FAQ.html#t6
3293 * There are two new settings for GForce
3294 * the sampler one:
3295 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3296 * and the texture one:
3297 * GL_MAX_TEXTURE_COORDS_ARB.
3298 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3299 ******************/
3301 oldValue = This->stateBlock->samplerState[Sampler][Type];
3302 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3303 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3305 /* Handle recording of state blocks */
3306 if (This->isRecordingState) {
3307 TRACE("Recording... not performing anything\n");
3308 return WINED3D_OK;
3311 if(oldValue == Value) {
3312 TRACE("Application is setting the old value over, nothing to do\n");
3313 return WINED3D_OK;
3316 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3318 return WINED3D_OK;
3321 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3324 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3325 This, Sampler, debug_d3dsamplerstate(Type), Type);
3327 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3328 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3331 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3332 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3333 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3335 *Value = This->stateBlock->samplerState[Sampler][Type];
3336 TRACE("(%p) : Returning %#x\n", This, *Value);
3338 return WINED3D_OK;
3341 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3344 This->updateStateBlock->changed.scissorRect = TRUE;
3345 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3346 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3347 return WINED3D_OK;
3349 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3351 if(This->isRecordingState) {
3352 TRACE("Recording... not performing anything\n");
3353 return WINED3D_OK;
3356 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3358 return WINED3D_OK;
3361 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3364 *pRect = This->updateStateBlock->scissorRect;
3365 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3366 return WINED3D_OK;
3369 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3370 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3371 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3373 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3375 This->updateStateBlock->vertexDecl = pDecl;
3376 This->updateStateBlock->changed.vertexDecl = TRUE;
3378 if (This->isRecordingState) {
3379 TRACE("Recording... not performing anything\n");
3380 return WINED3D_OK;
3381 } else if(pDecl == oldDecl) {
3382 /* Checked after the assignment to allow proper stateblock recording */
3383 TRACE("Application is setting the old declaration over, nothing to do\n");
3384 return WINED3D_OK;
3387 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3388 return WINED3D_OK;
3391 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3394 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3396 *ppDecl = This->stateBlock->vertexDecl;
3397 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3398 return WINED3D_OK;
3401 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3403 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3405 This->updateStateBlock->vertexShader = pShader;
3406 This->updateStateBlock->changed.vertexShader = TRUE;
3408 if (This->isRecordingState) {
3409 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3410 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3411 TRACE("Recording... not performing anything\n");
3412 return WINED3D_OK;
3413 } else if(oldShader == pShader) {
3414 /* Checked here to allow proper stateblock recording */
3415 TRACE("App is setting the old shader over, nothing to do\n");
3416 return WINED3D_OK;
3419 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3420 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3421 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3423 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3425 return WINED3D_OK;
3428 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3431 if (NULL == ppShader) {
3432 return WINED3DERR_INVALIDCALL;
3434 *ppShader = This->stateBlock->vertexShader;
3435 if( NULL != *ppShader)
3436 IWineD3DVertexShader_AddRef(*ppShader);
3438 TRACE("(%p) : returning %p\n", This, *ppShader);
3439 return WINED3D_OK;
3442 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3443 IWineD3DDevice *iface,
3444 UINT start,
3445 CONST BOOL *srcData,
3446 UINT count) {
3448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3449 int i, cnt = min(count, MAX_CONST_B - start);
3451 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3452 iface, srcData, start, count);
3454 if (srcData == NULL || cnt < 0)
3455 return WINED3DERR_INVALIDCALL;
3457 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3458 for (i = 0; i < cnt; i++)
3459 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3461 for (i = start; i < cnt + start; ++i) {
3462 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3465 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3467 return WINED3D_OK;
3470 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3471 IWineD3DDevice *iface,
3472 UINT start,
3473 BOOL *dstData,
3474 UINT count) {
3476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3477 int cnt = min(count, MAX_CONST_B - start);
3479 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3480 iface, dstData, start, count);
3482 if (dstData == NULL || cnt < 0)
3483 return WINED3DERR_INVALIDCALL;
3485 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3486 return WINED3D_OK;
3489 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3490 IWineD3DDevice *iface,
3491 UINT start,
3492 CONST int *srcData,
3493 UINT count) {
3495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3496 int i, cnt = min(count, MAX_CONST_I - start);
3498 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3499 iface, srcData, start, count);
3501 if (srcData == NULL || cnt < 0)
3502 return WINED3DERR_INVALIDCALL;
3504 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3505 for (i = 0; i < cnt; i++)
3506 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3507 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3509 for (i = start; i < cnt + start; ++i) {
3510 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3513 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3515 return WINED3D_OK;
3518 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3519 IWineD3DDevice *iface,
3520 UINT start,
3521 int *dstData,
3522 UINT count) {
3524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3525 int cnt = min(count, MAX_CONST_I - start);
3527 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3528 iface, dstData, start, count);
3530 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3531 return WINED3DERR_INVALIDCALL;
3533 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3534 return WINED3D_OK;
3537 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3538 IWineD3DDevice *iface,
3539 UINT start,
3540 CONST float *srcData,
3541 UINT count) {
3543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3544 int i;
3546 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3547 iface, srcData, start, count);
3549 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3550 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3551 return WINED3DERR_INVALIDCALL;
3553 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3554 if(TRACE_ON(d3d)) {
3555 for (i = 0; i < count; i++)
3556 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3557 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3560 for (i = start; i < count + start; ++i) {
3561 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3562 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3563 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3564 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3565 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3567 ptr->idx[ptr->count++] = i;
3568 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3572 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3574 return WINED3D_OK;
3577 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3578 IWineD3DDevice *iface,
3579 UINT start,
3580 CONST float *srcData,
3581 UINT count) {
3583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3584 int i;
3586 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3587 iface, srcData, start, count);
3589 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3590 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3591 return WINED3DERR_INVALIDCALL;
3593 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3594 if(TRACE_ON(d3d)) {
3595 for (i = 0; i < count; i++)
3596 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3597 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3600 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3601 * context. On a context switch the old context will be fully dirtified
3603 memset(This->activeContext->vshader_const_dirty + start, 1,
3604 sizeof(*This->activeContext->vshader_const_dirty) * count);
3605 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count);
3607 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3609 return WINED3D_OK;
3612 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3613 IWineD3DDevice *iface,
3614 UINT start,
3615 float *dstData,
3616 UINT count) {
3618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3619 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3621 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3622 iface, dstData, start, count);
3624 if (dstData == NULL || cnt < 0)
3625 return WINED3DERR_INVALIDCALL;
3627 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3628 return WINED3D_OK;
3631 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3632 DWORD i;
3633 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3634 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3638 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3639 int i = This->rev_tex_unit_map[unit];
3640 int j = This->texUnitMap[stage];
3642 This->texUnitMap[stage] = unit;
3643 if (i != -1 && i != stage) {
3644 This->texUnitMap[i] = -1;
3647 This->rev_tex_unit_map[unit] = stage;
3648 if (j != -1 && j != unit) {
3649 This->rev_tex_unit_map[j] = -1;
3653 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3654 int i;
3656 for (i = 0; i < MAX_TEXTURES; ++i) {
3657 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3658 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3659 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3660 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3661 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3662 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3663 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3664 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3666 if (color_op == WINED3DTOP_DISABLE) {
3667 /* Not used, and disable higher stages */
3668 while (i < MAX_TEXTURES) {
3669 This->fixed_function_usage_map[i] = FALSE;
3670 ++i;
3672 break;
3675 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3676 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3677 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3678 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3679 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3680 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3681 This->fixed_function_usage_map[i] = TRUE;
3682 } else {
3683 This->fixed_function_usage_map[i] = FALSE;
3686 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3687 This->fixed_function_usage_map[i+1] = TRUE;
3692 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3693 int i, tex;
3695 device_update_fixed_function_usage_map(This);
3697 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3698 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3699 if (!This->fixed_function_usage_map[i]) continue;
3701 if (This->texUnitMap[i] != i) {
3702 device_map_stage(This, i, i);
3703 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3704 markTextureStagesDirty(This, i);
3707 return;
3710 /* Now work out the mapping */
3711 tex = 0;
3712 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3713 if (!This->fixed_function_usage_map[i]) continue;
3715 if (This->texUnitMap[i] != tex) {
3716 device_map_stage(This, i, tex);
3717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3718 markTextureStagesDirty(This, i);
3721 ++tex;
3725 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3726 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3727 int i;
3729 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3730 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3731 device_map_stage(This, i, i);
3732 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3733 if (i < MAX_TEXTURES) {
3734 markTextureStagesDirty(This, i);
3740 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3741 int current_mapping = This->rev_tex_unit_map[unit];
3743 if (current_mapping == -1) {
3744 /* Not currently used */
3745 return TRUE;
3748 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3749 /* Used by a fragment sampler */
3751 if (!pshader_sampler_tokens) {
3752 /* No pixel shader, check fixed function */
3753 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3756 /* Pixel shader, check the shader's sampler map */
3757 return !pshader_sampler_tokens[current_mapping];
3760 /* Used by a vertex sampler */
3761 return !vshader_sampler_tokens[current_mapping];
3764 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3765 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3766 DWORD *pshader_sampler_tokens = NULL;
3767 int start = GL_LIMITS(combined_samplers) - 1;
3768 int i;
3770 if (ps) {
3771 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3773 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3774 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3775 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3778 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3779 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3780 if (vshader_sampler_tokens[i]) {
3781 if (This->texUnitMap[vsampler_idx] != -1) {
3782 /* Already mapped somewhere */
3783 continue;
3786 while (start >= 0) {
3787 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3788 device_map_stage(This, vsampler_idx, start);
3789 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3791 --start;
3792 break;
3795 --start;
3801 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3802 BOOL vs = use_vs(This);
3803 BOOL ps = use_ps(This);
3805 * Rules are:
3806 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3807 * that would be really messy and require shader recompilation
3808 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3809 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3811 if (ps) {
3812 device_map_psamplers(This);
3813 } else {
3814 device_map_fixed_function_samplers(This);
3817 if (vs) {
3818 device_map_vsamplers(This, ps);
3822 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3824 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3825 This->updateStateBlock->pixelShader = pShader;
3826 This->updateStateBlock->changed.pixelShader = TRUE;
3828 /* Handle recording of state blocks */
3829 if (This->isRecordingState) {
3830 TRACE("Recording... not performing anything\n");
3833 if (This->isRecordingState) {
3834 TRACE("Recording... not performing anything\n");
3835 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3836 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3837 return WINED3D_OK;
3840 if(pShader == oldShader) {
3841 TRACE("App is setting the old pixel shader over, nothing to do\n");
3842 return WINED3D_OK;
3845 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3846 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3848 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3849 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3851 return WINED3D_OK;
3854 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3857 if (NULL == ppShader) {
3858 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3859 return WINED3DERR_INVALIDCALL;
3862 *ppShader = This->stateBlock->pixelShader;
3863 if (NULL != *ppShader) {
3864 IWineD3DPixelShader_AddRef(*ppShader);
3866 TRACE("(%p) : returning %p\n", This, *ppShader);
3867 return WINED3D_OK;
3870 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3871 IWineD3DDevice *iface,
3872 UINT start,
3873 CONST BOOL *srcData,
3874 UINT count) {
3876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3877 int i, cnt = min(count, MAX_CONST_B - start);
3879 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3880 iface, srcData, start, count);
3882 if (srcData == NULL || cnt < 0)
3883 return WINED3DERR_INVALIDCALL;
3885 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3886 for (i = 0; i < cnt; i++)
3887 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3889 for (i = start; i < cnt + start; ++i) {
3890 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3893 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3895 return WINED3D_OK;
3898 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3899 IWineD3DDevice *iface,
3900 UINT start,
3901 BOOL *dstData,
3902 UINT count) {
3904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3905 int cnt = min(count, MAX_CONST_B - start);
3907 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3908 iface, dstData, start, count);
3910 if (dstData == NULL || cnt < 0)
3911 return WINED3DERR_INVALIDCALL;
3913 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3914 return WINED3D_OK;
3917 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3918 IWineD3DDevice *iface,
3919 UINT start,
3920 CONST int *srcData,
3921 UINT count) {
3923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3924 int i, cnt = min(count, MAX_CONST_I - start);
3926 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3927 iface, srcData, start, count);
3929 if (srcData == NULL || cnt < 0)
3930 return WINED3DERR_INVALIDCALL;
3932 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3933 for (i = 0; i < cnt; i++)
3934 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3935 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3937 for (i = start; i < cnt + start; ++i) {
3938 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3941 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3943 return WINED3D_OK;
3946 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3947 IWineD3DDevice *iface,
3948 UINT start,
3949 int *dstData,
3950 UINT count) {
3952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3953 int cnt = min(count, MAX_CONST_I - start);
3955 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3956 iface, dstData, start, count);
3958 if (dstData == NULL || cnt < 0)
3959 return WINED3DERR_INVALIDCALL;
3961 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3962 return WINED3D_OK;
3965 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3966 IWineD3DDevice *iface,
3967 UINT start,
3968 CONST float *srcData,
3969 UINT count) {
3971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3972 int i;
3974 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3975 iface, srcData, start, count);
3977 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3978 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3979 return WINED3DERR_INVALIDCALL;
3981 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3982 if(TRACE_ON(d3d)) {
3983 for (i = 0; i < count; i++)
3984 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3985 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3988 for (i = start; i < count + start; ++i) {
3989 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3990 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3991 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3992 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3993 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3995 ptr->idx[ptr->count++] = i;
3996 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4000 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4002 return WINED3D_OK;
4005 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4006 IWineD3DDevice *iface,
4007 UINT start,
4008 CONST float *srcData,
4009 UINT count) {
4011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4012 int i;
4014 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4015 iface, srcData, start, count);
4017 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4018 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4019 return WINED3DERR_INVALIDCALL;
4021 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4022 if(TRACE_ON(d3d)) {
4023 for (i = 0; i < count; i++)
4024 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4025 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4028 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4029 * context. On a context switch the old context will be fully dirtified
4031 memset(This->activeContext->pshader_const_dirty + start, 1,
4032 sizeof(*This->activeContext->pshader_const_dirty) * count);
4033 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count);
4035 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4037 return WINED3D_OK;
4040 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4041 IWineD3DDevice *iface,
4042 UINT start,
4043 float *dstData,
4044 UINT count) {
4046 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4047 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4049 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4050 iface, dstData, start, count);
4052 if (dstData == NULL || cnt < 0)
4053 return WINED3DERR_INVALIDCALL;
4055 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4056 return WINED3D_OK;
4059 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4060 static HRESULT
4061 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4062 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4063 unsigned int i;
4064 DWORD DestFVF = dest->fvf;
4065 WINED3DVIEWPORT vp;
4066 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4067 BOOL doClip;
4068 int numTextures;
4070 if (lpStrideData->u.s.normal.lpData) {
4071 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4074 if (lpStrideData->u.s.position.lpData == NULL) {
4075 ERR("Source has no position mask\n");
4076 return WINED3DERR_INVALIDCALL;
4079 /* We might access VBOs from this code, so hold the lock */
4080 ENTER_GL();
4082 if (dest->resource.allocatedMemory == NULL) {
4083 /* This may happen if we do direct locking into a vbo. Unlikely,
4084 * but theoretically possible(ddraw processvertices test)
4086 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4087 if(!dest->resource.allocatedMemory) {
4088 LEAVE_GL();
4089 ERR("Out of memory\n");
4090 return E_OUTOFMEMORY;
4092 if(dest->vbo) {
4093 void *src;
4094 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4095 checkGLcall("glBindBufferARB");
4096 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4097 if(src) {
4098 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4100 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4101 checkGLcall("glUnmapBufferARB");
4105 /* Get a pointer into the destination vbo(create one if none exists) and
4106 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4108 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4109 dest->Flags |= VBFLAG_CREATEVBO;
4110 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4113 if(dest->vbo) {
4114 unsigned char extrabytes = 0;
4115 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4116 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4117 * this may write 4 extra bytes beyond the area that should be written
4119 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4120 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4121 if(!dest_conv_addr) {
4122 ERR("Out of memory\n");
4123 /* Continue without storing converted vertices */
4125 dest_conv = dest_conv_addr;
4128 /* Should I clip?
4129 * a) WINED3DRS_CLIPPING is enabled
4130 * b) WINED3DVOP_CLIP is passed
4132 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4133 static BOOL warned = FALSE;
4135 * The clipping code is not quite correct. Some things need
4136 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4137 * so disable clipping for now.
4138 * (The graphics in Half-Life are broken, and my processvertices
4139 * test crashes with IDirect3DDevice3)
4140 doClip = TRUE;
4142 doClip = FALSE;
4143 if(!warned) {
4144 warned = TRUE;
4145 FIXME("Clipping is broken and disabled for now\n");
4147 } else doClip = FALSE;
4148 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4150 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4151 WINED3DTS_VIEW,
4152 &view_mat);
4153 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4154 WINED3DTS_PROJECTION,
4155 &proj_mat);
4156 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4157 WINED3DTS_WORLDMATRIX(0),
4158 &world_mat);
4160 TRACE("View mat:\n");
4161 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);
4162 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);
4163 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);
4164 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);
4166 TRACE("Proj mat:\n");
4167 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);
4168 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);
4169 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);
4170 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);
4172 TRACE("World mat:\n");
4173 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);
4174 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);
4175 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);
4176 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);
4178 /* Get the viewport */
4179 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4180 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4181 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4183 multiply_matrix(&mat,&view_mat,&world_mat);
4184 multiply_matrix(&mat,&proj_mat,&mat);
4186 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4188 for (i = 0; i < dwCount; i+= 1) {
4189 unsigned int tex_index;
4191 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4192 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4193 /* The position first */
4194 float *p =
4195 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4196 float x, y, z, rhw;
4197 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4199 /* Multiplication with world, view and projection matrix */
4200 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);
4201 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);
4202 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);
4203 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);
4205 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4207 /* WARNING: The following things are taken from d3d7 and were not yet checked
4208 * against d3d8 or d3d9!
4211 /* Clipping conditions: From msdn
4213 * A vertex is clipped if it does not match the following requirements
4214 * -rhw < x <= rhw
4215 * -rhw < y <= rhw
4216 * 0 < z <= rhw
4217 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4219 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4220 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4224 if( !doClip ||
4225 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4226 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4227 ( rhw > eps ) ) ) {
4229 /* "Normal" viewport transformation (not clipped)
4230 * 1) The values are divided by rhw
4231 * 2) The y axis is negative, so multiply it with -1
4232 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4233 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4234 * 4) Multiply x with Width/2 and add Width/2
4235 * 5) The same for the height
4236 * 6) Add the viewpoint X and Y to the 2D coordinates and
4237 * The minimum Z value to z
4238 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4240 * Well, basically it's simply a linear transformation into viewport
4241 * coordinates
4244 x /= rhw;
4245 y /= rhw;
4246 z /= rhw;
4248 y *= -1;
4250 x *= vp.Width / 2;
4251 y *= vp.Height / 2;
4252 z *= vp.MaxZ - vp.MinZ;
4254 x += vp.Width / 2 + vp.X;
4255 y += vp.Height / 2 + vp.Y;
4256 z += vp.MinZ;
4258 rhw = 1 / rhw;
4259 } else {
4260 /* That vertex got clipped
4261 * Contrary to OpenGL it is not dropped completely, it just
4262 * undergoes a different calculation.
4264 TRACE("Vertex got clipped\n");
4265 x += rhw;
4266 y += rhw;
4268 x /= 2;
4269 y /= 2;
4271 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4272 * outside of the main vertex buffer memory. That needs some more
4273 * investigation...
4277 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4280 ( (float *) dest_ptr)[0] = x;
4281 ( (float *) dest_ptr)[1] = y;
4282 ( (float *) dest_ptr)[2] = z;
4283 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4285 dest_ptr += 3 * sizeof(float);
4287 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4288 dest_ptr += sizeof(float);
4291 if(dest_conv) {
4292 float w = 1 / rhw;
4293 ( (float *) dest_conv)[0] = x * w;
4294 ( (float *) dest_conv)[1] = y * w;
4295 ( (float *) dest_conv)[2] = z * w;
4296 ( (float *) dest_conv)[3] = w;
4298 dest_conv += 3 * sizeof(float);
4300 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4301 dest_conv += sizeof(float);
4305 if (DestFVF & WINED3DFVF_PSIZE) {
4306 dest_ptr += sizeof(DWORD);
4307 if(dest_conv) dest_conv += sizeof(DWORD);
4309 if (DestFVF & WINED3DFVF_NORMAL) {
4310 float *normal =
4311 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4312 /* AFAIK this should go into the lighting information */
4313 FIXME("Didn't expect the destination to have a normal\n");
4314 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4315 if(dest_conv) {
4316 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4320 if (DestFVF & WINED3DFVF_DIFFUSE) {
4321 DWORD *color_d =
4322 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4323 if(!color_d) {
4324 static BOOL warned = FALSE;
4326 if(!warned) {
4327 ERR("No diffuse color in source, but destination has one\n");
4328 warned = TRUE;
4331 *( (DWORD *) dest_ptr) = 0xffffffff;
4332 dest_ptr += sizeof(DWORD);
4334 if(dest_conv) {
4335 *( (DWORD *) dest_conv) = 0xffffffff;
4336 dest_conv += sizeof(DWORD);
4339 else {
4340 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4341 if(dest_conv) {
4342 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4343 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4344 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4345 dest_conv += sizeof(DWORD);
4350 if (DestFVF & WINED3DFVF_SPECULAR) {
4351 /* What's the color value in the feedback buffer? */
4352 DWORD *color_s =
4353 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4354 if(!color_s) {
4355 static BOOL warned = FALSE;
4357 if(!warned) {
4358 ERR("No specular color in source, but destination has one\n");
4359 warned = TRUE;
4362 *( (DWORD *) dest_ptr) = 0xFF000000;
4363 dest_ptr += sizeof(DWORD);
4365 if(dest_conv) {
4366 *( (DWORD *) dest_conv) = 0xFF000000;
4367 dest_conv += sizeof(DWORD);
4370 else {
4371 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4372 if(dest_conv) {
4373 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4374 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4375 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4376 dest_conv += sizeof(DWORD);
4381 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4382 float *tex_coord =
4383 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4384 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4385 if(!tex_coord) {
4386 ERR("No source texture, but destination requests one\n");
4387 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4388 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4390 else {
4391 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4392 if(dest_conv) {
4393 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4399 if(dest_conv) {
4400 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4401 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4402 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4403 dwCount * get_flexible_vertex_size(DestFVF),
4404 dest_conv_addr));
4405 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4406 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4409 LEAVE_GL();
4411 return WINED3D_OK;
4413 #undef copy_and_next
4415 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4417 WineDirect3DVertexStridedData strided;
4418 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4419 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4421 if(pVertexDecl) {
4422 ERR("Output vertex declaration not implemented yet\n");
4425 /* Need any context to write to the vbo. */
4426 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4428 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4429 * control the streamIsUP flag, thus restore it afterwards.
4431 This->stateBlock->streamIsUP = FALSE;
4432 memset(&strided, 0, sizeof(strided));
4433 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4434 This->stateBlock->streamIsUP = streamWasUP;
4436 if(vbo || SrcStartIndex) {
4437 unsigned int i;
4438 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4439 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4441 * Also get the start index in, but only loop over all elements if there's something to add at all.
4443 #define FIXSRC(type) \
4444 if(strided.u.s.type.VBO) { \
4445 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4446 strided.u.s.type.VBO = 0; \
4447 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4448 ENTER_GL(); \
4449 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4450 vb->vbo = 0; \
4451 LEAVE_GL(); \
4453 if(strided.u.s.type.lpData) { \
4454 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4456 FIXSRC(position);
4457 FIXSRC(blendWeights);
4458 FIXSRC(blendMatrixIndices);
4459 FIXSRC(normal);
4460 FIXSRC(pSize);
4461 FIXSRC(diffuse);
4462 FIXSRC(specular);
4463 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4464 FIXSRC(texCoords[i]);
4466 FIXSRC(position2);
4467 FIXSRC(normal2);
4468 FIXSRC(tangent);
4469 FIXSRC(binormal);
4470 FIXSRC(tessFactor);
4471 FIXSRC(fog);
4472 FIXSRC(depth);
4473 FIXSRC(sample);
4474 #undef FIXSRC
4477 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4480 /*****
4481 * Get / Set Texture Stage States
4482 * TODO: Verify against dx9 definitions
4483 *****/
4484 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4486 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4488 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4490 if (Stage >= MAX_TEXTURES) {
4491 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4492 return WINED3D_OK;
4495 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4496 This->updateStateBlock->textureState[Stage][Type] = Value;
4498 if (This->isRecordingState) {
4499 TRACE("Recording... not performing anything\n");
4500 return WINED3D_OK;
4503 /* Checked after the assignments to allow proper stateblock recording */
4504 if(oldValue == Value) {
4505 TRACE("App is setting the old value over, nothing to do\n");
4506 return WINED3D_OK;
4509 if(Stage > This->stateBlock->lowest_disabled_stage &&
4510 This->shader_backend->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4511 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4512 * Changes in other states are important on disabled stages too
4514 return WINED3D_OK;
4517 if(Type == WINED3DTSS_COLOROP) {
4518 int i;
4520 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4521 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4522 * they have to be disabled
4524 * The current stage is dirtified below.
4526 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4527 TRACE("Additionally dirtifying stage %d\n", i);
4528 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4530 This->stateBlock->lowest_disabled_stage = Stage;
4531 TRACE("New lowest disabled: %d\n", Stage);
4532 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4533 /* Previously disabled stage enabled. Stages above it may need enabling
4534 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4535 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4537 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4540 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4541 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4542 break;
4544 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4545 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4547 This->stateBlock->lowest_disabled_stage = i;
4548 TRACE("New lowest disabled: %d\n", i);
4550 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4551 /* TODO: Built a stage -> texture unit mapping for register combiners */
4555 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4557 return WINED3D_OK;
4560 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4562 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4563 *pValue = This->updateStateBlock->textureState[Stage][Type];
4564 return WINED3D_OK;
4567 /*****
4568 * Get / Set Texture
4569 *****/
4570 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4572 IWineD3DBaseTexture *oldTexture;
4574 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4576 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4577 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4580 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4581 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4582 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4585 oldTexture = This->updateStateBlock->textures[Stage];
4587 if(pTexture != NULL) {
4588 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4590 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4591 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4592 return WINED3DERR_INVALIDCALL;
4594 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4597 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4598 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4600 This->updateStateBlock->changed.textures[Stage] = TRUE;
4601 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4602 This->updateStateBlock->textures[Stage] = pTexture;
4604 /* Handle recording of state blocks */
4605 if (This->isRecordingState) {
4606 TRACE("Recording... not performing anything\n");
4607 return WINED3D_OK;
4610 if(oldTexture == pTexture) {
4611 TRACE("App is setting the same texture again, nothing to do\n");
4612 return WINED3D_OK;
4615 /** NOTE: MSDN says that setTexture increases the reference count,
4616 * and that the application must set the texture back to null (or have a leaky application),
4617 * This means we should pass the refcount up to the parent
4618 *******************************/
4619 if (NULL != This->updateStateBlock->textures[Stage]) {
4620 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4621 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4623 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4624 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4625 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4626 * so the COLOROP and ALPHAOP have to be dirtified.
4628 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4629 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4631 if(bindCount == 1) {
4632 new->baseTexture.sampler = Stage;
4634 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4638 if (NULL != oldTexture) {
4639 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4640 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4642 IWineD3DBaseTexture_Release(oldTexture);
4643 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4644 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4645 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4648 if(bindCount && old->baseTexture.sampler == Stage) {
4649 int i;
4650 /* Have to do a search for the other sampler(s) where the texture is bound to
4651 * Shouldn't happen as long as apps bind a texture only to one stage
4653 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4654 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4655 if(This->updateStateBlock->textures[i] == oldTexture) {
4656 old->baseTexture.sampler = i;
4657 break;
4663 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4665 return WINED3D_OK;
4668 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4671 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4673 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4674 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4677 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4678 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4679 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4682 *ppTexture=This->stateBlock->textures[Stage];
4683 if (*ppTexture)
4684 IWineD3DBaseTexture_AddRef(*ppTexture);
4686 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4688 return WINED3D_OK;
4691 /*****
4692 * Get Back Buffer
4693 *****/
4694 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4695 IWineD3DSurface **ppBackBuffer) {
4696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4697 IWineD3DSwapChain *swapChain;
4698 HRESULT hr;
4700 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4702 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4703 if (hr == WINED3D_OK) {
4704 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4705 IWineD3DSwapChain_Release(swapChain);
4706 } else {
4707 *ppBackBuffer = NULL;
4709 return hr;
4712 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4714 WARN("(%p) : stub, calling idirect3d for now\n", This);
4715 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4718 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4719 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4720 IWineD3DSwapChain *swapChain;
4721 HRESULT hr;
4723 if(iSwapChain > 0) {
4724 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4725 if (hr == WINED3D_OK) {
4726 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4727 IWineD3DSwapChain_Release(swapChain);
4728 } else {
4729 FIXME("(%p) Error getting display mode\n", This);
4731 } else {
4732 /* Don't read the real display mode,
4733 but return the stored mode instead. X11 can't change the color
4734 depth, and some apps are pretty angry if they SetDisplayMode from
4735 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4737 Also don't relay to the swapchain because with ddraw it's possible
4738 that there isn't a swapchain at all */
4739 pMode->Width = This->ddraw_width;
4740 pMode->Height = This->ddraw_height;
4741 pMode->Format = This->ddraw_format;
4742 pMode->RefreshRate = 0;
4743 hr = WINED3D_OK;
4746 return hr;
4749 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4751 TRACE("(%p)->(%p)\n", This, hWnd);
4753 if(This->ddraw_fullscreen) {
4754 if(This->ddraw_window && This->ddraw_window != hWnd) {
4755 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4757 if(hWnd && This->ddraw_window != hWnd) {
4758 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4762 This->ddraw_window = hWnd;
4763 return WINED3D_OK;
4766 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4768 TRACE("(%p)->(%p)\n", This, hWnd);
4770 *hWnd = This->ddraw_window;
4771 return WINED3D_OK;
4774 /*****
4775 * Stateblock related functions
4776 *****/
4778 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4780 IWineD3DStateBlockImpl *object;
4781 HRESULT temp_result;
4782 int i;
4784 TRACE("(%p)\n", This);
4786 if (This->isRecordingState) {
4787 return WINED3DERR_INVALIDCALL;
4790 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4791 if (NULL == object ) {
4792 FIXME("(%p)Error allocating memory for stateblock\n", This);
4793 return E_OUTOFMEMORY;
4795 TRACE("(%p) created object %p\n", This, object);
4796 object->wineD3DDevice= This;
4797 /** FIXME: object->parent = parent; **/
4798 object->parent = NULL;
4799 object->blockType = WINED3DSBT_RECORDED;
4800 object->ref = 1;
4801 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4803 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4804 list_init(&object->lightMap[i]);
4807 temp_result = allocate_shader_constants(object);
4808 if (WINED3D_OK != temp_result)
4809 return temp_result;
4811 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4812 This->updateStateBlock = object;
4813 This->isRecordingState = TRUE;
4815 TRACE("(%p) recording stateblock %p\n",This , object);
4816 return WINED3D_OK;
4819 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4821 unsigned int i, j;
4822 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4824 if (!This->isRecordingState) {
4825 FIXME("(%p) not recording! returning error\n", This);
4826 *ppStateBlock = NULL;
4827 return WINED3DERR_INVALIDCALL;
4830 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4831 if(object->changed.renderState[i]) {
4832 object->contained_render_states[object->num_contained_render_states] = i;
4833 object->num_contained_render_states++;
4836 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4837 if(object->changed.transform[i]) {
4838 object->contained_transform_states[object->num_contained_transform_states] = i;
4839 object->num_contained_transform_states++;
4842 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4843 if(object->changed.vertexShaderConstantsF[i]) {
4844 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4845 object->num_contained_vs_consts_f++;
4848 for(i = 0; i < MAX_CONST_I; i++) {
4849 if(object->changed.vertexShaderConstantsI[i]) {
4850 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4851 object->num_contained_vs_consts_i++;
4854 for(i = 0; i < MAX_CONST_B; i++) {
4855 if(object->changed.vertexShaderConstantsB[i]) {
4856 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4857 object->num_contained_vs_consts_b++;
4860 for(i = 0; i < MAX_CONST_I; i++) {
4861 if(object->changed.pixelShaderConstantsI[i]) {
4862 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4863 object->num_contained_ps_consts_i++;
4866 for(i = 0; i < MAX_CONST_B; i++) {
4867 if(object->changed.pixelShaderConstantsB[i]) {
4868 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4869 object->num_contained_ps_consts_b++;
4872 for(i = 0; i < MAX_TEXTURES; i++) {
4873 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4874 if(object->changed.textureState[i][j]) {
4875 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4876 object->contained_tss_states[object->num_contained_tss_states].state = j;
4877 object->num_contained_tss_states++;
4881 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4882 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4883 if(object->changed.samplerState[i][j]) {
4884 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4885 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4886 object->num_contained_sampler_states++;
4891 *ppStateBlock = (IWineD3DStateBlock*) object;
4892 This->isRecordingState = FALSE;
4893 This->updateStateBlock = This->stateBlock;
4894 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4895 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4896 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4897 return WINED3D_OK;
4900 /*****
4901 * Scene related functions
4902 *****/
4903 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4904 /* At the moment we have no need for any functionality at the beginning
4905 of a scene */
4906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4907 TRACE("(%p)\n", This);
4909 if(This->inScene) {
4910 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4911 return WINED3DERR_INVALIDCALL;
4913 This->inScene = TRUE;
4914 return WINED3D_OK;
4917 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4919 TRACE("(%p)\n", This);
4921 if(!This->inScene) {
4922 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4923 return WINED3DERR_INVALIDCALL;
4926 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4927 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4928 ENTER_GL();
4929 glFlush();
4930 checkGLcall("glFlush");
4931 LEAVE_GL();
4933 This->inScene = FALSE;
4934 return WINED3D_OK;
4937 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4938 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4939 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4941 IWineD3DSwapChain *swapChain = NULL;
4942 int i;
4943 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4945 TRACE("(%p) Presenting the frame\n", This);
4947 for(i = 0 ; i < swapchains ; i ++) {
4949 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4950 TRACE("presentinng chain %d, %p\n", i, swapChain);
4951 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4952 IWineD3DSwapChain_Release(swapChain);
4955 return WINED3D_OK;
4958 /* Not called from the VTable (internal subroutine) */
4959 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4960 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4961 float Z, DWORD Stencil) {
4962 GLbitfield glMask = 0;
4963 unsigned int i;
4964 WINED3DRECT curRect;
4965 RECT vp_rect;
4966 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4967 UINT drawable_width, drawable_height;
4968 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4970 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4971 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4972 * for the cleared parts, and the untouched parts.
4974 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4975 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4976 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4977 * checking all this if the dest surface is in the drawable anyway.
4979 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4980 while(1) {
4981 if(vp->X != 0 || vp->Y != 0 ||
4982 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4983 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4984 break;
4986 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4987 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4988 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4989 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4990 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4991 break;
4993 if(Count > 0 && pRects && (
4994 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4995 pRects[0].x2 < target->currentDesc.Width ||
4996 pRects[0].y2 < target->currentDesc.Height)) {
4997 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4998 break;
5000 break;
5004 target->get_drawable_size(target, &drawable_width, &drawable_height);
5006 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5007 ENTER_GL();
5009 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5010 apply_fbo_state((IWineD3DDevice *) This);
5013 /* Only set the values up once, as they are not changing */
5014 if (Flags & WINED3DCLEAR_STENCIL) {
5015 glClearStencil(Stencil);
5016 checkGLcall("glClearStencil");
5017 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5018 glStencilMask(0xFFFFFFFF);
5021 if (Flags & WINED3DCLEAR_ZBUFFER) {
5022 glDepthMask(GL_TRUE);
5023 glClearDepth(Z);
5024 checkGLcall("glClearDepth");
5025 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5026 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5028 if(This->depth_copy_state == WINED3D_DCS_COPY) {
5029 if(vp->X != 0 || vp->Y != 0 ||
5030 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5031 depth_copy((IWineD3DDevice *) This);
5033 else if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5034 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5035 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5036 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5037 depth_copy((IWineD3DDevice *) This);
5039 else if(Count > 0 && pRects && (
5040 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5041 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5042 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5043 depth_copy((IWineD3DDevice *) This);
5046 This->depth_copy_state = WINED3D_DCS_INITIAL;
5049 if (Flags & WINED3DCLEAR_TARGET) {
5050 TRACE("Clearing screen with glClear to color %x\n", Color);
5051 glClearColor(D3DCOLOR_R(Color),
5052 D3DCOLOR_G(Color),
5053 D3DCOLOR_B(Color),
5054 D3DCOLOR_A(Color));
5055 checkGLcall("glClearColor");
5057 /* Clear ALL colors! */
5058 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5059 glMask = glMask | GL_COLOR_BUFFER_BIT;
5062 vp_rect.left = vp->X;
5063 vp_rect.top = vp->Y;
5064 vp_rect.right = vp->X + vp->Width;
5065 vp_rect.bottom = vp->Y + vp->Height;
5066 if (!(Count > 0 && pRects)) {
5067 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5068 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5070 if(This->render_offscreen) {
5071 glScissor(vp_rect.left, vp_rect.top,
5072 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5073 } else {
5074 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5075 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5077 checkGLcall("glScissor");
5078 glClear(glMask);
5079 checkGLcall("glClear");
5080 } else {
5081 /* Now process each rect in turn */
5082 for (i = 0; i < Count; i++) {
5083 /* Note gl uses lower left, width/height */
5084 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5085 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5086 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5088 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5089 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5090 curRect.x1, (target->currentDesc.Height - curRect.y2),
5091 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5093 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5094 * The rectangle is not cleared, no error is returned, but further rectanlges are
5095 * still cleared if they are valid
5097 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5098 TRACE("Rectangle with negative dimensions, ignoring\n");
5099 continue;
5102 if(This->render_offscreen) {
5103 glScissor(curRect.x1, curRect.y1,
5104 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5105 } else {
5106 glScissor(curRect.x1, drawable_height - curRect.y2,
5107 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5109 checkGLcall("glScissor");
5111 glClear(glMask);
5112 checkGLcall("glClear");
5116 /* Restore the old values (why..?) */
5117 if (Flags & WINED3DCLEAR_STENCIL) {
5118 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5120 if (Flags & WINED3DCLEAR_TARGET) {
5121 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5122 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5123 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5124 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5125 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5127 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5128 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5130 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5131 /* TODO: Move the fbo logic into ModifyLocation() */
5132 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5133 target->Flags |= SFLAG_INTEXTURE;
5136 LEAVE_GL();
5138 return WINED3D_OK;
5141 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5142 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5144 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5146 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5147 Count, pRects, Flags, Color, Z, Stencil);
5149 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5150 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5151 /* TODO: What about depth stencil buffers without stencil bits? */
5152 return WINED3DERR_INVALIDCALL;
5155 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5158 /*****
5159 * Drawing functions
5160 *****/
5161 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5162 UINT PrimitiveCount) {
5164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5166 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5167 debug_d3dprimitivetype(PrimitiveType),
5168 StartVertex, PrimitiveCount);
5170 if(!This->stateBlock->vertexDecl) {
5171 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5172 return WINED3DERR_INVALIDCALL;
5175 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5176 if(This->stateBlock->streamIsUP) {
5177 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5178 This->stateBlock->streamIsUP = FALSE;
5181 if(This->stateBlock->loadBaseVertexIndex != 0) {
5182 This->stateBlock->loadBaseVertexIndex = 0;
5183 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5185 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5186 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5187 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5188 return WINED3D_OK;
5191 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5192 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5193 WINED3DPRIMITIVETYPE PrimitiveType,
5194 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5197 UINT idxStride = 2;
5198 IWineD3DIndexBuffer *pIB;
5199 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5200 GLuint vbo;
5202 pIB = This->stateBlock->pIndexData;
5203 if (!pIB) {
5204 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5205 * without an index buffer set. (The first time at least...)
5206 * D3D8 simply dies, but I doubt it can do much harm to return
5207 * D3DERR_INVALIDCALL there as well. */
5208 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5209 return WINED3DERR_INVALIDCALL;
5212 if(!This->stateBlock->vertexDecl) {
5213 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5214 return WINED3DERR_INVALIDCALL;
5217 if(This->stateBlock->streamIsUP) {
5218 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5219 This->stateBlock->streamIsUP = FALSE;
5221 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5223 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5224 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5225 minIndex, NumVertices, startIndex, primCount);
5227 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5228 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5229 idxStride = 2;
5230 } else {
5231 idxStride = 4;
5234 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5235 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5236 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5239 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5240 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5242 return WINED3D_OK;
5245 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5246 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5247 UINT VertexStreamZeroStride) {
5248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5249 IWineD3DVertexBuffer *vb;
5251 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5252 debug_d3dprimitivetype(PrimitiveType),
5253 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5255 if(!This->stateBlock->vertexDecl) {
5256 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5257 return WINED3DERR_INVALIDCALL;
5260 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5261 vb = This->stateBlock->streamSource[0];
5262 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5263 if(vb) IWineD3DVertexBuffer_Release(vb);
5264 This->stateBlock->streamOffset[0] = 0;
5265 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5266 This->stateBlock->streamIsUP = TRUE;
5267 This->stateBlock->loadBaseVertexIndex = 0;
5269 /* TODO: Only mark dirty if drawing from a different UP address */
5270 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5272 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5273 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5275 /* MSDN specifies stream zero settings must be set to NULL */
5276 This->stateBlock->streamStride[0] = 0;
5277 This->stateBlock->streamSource[0] = NULL;
5279 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5280 * the new stream sources or use UP drawing again
5282 return WINED3D_OK;
5285 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5286 UINT MinVertexIndex, UINT NumVertices,
5287 UINT PrimitiveCount, CONST void* pIndexData,
5288 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5289 UINT VertexStreamZeroStride) {
5290 int idxStride;
5291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5292 IWineD3DVertexBuffer *vb;
5293 IWineD3DIndexBuffer *ib;
5295 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5296 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5297 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5298 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5300 if(!This->stateBlock->vertexDecl) {
5301 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5302 return WINED3DERR_INVALIDCALL;
5305 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5306 idxStride = 2;
5307 } else {
5308 idxStride = 4;
5311 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5312 vb = This->stateBlock->streamSource[0];
5313 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5314 if(vb) IWineD3DVertexBuffer_Release(vb);
5315 This->stateBlock->streamIsUP = TRUE;
5316 This->stateBlock->streamOffset[0] = 0;
5317 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5319 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5320 This->stateBlock->baseVertexIndex = 0;
5321 This->stateBlock->loadBaseVertexIndex = 0;
5322 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5323 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5324 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5326 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5328 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5329 This->stateBlock->streamSource[0] = NULL;
5330 This->stateBlock->streamStride[0] = 0;
5331 ib = This->stateBlock->pIndexData;
5332 if(ib) {
5333 IWineD3DIndexBuffer_Release(ib);
5334 This->stateBlock->pIndexData = NULL;
5336 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5337 * SetStreamSource to specify a vertex buffer
5340 return WINED3D_OK;
5343 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5346 /* Mark the state dirty until we have nicer tracking
5347 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5348 * that value.
5350 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5351 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5352 This->stateBlock->baseVertexIndex = 0;
5353 This->up_strided = DrawPrimStrideData;
5354 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5355 This->up_strided = NULL;
5356 return WINED3D_OK;
5359 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5361 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5363 /* Mark the state dirty until we have nicer tracking
5364 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5365 * that value.
5367 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5368 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5369 This->stateBlock->streamIsUP = TRUE;
5370 This->stateBlock->baseVertexIndex = 0;
5371 This->up_strided = DrawPrimStrideData;
5372 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5373 This->up_strided = NULL;
5374 return WINED3D_OK;
5377 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5378 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5379 * not callable by the app directly no parameter validation checks are needed here.
5381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5382 WINED3DLOCKED_BOX src;
5383 WINED3DLOCKED_BOX dst;
5384 HRESULT hr;
5385 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5387 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5388 * dirtification to improve loading performance.
5390 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5391 if(FAILED(hr)) return hr;
5392 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5393 if(FAILED(hr)) {
5394 IWineD3DVolume_UnlockBox(pSourceVolume);
5395 return hr;
5398 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5400 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5401 if(FAILED(hr)) {
5402 IWineD3DVolume_UnlockBox(pSourceVolume);
5403 } else {
5404 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5406 return hr;
5409 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5410 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5411 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5412 HRESULT hr = WINED3D_OK;
5413 WINED3DRESOURCETYPE sourceType;
5414 WINED3DRESOURCETYPE destinationType;
5415 int i ,levels;
5417 /* TODO: think about moving the code into IWineD3DBaseTexture */
5419 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5421 /* verify that the source and destination textures aren't NULL */
5422 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5423 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5424 This, pSourceTexture, pDestinationTexture);
5425 hr = WINED3DERR_INVALIDCALL;
5428 if (pSourceTexture == pDestinationTexture) {
5429 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5430 This, pSourceTexture, pDestinationTexture);
5431 hr = WINED3DERR_INVALIDCALL;
5433 /* Verify that the source and destination textures are the same type */
5434 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5435 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5437 if (sourceType != destinationType) {
5438 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5439 This);
5440 hr = WINED3DERR_INVALIDCALL;
5443 /* check that both textures have the identical numbers of levels */
5444 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5445 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5446 hr = WINED3DERR_INVALIDCALL;
5449 if (WINED3D_OK == hr) {
5451 /* Make sure that the destination texture is loaded */
5452 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5454 /* Update every surface level of the texture */
5455 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5457 switch (sourceType) {
5458 case WINED3DRTYPE_TEXTURE:
5460 IWineD3DSurface *srcSurface;
5461 IWineD3DSurface *destSurface;
5463 for (i = 0 ; i < levels ; ++i) {
5464 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5465 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5466 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5467 IWineD3DSurface_Release(srcSurface);
5468 IWineD3DSurface_Release(destSurface);
5469 if (WINED3D_OK != hr) {
5470 WARN("(%p) : Call to update surface failed\n", This);
5471 return hr;
5475 break;
5476 case WINED3DRTYPE_CUBETEXTURE:
5478 IWineD3DSurface *srcSurface;
5479 IWineD3DSurface *destSurface;
5480 WINED3DCUBEMAP_FACES faceType;
5482 for (i = 0 ; i < levels ; ++i) {
5483 /* Update each cube face */
5484 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5485 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5486 if (WINED3D_OK != hr) {
5487 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5488 } else {
5489 TRACE("Got srcSurface %p\n", srcSurface);
5491 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5492 if (WINED3D_OK != hr) {
5493 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5494 } else {
5495 TRACE("Got desrSurface %p\n", destSurface);
5497 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5498 IWineD3DSurface_Release(srcSurface);
5499 IWineD3DSurface_Release(destSurface);
5500 if (WINED3D_OK != hr) {
5501 WARN("(%p) : Call to update surface failed\n", This);
5502 return hr;
5507 break;
5509 case WINED3DRTYPE_VOLUMETEXTURE:
5511 IWineD3DVolume *srcVolume = NULL;
5512 IWineD3DVolume *destVolume = NULL;
5514 for (i = 0 ; i < levels ; ++i) {
5515 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5516 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5517 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5518 IWineD3DVolume_Release(srcVolume);
5519 IWineD3DVolume_Release(destVolume);
5520 if (WINED3D_OK != hr) {
5521 WARN("(%p) : Call to update volume failed\n", This);
5522 return hr;
5526 break;
5528 default:
5529 FIXME("(%p) : Unsupported source and destination type\n", This);
5530 hr = WINED3DERR_INVALIDCALL;
5534 return hr;
5537 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5538 IWineD3DSwapChain *swapChain;
5539 HRESULT hr;
5540 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5541 if(hr == WINED3D_OK) {
5542 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5543 IWineD3DSwapChain_Release(swapChain);
5545 return hr;
5548 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5550 /* return a sensible default */
5551 *pNumPasses = 1;
5552 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5553 FIXME("(%p) : stub\n", This);
5554 return WINED3D_OK;
5557 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5559 int i;
5561 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5562 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5563 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5564 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5569 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5571 int j;
5572 UINT NewSize;
5573 PALETTEENTRY **palettes;
5575 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5577 if (PaletteNumber >= MAX_PALETTES) {
5578 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5579 return WINED3DERR_INVALIDCALL;
5582 if (PaletteNumber >= This->NumberOfPalettes) {
5583 NewSize = This->NumberOfPalettes;
5584 do {
5585 NewSize *= 2;
5586 } while(PaletteNumber >= NewSize);
5587 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5588 if (!palettes) {
5589 ERR("Out of memory!\n");
5590 return E_OUTOFMEMORY;
5592 This->palettes = palettes;
5593 This->NumberOfPalettes = NewSize;
5596 if (!This->palettes[PaletteNumber]) {
5597 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5598 if (!This->palettes[PaletteNumber]) {
5599 ERR("Out of memory!\n");
5600 return E_OUTOFMEMORY;
5604 for (j = 0; j < 256; ++j) {
5605 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5606 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5607 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5608 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5610 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5611 TRACE("(%p) : returning\n", This);
5612 return WINED3D_OK;
5615 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5617 int j;
5618 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5619 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5620 /* What happens in such situation isn't documented; Native seems to silently abort
5621 on such conditions. Return Invalid Call. */
5622 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5623 return WINED3DERR_INVALIDCALL;
5625 for (j = 0; j < 256; ++j) {
5626 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5627 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5628 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5629 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5631 TRACE("(%p) : returning\n", This);
5632 return WINED3D_OK;
5635 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5637 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5638 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5639 (tested with reference rasterizer). Return Invalid Call. */
5640 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5641 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5642 return WINED3DERR_INVALIDCALL;
5644 /*TODO: stateblocks */
5645 if (This->currentPalette != PaletteNumber) {
5646 This->currentPalette = PaletteNumber;
5647 dirtify_p8_texture_samplers(This);
5649 TRACE("(%p) : returning\n", This);
5650 return WINED3D_OK;
5653 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5655 if (PaletteNumber == NULL) {
5656 WARN("(%p) : returning Invalid Call\n", This);
5657 return WINED3DERR_INVALIDCALL;
5659 /*TODO: stateblocks */
5660 *PaletteNumber = This->currentPalette;
5661 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5662 return WINED3D_OK;
5665 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5666 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5667 static BOOL showFixmes = TRUE;
5668 if (showFixmes) {
5669 FIXME("(%p) : stub\n", This);
5670 showFixmes = FALSE;
5673 This->softwareVertexProcessing = bSoftware;
5674 return WINED3D_OK;
5678 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5680 static BOOL showFixmes = TRUE;
5681 if (showFixmes) {
5682 FIXME("(%p) : stub\n", This);
5683 showFixmes = FALSE;
5685 return This->softwareVertexProcessing;
5689 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5691 IWineD3DSwapChain *swapChain;
5692 HRESULT hr;
5694 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5696 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5697 if(hr == WINED3D_OK){
5698 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5699 IWineD3DSwapChain_Release(swapChain);
5700 }else{
5701 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5703 return hr;
5707 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5709 static BOOL showfixmes = TRUE;
5710 if(nSegments != 0.0f) {
5711 if( showfixmes) {
5712 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5713 showfixmes = FALSE;
5716 return WINED3D_OK;
5719 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5721 static BOOL showfixmes = TRUE;
5722 if( showfixmes) {
5723 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5724 showfixmes = FALSE;
5726 return 0.0f;
5729 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5731 /** TODO: remove casts to IWineD3DSurfaceImpl
5732 * NOTE: move code to surface to accomplish this
5733 ****************************************/
5734 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5735 int srcWidth, srcHeight;
5736 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5737 WINED3DFORMAT destFormat, srcFormat;
5738 UINT destSize;
5739 int srcLeft, destLeft, destTop;
5740 WINED3DPOOL srcPool, destPool;
5741 int offset = 0;
5742 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5743 glDescriptor *glDescription = NULL;
5744 GLenum dummy;
5745 int bpp;
5746 CONVERT_TYPES convert = NO_CONVERSION;
5748 WINED3DSURFACE_DESC winedesc;
5750 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5751 memset(&winedesc, 0, sizeof(winedesc));
5752 winedesc.Width = &srcSurfaceWidth;
5753 winedesc.Height = &srcSurfaceHeight;
5754 winedesc.Pool = &srcPool;
5755 winedesc.Format = &srcFormat;
5757 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5759 winedesc.Width = &destSurfaceWidth;
5760 winedesc.Height = &destSurfaceHeight;
5761 winedesc.Pool = &destPool;
5762 winedesc.Format = &destFormat;
5763 winedesc.Size = &destSize;
5765 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5767 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5768 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5769 return WINED3DERR_INVALIDCALL;
5772 /* This call loads the opengl surface directly, instead of copying the surface to the
5773 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5774 * copy in sysmem and use regular surface loading.
5776 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5777 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5778 if(convert != NO_CONVERSION) {
5779 return IWineD3DSurface_BltFast(pDestinationSurface,
5780 pDestPoint ? pDestPoint->x : 0,
5781 pDestPoint ? pDestPoint->y : 0,
5782 pSourceSurface, (RECT *) pSourceRect, 0);
5785 if (destFormat == WINED3DFMT_UNKNOWN) {
5786 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5787 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5789 /* Get the update surface description */
5790 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5793 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5795 ENTER_GL();
5797 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5798 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5799 checkGLcall("glActiveTextureARB");
5802 /* Make sure the surface is loaded and up to date */
5803 IWineD3DSurface_PreLoad(pDestinationSurface);
5805 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5807 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5808 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5809 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5810 srcLeft = pSourceRect ? pSourceRect->left : 0;
5811 destLeft = pDestPoint ? pDestPoint->x : 0;
5812 destTop = pDestPoint ? pDestPoint->y : 0;
5815 /* This function doesn't support compressed textures
5816 the pitch is just bytesPerPixel * width */
5817 if(srcWidth != srcSurfaceWidth || srcLeft ){
5818 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5819 offset += srcLeft * pSrcSurface->bytesPerPixel;
5820 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5822 /* TODO DXT formats */
5824 if(pSourceRect != NULL && pSourceRect->top != 0){
5825 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5827 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5828 ,This
5829 ,glDescription->level
5830 ,destLeft
5831 ,destTop
5832 ,srcWidth
5833 ,srcHeight
5834 ,glDescription->glFormat
5835 ,glDescription->glType
5836 ,IWineD3DSurface_GetData(pSourceSurface)
5839 /* Sanity check */
5840 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5842 /* need to lock the surface to get the data */
5843 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5846 /* TODO: Cube and volume support */
5847 if(rowoffset != 0){
5848 /* not a whole row so we have to do it a line at a time */
5849 int j;
5851 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5852 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5854 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5856 glTexSubImage2D(glDescription->target
5857 ,glDescription->level
5858 ,destLeft
5860 ,srcWidth
5862 ,glDescription->glFormat
5863 ,glDescription->glType
5864 ,data /* could be quicker using */
5866 data += rowoffset;
5869 } else { /* Full width, so just write out the whole texture */
5871 if (WINED3DFMT_DXT1 == destFormat ||
5872 WINED3DFMT_DXT2 == destFormat ||
5873 WINED3DFMT_DXT3 == destFormat ||
5874 WINED3DFMT_DXT4 == destFormat ||
5875 WINED3DFMT_DXT5 == destFormat) {
5876 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5877 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5878 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5879 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5880 } if (destFormat != srcFormat) {
5881 FIXME("Updating mixed format compressed texture is not curretly support\n");
5882 } else {
5883 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5884 glDescription->level,
5885 glDescription->glFormatInternal,
5886 srcWidth,
5887 srcHeight,
5889 destSize,
5890 IWineD3DSurface_GetData(pSourceSurface));
5892 } else {
5893 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5897 } else {
5898 glTexSubImage2D(glDescription->target
5899 ,glDescription->level
5900 ,destLeft
5901 ,destTop
5902 ,srcWidth
5903 ,srcHeight
5904 ,glDescription->glFormat
5905 ,glDescription->glType
5906 ,IWineD3DSurface_GetData(pSourceSurface)
5910 checkGLcall("glTexSubImage2D");
5912 LEAVE_GL();
5914 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5915 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5917 return WINED3D_OK;
5920 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5922 struct WineD3DRectPatch *patch;
5923 unsigned int i;
5924 struct list *e;
5925 BOOL found;
5926 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5928 if(!(Handle || pRectPatchInfo)) {
5929 /* TODO: Write a test for the return value, thus the FIXME */
5930 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5931 return WINED3DERR_INVALIDCALL;
5934 if(Handle) {
5935 i = PATCHMAP_HASHFUNC(Handle);
5936 found = FALSE;
5937 LIST_FOR_EACH(e, &This->patches[i]) {
5938 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5939 if(patch->Handle == Handle) {
5940 found = TRUE;
5941 break;
5945 if(!found) {
5946 TRACE("Patch does not exist. Creating a new one\n");
5947 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5948 patch->Handle = Handle;
5949 list_add_head(&This->patches[i], &patch->entry);
5950 } else {
5951 TRACE("Found existing patch %p\n", patch);
5953 } else {
5954 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5955 * attributes we have to tesselate, read back, and draw. This needs a patch
5956 * management structure instance. Create one.
5958 * A possible improvement is to check if a vertex shader is used, and if not directly
5959 * draw the patch.
5961 FIXME("Drawing an uncached patch. This is slow\n");
5962 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5965 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5966 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5967 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5968 HRESULT hr;
5969 TRACE("Tesselation density or patch info changed, retesselating\n");
5971 if(pRectPatchInfo) {
5972 patch->RectPatchInfo = *pRectPatchInfo;
5974 patch->numSegs[0] = pNumSegs[0];
5975 patch->numSegs[1] = pNumSegs[1];
5976 patch->numSegs[2] = pNumSegs[2];
5977 patch->numSegs[3] = pNumSegs[3];
5979 hr = tesselate_rectpatch(This, patch);
5980 if(FAILED(hr)) {
5981 WARN("Patch tesselation failed\n");
5983 /* Do not release the handle to store the params of the patch */
5984 if(!Handle) {
5985 HeapFree(GetProcessHeap(), 0, patch);
5987 return hr;
5991 This->currentPatch = patch;
5992 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5993 This->currentPatch = NULL;
5995 /* Destroy uncached patches */
5996 if(!Handle) {
5997 HeapFree(GetProcessHeap(), 0, patch->mem);
5998 HeapFree(GetProcessHeap(), 0, patch);
6000 return WINED3D_OK;
6003 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6005 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6006 FIXME("(%p) : Stub\n", This);
6007 return WINED3D_OK;
6010 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6012 int i;
6013 struct WineD3DRectPatch *patch;
6014 struct list *e;
6015 TRACE("(%p) Handle(%d)\n", This, Handle);
6017 i = PATCHMAP_HASHFUNC(Handle);
6018 LIST_FOR_EACH(e, &This->patches[i]) {
6019 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6020 if(patch->Handle == Handle) {
6021 TRACE("Deleting patch %p\n", patch);
6022 list_remove(&patch->entry);
6023 HeapFree(GetProcessHeap(), 0, patch->mem);
6024 HeapFree(GetProcessHeap(), 0, patch);
6025 return WINED3D_OK;
6029 /* TODO: Write a test for the return value */
6030 FIXME("Attempt to destroy nonexistent patch\n");
6031 return WINED3DERR_INVALIDCALL;
6034 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6035 HRESULT hr;
6036 IWineD3DSwapChain *swapchain;
6038 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6039 if (SUCCEEDED(hr)) {
6040 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6041 return swapchain;
6044 return NULL;
6047 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
6048 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6050 if (!*fbo) {
6051 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
6052 checkGLcall("glGenFramebuffersEXT()");
6054 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
6055 checkGLcall("glBindFramebuffer()");
6058 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
6059 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
6060 IWineD3DBaseTextureImpl *texture_impl;
6061 GLenum texttarget, target;
6062 GLint old_binding;
6064 texttarget = surface_impl->glDescription.target;
6065 if(texttarget == GL_TEXTURE_2D) {
6066 target = GL_TEXTURE_2D;
6067 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6068 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6069 target = GL_TEXTURE_RECTANGLE_ARB;
6070 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6071 } else {
6072 target = GL_TEXTURE_CUBE_MAP_ARB;
6073 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6076 IWineD3DSurface_PreLoad(surface);
6078 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6079 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6080 glBindTexture(target, old_binding);
6082 /* Update base texture states array */
6083 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6084 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6085 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6086 if (texture_impl->baseTexture.bindCount) {
6087 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6090 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6093 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6094 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6096 checkGLcall("attach_surface_fbo");
6099 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6101 IWineD3DSwapChain *swapchain;
6103 swapchain = get_swapchain(surface);
6104 if (swapchain) {
6105 GLenum buffer;
6107 TRACE("Surface %p is onscreen\n", surface);
6109 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6110 buffer = surface_get_gl_buffer(surface, swapchain);
6111 glDrawBuffer(buffer);
6112 checkGLcall("glDrawBuffer()");
6113 } else {
6114 TRACE("Surface %p is offscreen\n", surface);
6115 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
6116 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6119 if (rect) {
6120 glEnable(GL_SCISSOR_TEST);
6121 if(!swapchain) {
6122 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6123 } else {
6124 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6125 rect->x2 - rect->x1, rect->y2 - rect->y1);
6127 checkGLcall("glScissor");
6128 } else {
6129 glDisable(GL_SCISSOR_TEST);
6131 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6133 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6134 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6136 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6137 glClear(GL_COLOR_BUFFER_BIT);
6138 checkGLcall("glClear");
6140 if (This->render_offscreen) {
6141 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6142 } else {
6143 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6144 checkGLcall("glBindFramebuffer()");
6147 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6148 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6149 glDrawBuffer(GL_BACK);
6150 checkGLcall("glDrawBuffer()");
6154 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6155 unsigned int r, g, b, a;
6156 DWORD ret;
6158 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6159 destfmt == WINED3DFMT_R8G8B8)
6160 return color;
6162 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6164 a = (color & 0xff000000) >> 24;
6165 r = (color & 0x00ff0000) >> 16;
6166 g = (color & 0x0000ff00) >> 8;
6167 b = (color & 0x000000ff) >> 0;
6169 switch(destfmt)
6171 case WINED3DFMT_R5G6B5:
6172 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6173 r = (r * 32) / 256;
6174 g = (g * 64) / 256;
6175 b = (b * 32) / 256;
6176 ret = r << 11;
6177 ret |= g << 5;
6178 ret |= b;
6179 TRACE("Returning %08x\n", ret);
6180 return ret;
6182 case WINED3DFMT_X1R5G5B5:
6183 case WINED3DFMT_A1R5G5B5:
6184 a = (a * 2) / 256;
6185 r = (r * 32) / 256;
6186 g = (g * 32) / 256;
6187 b = (b * 32) / 256;
6188 ret = a << 15;
6189 ret |= r << 10;
6190 ret |= g << 5;
6191 ret |= b << 0;
6192 TRACE("Returning %08x\n", ret);
6193 return ret;
6195 case WINED3DFMT_A8:
6196 TRACE("Returning %08x\n", a);
6197 return a;
6199 case WINED3DFMT_X4R4G4B4:
6200 case WINED3DFMT_A4R4G4B4:
6201 a = (a * 16) / 256;
6202 r = (r * 16) / 256;
6203 g = (g * 16) / 256;
6204 b = (b * 16) / 256;
6205 ret = a << 12;
6206 ret |= r << 8;
6207 ret |= g << 4;
6208 ret |= b << 0;
6209 TRACE("Returning %08x\n", ret);
6210 return ret;
6212 case WINED3DFMT_R3G3B2:
6213 r = (r * 8) / 256;
6214 g = (g * 8) / 256;
6215 b = (b * 4) / 256;
6216 ret = r << 5;
6217 ret |= g << 2;
6218 ret |= b << 0;
6219 TRACE("Returning %08x\n", ret);
6220 return ret;
6222 case WINED3DFMT_X8B8G8R8:
6223 case WINED3DFMT_A8B8G8R8:
6224 ret = a << 24;
6225 ret |= b << 16;
6226 ret |= g << 8;
6227 ret |= r << 0;
6228 TRACE("Returning %08x\n", ret);
6229 return ret;
6231 case WINED3DFMT_A2R10G10B10:
6232 a = (a * 4) / 256;
6233 r = (r * 1024) / 256;
6234 g = (g * 1024) / 256;
6235 b = (b * 1024) / 256;
6236 ret = a << 30;
6237 ret |= r << 20;
6238 ret |= g << 10;
6239 ret |= b << 0;
6240 TRACE("Returning %08x\n", ret);
6241 return ret;
6243 case WINED3DFMT_A2B10G10R10:
6244 a = (a * 4) / 256;
6245 r = (r * 1024) / 256;
6246 g = (g * 1024) / 256;
6247 b = (b * 1024) / 256;
6248 ret = a << 30;
6249 ret |= b << 20;
6250 ret |= g << 10;
6251 ret |= r << 0;
6252 TRACE("Returning %08x\n", ret);
6253 return ret;
6255 default:
6256 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6257 return 0;
6261 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6263 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6264 WINEDDBLTFX BltFx;
6265 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6267 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6268 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6269 return WINED3DERR_INVALIDCALL;
6272 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6273 ENTER_GL();
6274 color_fill_fbo(iface, pSurface, pRect, color);
6275 LEAVE_GL();
6276 return WINED3D_OK;
6277 } else {
6278 /* Just forward this to the DirectDraw blitting engine */
6279 memset(&BltFx, 0, sizeof(BltFx));
6280 BltFx.dwSize = sizeof(BltFx);
6281 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6282 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6286 /* rendertarget and depth stencil functions */
6287 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6290 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6291 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6292 return WINED3DERR_INVALIDCALL;
6295 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6296 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6297 /* Note inc ref on returned surface */
6298 if(*ppRenderTarget != NULL)
6299 IWineD3DSurface_AddRef(*ppRenderTarget);
6300 return WINED3D_OK;
6303 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6305 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6306 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6307 IWineD3DSwapChainImpl *Swapchain;
6308 HRESULT hr;
6310 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6312 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6313 if(hr != WINED3D_OK) {
6314 ERR("Can't get the swapchain\n");
6315 return hr;
6318 /* Make sure to release the swapchain */
6319 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6321 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6322 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6323 return WINED3DERR_INVALIDCALL;
6325 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6326 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6327 return WINED3DERR_INVALIDCALL;
6330 if(Swapchain->frontBuffer != Front) {
6331 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6333 if(Swapchain->frontBuffer)
6334 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6335 Swapchain->frontBuffer = Front;
6337 if(Swapchain->frontBuffer) {
6338 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6342 if(Back && !Swapchain->backBuffer) {
6343 /* We need memory for the back buffer array - only one back buffer this way */
6344 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6345 if(!Swapchain->backBuffer) {
6346 ERR("Out of memory\n");
6347 return E_OUTOFMEMORY;
6351 if(Swapchain->backBuffer[0] != Back) {
6352 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6354 /* What to do about the context here in the case of multithreading? Not sure.
6355 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6357 ENTER_GL();
6358 if(!Swapchain->backBuffer[0]) {
6359 /* GL was told to draw to the front buffer at creation,
6360 * undo that
6362 glDrawBuffer(GL_BACK);
6363 checkGLcall("glDrawBuffer(GL_BACK)");
6364 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6365 Swapchain->presentParms.BackBufferCount = 1;
6366 } else if (!Back) {
6367 /* That makes problems - disable for now */
6368 /* glDrawBuffer(GL_FRONT); */
6369 checkGLcall("glDrawBuffer(GL_FRONT)");
6370 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6371 Swapchain->presentParms.BackBufferCount = 0;
6373 LEAVE_GL();
6375 if(Swapchain->backBuffer[0])
6376 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6377 Swapchain->backBuffer[0] = Back;
6379 if(Swapchain->backBuffer[0]) {
6380 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6381 } else {
6382 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6383 Swapchain->backBuffer = NULL;
6388 return WINED3D_OK;
6391 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6393 *ppZStencilSurface = This->stencilBufferTarget;
6394 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6396 if(*ppZStencilSurface != NULL) {
6397 /* Note inc ref on returned surface */
6398 IWineD3DSurface_AddRef(*ppZStencilSurface);
6399 return WINED3D_OK;
6400 } else {
6401 return WINED3DERR_NOTFOUND;
6405 /* TODO: Handle stencil attachments */
6406 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6407 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6408 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6410 TRACE("Set depth stencil to %p\n", depth_stencil);
6412 if (depth_stencil_impl) {
6413 if (depth_stencil_impl->current_renderbuffer) {
6414 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6415 checkGLcall("glFramebufferRenderbufferEXT()");
6416 } else {
6417 IWineD3DBaseTextureImpl *texture_impl;
6418 GLenum texttarget, target;
6419 GLint old_binding = 0;
6421 texttarget = depth_stencil_impl->glDescription.target;
6422 if(texttarget == GL_TEXTURE_2D) {
6423 target = GL_TEXTURE_2D;
6424 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6425 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6426 target = GL_TEXTURE_RECTANGLE_ARB;
6427 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6428 } else {
6429 target = GL_TEXTURE_CUBE_MAP_ARB;
6430 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6433 IWineD3DSurface_PreLoad(depth_stencil);
6435 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6436 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6437 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6438 glBindTexture(target, old_binding);
6440 /* Update base texture states array */
6441 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6442 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6443 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6444 if (texture_impl->baseTexture.bindCount) {
6445 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6448 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6451 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6452 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6453 checkGLcall("glFramebufferTexture2DEXT()");
6455 } else {
6456 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6457 checkGLcall("glFramebufferTexture2DEXT()");
6461 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6463 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6465 TRACE("Set render target %u to %p\n", idx, render_target);
6467 if (rtimpl) {
6468 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6469 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6470 } else {
6471 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6472 checkGLcall("glFramebufferTexture2DEXT()");
6474 This->draw_buffers[idx] = GL_NONE;
6478 static void check_fbo_status(IWineD3DDevice *iface) {
6479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6480 GLenum status;
6482 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6483 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6484 TRACE("FBO complete\n");
6485 } else {
6486 IWineD3DSurfaceImpl *attachment;
6487 int i;
6488 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6490 /* Dump the FBO attachments */
6491 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6492 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6493 if (attachment) {
6494 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6495 attachment->pow2Width, attachment->pow2Height);
6498 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6499 if (attachment) {
6500 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6501 attachment->pow2Width, attachment->pow2Height);
6506 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6507 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6508 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6509 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6511 if (!ds_impl) return FALSE;
6513 if (ds_impl->current_renderbuffer) {
6514 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6515 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6518 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6519 rt_impl->pow2Height != ds_impl->pow2Height);
6522 void apply_fbo_state(IWineD3DDevice *iface) {
6523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6524 unsigned int i;
6526 if (This->render_offscreen) {
6527 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6529 /* Apply render targets */
6530 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6531 IWineD3DSurface *render_target = This->render_targets[i];
6532 if (This->fbo_color_attachments[i] != render_target) {
6533 set_render_target_fbo(iface, i, render_target);
6534 This->fbo_color_attachments[i] = render_target;
6538 /* Apply depth targets */
6539 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6540 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6541 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6543 if (This->stencilBufferTarget) {
6544 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6546 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6547 This->fbo_depth_attachment = This->stencilBufferTarget;
6550 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6551 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6552 checkGLcall("glDrawBuffers()");
6553 } else {
6554 glDrawBuffer(This->draw_buffers[0]);
6555 checkGLcall("glDrawBuffer()");
6557 } else {
6558 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6561 check_fbo_status(iface);
6564 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6565 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6566 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6567 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6568 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6569 GLenum gl_filter;
6571 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6572 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6573 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6574 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6576 switch (filter) {
6577 case WINED3DTEXF_LINEAR:
6578 gl_filter = GL_LINEAR;
6579 break;
6581 default:
6582 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6583 case WINED3DTEXF_NONE:
6584 case WINED3DTEXF_POINT:
6585 gl_filter = GL_NEAREST;
6586 break;
6589 /* Attach src surface to src fbo */
6590 src_swapchain = get_swapchain(src_surface);
6591 if (src_swapchain) {
6592 GLenum buffer;
6594 TRACE("Source surface %p is onscreen\n", src_surface);
6595 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6596 /* Make sure the drawable is up to date. In the offscreen case
6597 * attach_surface_fbo() implicitly takes care of this. */
6598 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6600 ENTER_GL();
6601 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6602 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6603 glReadBuffer(buffer);
6604 checkGLcall("glReadBuffer()");
6606 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6607 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6608 } else {
6609 TRACE("Source surface %p is offscreen\n", src_surface);
6610 ENTER_GL();
6611 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6612 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6613 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6614 checkGLcall("glReadBuffer()");
6616 LEAVE_GL();
6618 /* Attach dst surface to dst fbo */
6619 dst_swapchain = get_swapchain(dst_surface);
6620 if (dst_swapchain) {
6621 GLenum buffer;
6623 TRACE("Destination surface %p is onscreen\n", dst_surface);
6624 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6625 /* Make sure the drawable is up to date. In the offscreen case
6626 * attach_surface_fbo() implicitly takes care of this. */
6627 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6629 ENTER_GL();
6630 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6631 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6632 glDrawBuffer(buffer);
6633 checkGLcall("glDrawBuffer()");
6635 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6636 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6637 } else {
6638 TRACE("Destination surface %p is offscreen\n", dst_surface);
6640 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6641 if(!src_swapchain) {
6642 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6645 ENTER_GL();
6646 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6647 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6648 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6649 checkGLcall("glDrawBuffer()");
6651 glDisable(GL_SCISSOR_TEST);
6652 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6654 if (flip) {
6655 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6656 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6657 checkGLcall("glBlitFramebuffer()");
6658 } else {
6659 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6660 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6661 checkGLcall("glBlitFramebuffer()");
6664 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6666 if (This->render_offscreen) {
6667 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6668 } else {
6669 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6670 checkGLcall("glBindFramebuffer()");
6673 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6674 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6675 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6676 glDrawBuffer(GL_BACK);
6677 checkGLcall("glDrawBuffer()");
6679 LEAVE_GL();
6682 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6684 WINED3DVIEWPORT viewport;
6686 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6688 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6689 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6690 This, RenderTargetIndex, GL_LIMITS(buffers));
6691 return WINED3DERR_INVALIDCALL;
6694 /* MSDN says that null disables the render target
6695 but a device must always be associated with a render target
6696 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6698 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6699 FIXME("Trying to set render target 0 to NULL\n");
6700 return WINED3DERR_INVALIDCALL;
6702 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6703 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);
6704 return WINED3DERR_INVALIDCALL;
6707 /* If we are trying to set what we already have, don't bother */
6708 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6709 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6710 return WINED3D_OK;
6712 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6713 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6714 This->render_targets[RenderTargetIndex] = pRenderTarget;
6716 /* Render target 0 is special */
6717 if(RenderTargetIndex == 0) {
6718 /* Finally, reset the viewport as the MSDN states. */
6719 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6720 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6721 viewport.X = 0;
6722 viewport.Y = 0;
6723 viewport.MaxZ = 1.0f;
6724 viewport.MinZ = 0.0f;
6725 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6726 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6727 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6729 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6731 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6732 * ctx properly.
6733 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6734 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6736 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6738 return WINED3D_OK;
6741 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6743 HRESULT hr = WINED3D_OK;
6744 IWineD3DSurface *tmp;
6746 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6748 if (pNewZStencil == This->stencilBufferTarget) {
6749 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6750 } else {
6751 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6752 * depending on the renter target implementation being used.
6753 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6754 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6755 * stencil buffer and incur an extra memory overhead
6756 ******************************************************/
6758 tmp = This->stencilBufferTarget;
6759 This->stencilBufferTarget = pNewZStencil;
6760 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6761 /* should we be calling the parent or the wined3d surface? */
6762 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6763 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6764 hr = WINED3D_OK;
6766 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6767 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6768 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6769 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6770 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6774 return hr;
6777 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6778 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6780 /* TODO: the use of Impl is deprecated. */
6781 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6782 WINED3DLOCKED_RECT lockedRect;
6784 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6786 /* some basic validation checks */
6787 if(This->cursorTexture) {
6788 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6789 ENTER_GL();
6790 glDeleteTextures(1, &This->cursorTexture);
6791 LEAVE_GL();
6792 This->cursorTexture = 0;
6795 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6796 This->haveHardwareCursor = TRUE;
6797 else
6798 This->haveHardwareCursor = FALSE;
6800 if(pCursorBitmap) {
6801 WINED3DLOCKED_RECT rect;
6803 /* MSDN: Cursor must be A8R8G8B8 */
6804 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6805 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6806 return WINED3DERR_INVALIDCALL;
6809 /* MSDN: Cursor must be smaller than the display mode */
6810 if(pSur->currentDesc.Width > This->ddraw_width ||
6811 pSur->currentDesc.Height > This->ddraw_height) {
6812 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);
6813 return WINED3DERR_INVALIDCALL;
6816 if (!This->haveHardwareCursor) {
6817 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6819 /* Do not store the surface's pointer because the application may
6820 * release it after setting the cursor image. Windows doesn't
6821 * addref the set surface, so we can't do this either without
6822 * creating circular refcount dependencies. Copy out the gl texture
6823 * instead.
6825 This->cursorWidth = pSur->currentDesc.Width;
6826 This->cursorHeight = pSur->currentDesc.Height;
6827 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6829 const GlPixelFormatDesc *glDesc;
6830 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6831 char *mem, *bits = (char *)rect.pBits;
6832 GLint intfmt = glDesc->glInternal;
6833 GLint format = glDesc->glFormat;
6834 GLint type = glDesc->glType;
6835 INT height = This->cursorHeight;
6836 INT width = This->cursorWidth;
6837 INT bpp = tableEntry->bpp;
6838 INT i;
6840 /* Reformat the texture memory (pitch and width can be
6841 * different) */
6842 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6843 for(i = 0; i < height; i++)
6844 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6845 IWineD3DSurface_UnlockRect(pCursorBitmap);
6846 ENTER_GL();
6848 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6849 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6850 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6853 /* Make sure that a proper texture unit is selected */
6854 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6855 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6856 checkGLcall("glActiveTextureARB");
6858 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6859 /* Create a new cursor texture */
6860 glGenTextures(1, &This->cursorTexture);
6861 checkGLcall("glGenTextures");
6862 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6863 checkGLcall("glBindTexture");
6864 /* Copy the bitmap memory into the cursor texture */
6865 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6866 HeapFree(GetProcessHeap(), 0, mem);
6867 checkGLcall("glTexImage2D");
6869 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6870 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6871 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6874 LEAVE_GL();
6876 else
6878 FIXME("A cursor texture was not returned.\n");
6879 This->cursorTexture = 0;
6882 else
6884 /* Draw a hardware cursor */
6885 ICONINFO cursorInfo;
6886 HCURSOR cursor;
6887 /* Create and clear maskBits because it is not needed for
6888 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6889 * chunks. */
6890 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6891 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6892 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6893 WINED3DLOCK_NO_DIRTY_UPDATE |
6894 WINED3DLOCK_READONLY
6896 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6897 pSur->currentDesc.Height);
6899 cursorInfo.fIcon = FALSE;
6900 cursorInfo.xHotspot = XHotSpot;
6901 cursorInfo.yHotspot = YHotSpot;
6902 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6903 pSur->currentDesc.Height, 1,
6904 1, &maskBits);
6905 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6906 pSur->currentDesc.Height, 1,
6907 32, lockedRect.pBits);
6908 IWineD3DSurface_UnlockRect(pCursorBitmap);
6909 /* Create our cursor and clean up. */
6910 cursor = CreateIconIndirect(&cursorInfo);
6911 SetCursor(cursor);
6912 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6913 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6914 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6915 This->hardwareCursor = cursor;
6916 HeapFree(GetProcessHeap(), 0, maskBits);
6920 This->xHotSpot = XHotSpot;
6921 This->yHotSpot = YHotSpot;
6922 return WINED3D_OK;
6925 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6927 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6929 This->xScreenSpace = XScreenSpace;
6930 This->yScreenSpace = YScreenSpace;
6932 return;
6936 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6938 BOOL oldVisible = This->bCursorVisible;
6939 POINT pt;
6941 TRACE("(%p) : visible(%d)\n", This, bShow);
6944 * When ShowCursor is first called it should make the cursor appear at the OS's last
6945 * known cursor position. Because of this, some applications just repetitively call
6946 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6948 GetCursorPos(&pt);
6949 This->xScreenSpace = pt.x;
6950 This->yScreenSpace = pt.y;
6952 if (This->haveHardwareCursor) {
6953 This->bCursorVisible = bShow;
6954 if (bShow)
6955 SetCursor(This->hardwareCursor);
6956 else
6957 SetCursor(NULL);
6959 else
6961 if (This->cursorTexture)
6962 This->bCursorVisible = bShow;
6965 return oldVisible;
6968 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6970 IWineD3DResourceImpl *resource;
6971 TRACE("(%p) : state (%u)\n", This, This->state);
6973 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6974 switch (This->state) {
6975 case WINED3D_OK:
6976 return WINED3D_OK;
6977 case WINED3DERR_DEVICELOST:
6979 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6980 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6981 return WINED3DERR_DEVICENOTRESET;
6983 return WINED3DERR_DEVICELOST;
6985 case WINED3DERR_DRIVERINTERNALERROR:
6986 return WINED3DERR_DRIVERINTERNALERROR;
6989 /* Unknown state */
6990 return WINED3DERR_DRIVERINTERNALERROR;
6994 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6996 /** FIXME: Resource tracking needs to be done,
6997 * The closes we can do to this is set the priorities of all managed textures low
6998 * and then reset them.
6999 ***********************************************************/
7000 FIXME("(%p) : stub\n", This);
7001 return WINED3D_OK;
7004 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7005 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7007 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7008 if(surface->Flags & SFLAG_DIBSECTION) {
7009 /* Release the DC */
7010 SelectObject(surface->hDC, surface->dib.holdbitmap);
7011 DeleteDC(surface->hDC);
7012 /* Release the DIB section */
7013 DeleteObject(surface->dib.DIBsection);
7014 surface->dib.bitmap_data = NULL;
7015 surface->resource.allocatedMemory = NULL;
7016 surface->Flags &= ~SFLAG_DIBSECTION;
7018 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7019 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7020 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE)) {
7021 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7022 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7023 } else {
7024 surface->pow2Width = surface->pow2Height = 1;
7025 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7026 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7028 surface->glRect.left = 0;
7029 surface->glRect.top = 0;
7030 surface->glRect.right = surface->pow2Width;
7031 surface->glRect.bottom = surface->pow2Height;
7033 if(surface->glDescription.textureName) {
7034 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7035 ENTER_GL();
7036 glDeleteTextures(1, &surface->glDescription.textureName);
7037 LEAVE_GL();
7038 surface->glDescription.textureName = 0;
7039 surface->Flags &= ~SFLAG_CLIENT;
7041 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7042 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7043 surface->Flags |= SFLAG_NONPOW2;
7044 } else {
7045 surface->Flags &= ~SFLAG_NONPOW2;
7047 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7048 surface->resource.allocatedMemory = NULL;
7049 surface->resource.heapMemory = NULL;
7050 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7051 /* INDRAWABLE is a sane place for implicit targets / depth stencil after the reset */
7052 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7055 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7056 TRACE("Unloading resource %p\n", resource);
7057 IWineD3DResource_UnLoad(resource);
7058 IWineD3DResource_Release(resource);
7059 return S_OK;
7062 static void reset_fbo_state(IWineD3DDevice *iface) {
7063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7064 unsigned int i;
7066 ENTER_GL();
7067 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7068 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
7070 if (This->fbo) {
7071 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
7072 This->fbo = 0;
7074 if (This->src_fbo) {
7075 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
7076 This->src_fbo = 0;
7078 if (This->dst_fbo) {
7079 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
7080 This->dst_fbo = 0;
7082 checkGLcall("Tear down FBOs\n");
7083 LEAVE_GL();
7085 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7086 This->fbo_color_attachments[i] = NULL;
7088 This->fbo_depth_attachment = NULL;
7091 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7092 UINT i, count;
7093 WINED3DDISPLAYMODE m;
7094 HRESULT hr;
7096 /* All Windowed modes are supported, as is leaving the current mode */
7097 if(pp->Windowed) return TRUE;
7098 if(!pp->BackBufferWidth) return TRUE;
7099 if(!pp->BackBufferHeight) return TRUE;
7101 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7102 for(i = 0; i < count; i++) {
7103 memset(&m, 0, sizeof(m));
7104 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7105 if(FAILED(hr)) {
7106 ERR("EnumAdapterModes failed\n");
7108 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7109 /* Mode found, it is supported */
7110 return TRUE;
7113 /* Mode not found -> not supported */
7114 return FALSE;
7117 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7119 IWineD3DSwapChainImpl *swapchain;
7120 HRESULT hr;
7121 BOOL DisplayModeChanged = FALSE;
7122 WINED3DDISPLAYMODE mode;
7123 IWineD3DBaseShaderImpl *shader;
7124 IWineD3DSurfaceImpl *target;
7125 UINT i;
7126 TRACE("(%p)\n", This);
7128 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7129 if(FAILED(hr)) {
7130 ERR("Failed to get the first implicit swapchain\n");
7131 return hr;
7134 if(!is_display_mode_supported(This, pPresentationParameters)) {
7135 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7136 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7137 pPresentationParameters->BackBufferHeight);
7138 return WINED3DERR_INVALIDCALL;
7141 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7142 * on an existing gl context, so there's no real need for recreation.
7144 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7146 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7148 TRACE("New params:\n");
7149 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7150 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7151 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7152 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7153 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7154 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7155 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7156 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7157 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7158 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7159 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7160 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7161 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7163 /* No special treatment of these parameters. Just store them */
7164 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7165 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7166 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7167 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7169 /* What to do about these? */
7170 if(pPresentationParameters->BackBufferCount != 0 &&
7171 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7172 ERR("Cannot change the back buffer count yet\n");
7174 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7175 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7176 ERR("Cannot change the back buffer format yet\n");
7178 if(pPresentationParameters->hDeviceWindow != NULL &&
7179 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7180 ERR("Cannot change the device window yet\n");
7182 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7183 ERR("What do do about a changed auto depth stencil parameter?\n");
7186 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7187 reset_fbo_state((IWineD3DDevice *) This);
7190 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7191 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7192 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7195 ENTER_GL();
7196 if(This->depth_blt_texture) {
7197 glDeleteTextures(1, &This->depth_blt_texture);
7198 This->depth_blt_texture = 0;
7200 This->shader_backend->shader_destroy_depth_blt(iface);
7201 This->shader_backend->shader_free_private(iface);
7203 for (i = 0; i < GL_LIMITS(textures); i++) {
7204 /* Textures are recreated below */
7205 glDeleteTextures(1, &This->dummyTextureName[i]);
7206 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7207 This->dummyTextureName[i] = 0;
7209 LEAVE_GL();
7211 while(This->numContexts) {
7212 DestroyContext(This, This->contexts[0]);
7214 This->activeContext = NULL;
7215 HeapFree(GetProcessHeap(), 0, swapchain->context);
7216 swapchain->context = NULL;
7217 swapchain->num_contexts = 0;
7219 if(pPresentationParameters->Windowed) {
7220 mode.Width = swapchain->orig_width;
7221 mode.Height = swapchain->orig_height;
7222 mode.RefreshRate = 0;
7223 mode.Format = swapchain->presentParms.BackBufferFormat;
7224 } else {
7225 mode.Width = pPresentationParameters->BackBufferWidth;
7226 mode.Height = pPresentationParameters->BackBufferHeight;
7227 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7228 mode.Format = swapchain->presentParms.BackBufferFormat;
7231 /* Should Width == 800 && Height == 0 set 800x600? */
7232 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7233 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7234 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7236 WINED3DVIEWPORT vp;
7237 int i;
7239 vp.X = 0;
7240 vp.Y = 0;
7241 vp.Width = pPresentationParameters->BackBufferWidth;
7242 vp.Height = pPresentationParameters->BackBufferHeight;
7243 vp.MinZ = 0;
7244 vp.MaxZ = 1;
7246 if(!pPresentationParameters->Windowed) {
7247 DisplayModeChanged = TRUE;
7249 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7250 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7252 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7253 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7254 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7256 if(This->auto_depth_stencil_buffer) {
7257 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7261 /* Now set the new viewport */
7262 IWineD3DDevice_SetViewport(iface, &vp);
7265 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7266 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7267 DisplayModeChanged) {
7269 IWineD3DDevice_SetFullscreen(iface, !pPresentationParameters->Windowed);
7270 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7271 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7272 } else if(!pPresentationParameters->Windowed) {
7273 DWORD style = This->style, exStyle = This->exStyle;
7274 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7275 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7276 * Reset to clear up their mess. Guild Wars also loses the device during that.
7278 This->style = 0;
7279 This->exStyle = 0;
7280 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
7281 This->style = style;
7282 This->exStyle = exStyle;
7285 /* Recreate the primary swapchain's context */
7286 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7287 if(swapchain->backBuffer) {
7288 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7289 } else {
7290 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7292 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7293 &swapchain->presentParms);
7294 swapchain->num_contexts = 1;
7295 This->activeContext = swapchain->context[0];
7296 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7298 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7299 if(FAILED(hr)) {
7300 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7302 create_dummy_textures(This);
7305 hr = This->shader_backend->shader_alloc_private(iface);
7306 if(FAILED(hr)) {
7307 ERR("Failed to recreate shader private data\n");
7308 return hr;
7311 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7312 * first use
7314 return WINED3D_OK;
7317 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7319 /** FIXME: always true at the moment **/
7320 if(!bEnableDialogs) {
7321 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7323 return WINED3D_OK;
7327 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7329 TRACE("(%p) : pParameters %p\n", This, pParameters);
7331 *pParameters = This->createParms;
7332 return WINED3D_OK;
7335 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7336 IWineD3DSwapChain *swapchain;
7337 HRESULT hrc = WINED3D_OK;
7339 TRACE("Relaying to swapchain\n");
7341 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7342 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7343 IWineD3DSwapChain_Release(swapchain);
7345 return;
7348 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7349 IWineD3DSwapChain *swapchain;
7350 HRESULT hrc = WINED3D_OK;
7352 TRACE("Relaying to swapchain\n");
7354 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7355 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7356 IWineD3DSwapChain_Release(swapchain);
7358 return;
7362 /** ********************************************************
7363 * Notification functions
7364 ** ********************************************************/
7365 /** This function must be called in the release of a resource when ref == 0,
7366 * the contents of resource must still be correct,
7367 * any handles to other resource held by the caller must be closed
7368 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7369 *****************************************************/
7370 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7371 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7373 TRACE("(%p) : Adding Resource %p\n", This, resource);
7374 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7377 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7380 TRACE("(%p) : Removing resource %p\n", This, resource);
7382 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7386 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7388 int counter;
7390 TRACE("(%p) : resource %p\n", This, resource);
7391 switch(IWineD3DResource_GetType(resource)){
7392 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7393 case WINED3DRTYPE_SURFACE: {
7394 unsigned int i;
7396 /* Cleanup any FBO attachments if d3d is enabled */
7397 if(This->d3d_initialized) {
7398 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7399 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7401 TRACE("Last active render target destroyed\n");
7402 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7403 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7404 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7405 * and the lastActiveRenderTarget member shouldn't matter
7407 if(swapchain) {
7408 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7409 TRACE("Activating primary back buffer\n");
7410 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7411 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7412 /* Single buffering environment */
7413 TRACE("Activating primary front buffer\n");
7414 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7415 } else {
7416 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7417 /* Implicit render target destroyed, that means the device is being destroyed
7418 * whatever we set here, it shouldn't matter
7420 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7422 } else {
7423 /* May happen during ddraw uninitialization */
7424 TRACE("Render target set, but swapchain does not exist!\n");
7425 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7429 ENTER_GL();
7430 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7431 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7432 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7433 set_render_target_fbo(iface, i, NULL);
7434 This->fbo_color_attachments[i] = NULL;
7437 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7438 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7439 set_depth_stencil_fbo(iface, NULL);
7440 This->fbo_depth_attachment = NULL;
7442 LEAVE_GL();
7445 break;
7447 case WINED3DRTYPE_TEXTURE:
7448 case WINED3DRTYPE_CUBETEXTURE:
7449 case WINED3DRTYPE_VOLUMETEXTURE:
7450 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7451 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7452 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7453 This->stateBlock->textures[counter] = NULL;
7455 if (This->updateStateBlock != This->stateBlock ){
7456 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7457 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7458 This->updateStateBlock->textures[counter] = NULL;
7462 break;
7463 case WINED3DRTYPE_VOLUME:
7464 /* TODO: nothing really? */
7465 break;
7466 case WINED3DRTYPE_VERTEXBUFFER:
7467 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7469 int streamNumber;
7470 TRACE("Cleaning up stream pointers\n");
7472 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7473 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7474 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7476 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7477 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7478 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7479 This->updateStateBlock->streamSource[streamNumber] = 0;
7480 /* Set changed flag? */
7483 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) */
7484 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7485 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7486 This->stateBlock->streamSource[streamNumber] = 0;
7489 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7490 else { /* This shouldn't happen */
7491 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7493 #endif
7497 break;
7498 case WINED3DRTYPE_INDEXBUFFER:
7499 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7500 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7501 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7502 This->updateStateBlock->pIndexData = NULL;
7505 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7506 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7507 This->stateBlock->pIndexData = NULL;
7511 break;
7512 default:
7513 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7514 break;
7518 /* Remove the resource from the resourceStore */
7519 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7521 TRACE("Resource released\n");
7525 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7527 IWineD3DResourceImpl *resource, *cursor;
7528 HRESULT ret;
7529 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7531 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7532 TRACE("enumerating resource %p\n", resource);
7533 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7534 ret = pCallback((IWineD3DResource *) resource, pData);
7535 if(ret == S_FALSE) {
7536 TRACE("Canceling enumeration\n");
7537 break;
7540 return WINED3D_OK;
7543 /**********************************************************
7544 * IWineD3DDevice VTbl follows
7545 **********************************************************/
7547 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7549 /*** IUnknown methods ***/
7550 IWineD3DDeviceImpl_QueryInterface,
7551 IWineD3DDeviceImpl_AddRef,
7552 IWineD3DDeviceImpl_Release,
7553 /*** IWineD3DDevice methods ***/
7554 IWineD3DDeviceImpl_GetParent,
7555 /*** Creation methods**/
7556 IWineD3DDeviceImpl_CreateVertexBuffer,
7557 IWineD3DDeviceImpl_CreateIndexBuffer,
7558 IWineD3DDeviceImpl_CreateStateBlock,
7559 IWineD3DDeviceImpl_CreateSurface,
7560 IWineD3DDeviceImpl_CreateTexture,
7561 IWineD3DDeviceImpl_CreateVolumeTexture,
7562 IWineD3DDeviceImpl_CreateVolume,
7563 IWineD3DDeviceImpl_CreateCubeTexture,
7564 IWineD3DDeviceImpl_CreateQuery,
7565 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7566 IWineD3DDeviceImpl_CreateVertexDeclaration,
7567 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7568 IWineD3DDeviceImpl_CreateVertexShader,
7569 IWineD3DDeviceImpl_CreatePixelShader,
7570 IWineD3DDeviceImpl_CreatePalette,
7571 /*** Odd functions **/
7572 IWineD3DDeviceImpl_Init3D,
7573 IWineD3DDeviceImpl_Uninit3D,
7574 IWineD3DDeviceImpl_SetFullscreen,
7575 IWineD3DDeviceImpl_SetMultithreaded,
7576 IWineD3DDeviceImpl_EvictManagedResources,
7577 IWineD3DDeviceImpl_GetAvailableTextureMem,
7578 IWineD3DDeviceImpl_GetBackBuffer,
7579 IWineD3DDeviceImpl_GetCreationParameters,
7580 IWineD3DDeviceImpl_GetDeviceCaps,
7581 IWineD3DDeviceImpl_GetDirect3D,
7582 IWineD3DDeviceImpl_GetDisplayMode,
7583 IWineD3DDeviceImpl_SetDisplayMode,
7584 IWineD3DDeviceImpl_GetHWND,
7585 IWineD3DDeviceImpl_SetHWND,
7586 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7587 IWineD3DDeviceImpl_GetRasterStatus,
7588 IWineD3DDeviceImpl_GetSwapChain,
7589 IWineD3DDeviceImpl_Reset,
7590 IWineD3DDeviceImpl_SetDialogBoxMode,
7591 IWineD3DDeviceImpl_SetCursorProperties,
7592 IWineD3DDeviceImpl_SetCursorPosition,
7593 IWineD3DDeviceImpl_ShowCursor,
7594 IWineD3DDeviceImpl_TestCooperativeLevel,
7595 /*** Getters and setters **/
7596 IWineD3DDeviceImpl_SetClipPlane,
7597 IWineD3DDeviceImpl_GetClipPlane,
7598 IWineD3DDeviceImpl_SetClipStatus,
7599 IWineD3DDeviceImpl_GetClipStatus,
7600 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7601 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7602 IWineD3DDeviceImpl_SetDepthStencilSurface,
7603 IWineD3DDeviceImpl_GetDepthStencilSurface,
7604 IWineD3DDeviceImpl_SetFVF,
7605 IWineD3DDeviceImpl_GetFVF,
7606 IWineD3DDeviceImpl_SetGammaRamp,
7607 IWineD3DDeviceImpl_GetGammaRamp,
7608 IWineD3DDeviceImpl_SetIndices,
7609 IWineD3DDeviceImpl_GetIndices,
7610 IWineD3DDeviceImpl_SetBaseVertexIndex,
7611 IWineD3DDeviceImpl_GetBaseVertexIndex,
7612 IWineD3DDeviceImpl_SetLight,
7613 IWineD3DDeviceImpl_GetLight,
7614 IWineD3DDeviceImpl_SetLightEnable,
7615 IWineD3DDeviceImpl_GetLightEnable,
7616 IWineD3DDeviceImpl_SetMaterial,
7617 IWineD3DDeviceImpl_GetMaterial,
7618 IWineD3DDeviceImpl_SetNPatchMode,
7619 IWineD3DDeviceImpl_GetNPatchMode,
7620 IWineD3DDeviceImpl_SetPaletteEntries,
7621 IWineD3DDeviceImpl_GetPaletteEntries,
7622 IWineD3DDeviceImpl_SetPixelShader,
7623 IWineD3DDeviceImpl_GetPixelShader,
7624 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7625 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7626 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7627 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7628 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7629 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7630 IWineD3DDeviceImpl_SetRenderState,
7631 IWineD3DDeviceImpl_GetRenderState,
7632 IWineD3DDeviceImpl_SetRenderTarget,
7633 IWineD3DDeviceImpl_GetRenderTarget,
7634 IWineD3DDeviceImpl_SetFrontBackBuffers,
7635 IWineD3DDeviceImpl_SetSamplerState,
7636 IWineD3DDeviceImpl_GetSamplerState,
7637 IWineD3DDeviceImpl_SetScissorRect,
7638 IWineD3DDeviceImpl_GetScissorRect,
7639 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7640 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7641 IWineD3DDeviceImpl_SetStreamSource,
7642 IWineD3DDeviceImpl_GetStreamSource,
7643 IWineD3DDeviceImpl_SetStreamSourceFreq,
7644 IWineD3DDeviceImpl_GetStreamSourceFreq,
7645 IWineD3DDeviceImpl_SetTexture,
7646 IWineD3DDeviceImpl_GetTexture,
7647 IWineD3DDeviceImpl_SetTextureStageState,
7648 IWineD3DDeviceImpl_GetTextureStageState,
7649 IWineD3DDeviceImpl_SetTransform,
7650 IWineD3DDeviceImpl_GetTransform,
7651 IWineD3DDeviceImpl_SetVertexDeclaration,
7652 IWineD3DDeviceImpl_GetVertexDeclaration,
7653 IWineD3DDeviceImpl_SetVertexShader,
7654 IWineD3DDeviceImpl_GetVertexShader,
7655 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7656 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7657 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7658 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7659 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7660 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7661 IWineD3DDeviceImpl_SetViewport,
7662 IWineD3DDeviceImpl_GetViewport,
7663 IWineD3DDeviceImpl_MultiplyTransform,
7664 IWineD3DDeviceImpl_ValidateDevice,
7665 IWineD3DDeviceImpl_ProcessVertices,
7666 /*** State block ***/
7667 IWineD3DDeviceImpl_BeginStateBlock,
7668 IWineD3DDeviceImpl_EndStateBlock,
7669 /*** Scene management ***/
7670 IWineD3DDeviceImpl_BeginScene,
7671 IWineD3DDeviceImpl_EndScene,
7672 IWineD3DDeviceImpl_Present,
7673 IWineD3DDeviceImpl_Clear,
7674 /*** Drawing ***/
7675 IWineD3DDeviceImpl_DrawPrimitive,
7676 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7677 IWineD3DDeviceImpl_DrawPrimitiveUP,
7678 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7679 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7680 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7681 IWineD3DDeviceImpl_DrawRectPatch,
7682 IWineD3DDeviceImpl_DrawTriPatch,
7683 IWineD3DDeviceImpl_DeletePatch,
7684 IWineD3DDeviceImpl_ColorFill,
7685 IWineD3DDeviceImpl_UpdateTexture,
7686 IWineD3DDeviceImpl_UpdateSurface,
7687 IWineD3DDeviceImpl_GetFrontBufferData,
7688 /*** object tracking ***/
7689 IWineD3DDeviceImpl_ResourceReleased,
7690 IWineD3DDeviceImpl_EnumResources
7693 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7695 /*** IUnknown methods ***/
7696 IWineD3DDeviceImpl_QueryInterface,
7697 IWineD3DDeviceImpl_AddRef,
7698 IWineD3DDeviceImpl_Release,
7699 /*** IWineD3DDevice methods ***/
7700 IWineD3DDeviceImpl_GetParent,
7701 /*** Creation methods**/
7702 IWineD3DDeviceImpl_CreateVertexBuffer,
7703 IWineD3DDeviceImpl_CreateIndexBuffer,
7704 IWineD3DDeviceImpl_CreateStateBlock,
7705 IWineD3DDeviceImpl_CreateSurface,
7706 IWineD3DDeviceImpl_CreateTexture,
7707 IWineD3DDeviceImpl_CreateVolumeTexture,
7708 IWineD3DDeviceImpl_CreateVolume,
7709 IWineD3DDeviceImpl_CreateCubeTexture,
7710 IWineD3DDeviceImpl_CreateQuery,
7711 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7712 IWineD3DDeviceImpl_CreateVertexDeclaration,
7713 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7714 IWineD3DDeviceImpl_CreateVertexShader,
7715 IWineD3DDeviceImpl_CreatePixelShader,
7716 IWineD3DDeviceImpl_CreatePalette,
7717 /*** Odd functions **/
7718 IWineD3DDeviceImpl_Init3D,
7719 IWineD3DDeviceImpl_Uninit3D,
7720 IWineD3DDeviceImpl_SetFullscreen,
7721 IWineD3DDeviceImpl_SetMultithreaded,
7722 IWineD3DDeviceImpl_EvictManagedResources,
7723 IWineD3DDeviceImpl_GetAvailableTextureMem,
7724 IWineD3DDeviceImpl_GetBackBuffer,
7725 IWineD3DDeviceImpl_GetCreationParameters,
7726 IWineD3DDeviceImpl_GetDeviceCaps,
7727 IWineD3DDeviceImpl_GetDirect3D,
7728 IWineD3DDeviceImpl_GetDisplayMode,
7729 IWineD3DDeviceImpl_SetDisplayMode,
7730 IWineD3DDeviceImpl_GetHWND,
7731 IWineD3DDeviceImpl_SetHWND,
7732 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7733 IWineD3DDeviceImpl_GetRasterStatus,
7734 IWineD3DDeviceImpl_GetSwapChain,
7735 IWineD3DDeviceImpl_Reset,
7736 IWineD3DDeviceImpl_SetDialogBoxMode,
7737 IWineD3DDeviceImpl_SetCursorProperties,
7738 IWineD3DDeviceImpl_SetCursorPosition,
7739 IWineD3DDeviceImpl_ShowCursor,
7740 IWineD3DDeviceImpl_TestCooperativeLevel,
7741 /*** Getters and setters **/
7742 IWineD3DDeviceImpl_SetClipPlane,
7743 IWineD3DDeviceImpl_GetClipPlane,
7744 IWineD3DDeviceImpl_SetClipStatus,
7745 IWineD3DDeviceImpl_GetClipStatus,
7746 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7747 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7748 IWineD3DDeviceImpl_SetDepthStencilSurface,
7749 IWineD3DDeviceImpl_GetDepthStencilSurface,
7750 IWineD3DDeviceImpl_SetFVF,
7751 IWineD3DDeviceImpl_GetFVF,
7752 IWineD3DDeviceImpl_SetGammaRamp,
7753 IWineD3DDeviceImpl_GetGammaRamp,
7754 IWineD3DDeviceImpl_SetIndices,
7755 IWineD3DDeviceImpl_GetIndices,
7756 IWineD3DDeviceImpl_SetBaseVertexIndex,
7757 IWineD3DDeviceImpl_GetBaseVertexIndex,
7758 IWineD3DDeviceImpl_SetLight,
7759 IWineD3DDeviceImpl_GetLight,
7760 IWineD3DDeviceImpl_SetLightEnable,
7761 IWineD3DDeviceImpl_GetLightEnable,
7762 IWineD3DDeviceImpl_SetMaterial,
7763 IWineD3DDeviceImpl_GetMaterial,
7764 IWineD3DDeviceImpl_SetNPatchMode,
7765 IWineD3DDeviceImpl_GetNPatchMode,
7766 IWineD3DDeviceImpl_SetPaletteEntries,
7767 IWineD3DDeviceImpl_GetPaletteEntries,
7768 IWineD3DDeviceImpl_SetPixelShader,
7769 IWineD3DDeviceImpl_GetPixelShader,
7770 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7771 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7772 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7773 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7774 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7775 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7776 IWineD3DDeviceImpl_SetRenderState,
7777 IWineD3DDeviceImpl_GetRenderState,
7778 IWineD3DDeviceImpl_SetRenderTarget,
7779 IWineD3DDeviceImpl_GetRenderTarget,
7780 IWineD3DDeviceImpl_SetFrontBackBuffers,
7781 IWineD3DDeviceImpl_SetSamplerState,
7782 IWineD3DDeviceImpl_GetSamplerState,
7783 IWineD3DDeviceImpl_SetScissorRect,
7784 IWineD3DDeviceImpl_GetScissorRect,
7785 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7786 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7787 IWineD3DDeviceImpl_SetStreamSource,
7788 IWineD3DDeviceImpl_GetStreamSource,
7789 IWineD3DDeviceImpl_SetStreamSourceFreq,
7790 IWineD3DDeviceImpl_GetStreamSourceFreq,
7791 IWineD3DDeviceImpl_SetTexture,
7792 IWineD3DDeviceImpl_GetTexture,
7793 IWineD3DDeviceImpl_SetTextureStageState,
7794 IWineD3DDeviceImpl_GetTextureStageState,
7795 IWineD3DDeviceImpl_SetTransform,
7796 IWineD3DDeviceImpl_GetTransform,
7797 IWineD3DDeviceImpl_SetVertexDeclaration,
7798 IWineD3DDeviceImpl_GetVertexDeclaration,
7799 IWineD3DDeviceImpl_SetVertexShader,
7800 IWineD3DDeviceImpl_GetVertexShader,
7801 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7802 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7803 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7804 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7805 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7806 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7807 IWineD3DDeviceImpl_SetViewport,
7808 IWineD3DDeviceImpl_GetViewport,
7809 IWineD3DDeviceImpl_MultiplyTransform,
7810 IWineD3DDeviceImpl_ValidateDevice,
7811 IWineD3DDeviceImpl_ProcessVertices,
7812 /*** State block ***/
7813 IWineD3DDeviceImpl_BeginStateBlock,
7814 IWineD3DDeviceImpl_EndStateBlock,
7815 /*** Scene management ***/
7816 IWineD3DDeviceImpl_BeginScene,
7817 IWineD3DDeviceImpl_EndScene,
7818 IWineD3DDeviceImpl_Present,
7819 IWineD3DDeviceImpl_Clear,
7820 /*** Drawing ***/
7821 IWineD3DDeviceImpl_DrawPrimitive,
7822 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7823 IWineD3DDeviceImpl_DrawPrimitiveUP,
7824 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7825 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7826 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7827 IWineD3DDeviceImpl_DrawRectPatch,
7828 IWineD3DDeviceImpl_DrawTriPatch,
7829 IWineD3DDeviceImpl_DeletePatch,
7830 IWineD3DDeviceImpl_ColorFill,
7831 IWineD3DDeviceImpl_UpdateTexture,
7832 IWineD3DDeviceImpl_UpdateSurface,
7833 IWineD3DDeviceImpl_GetFrontBufferData,
7834 /*** object tracking ***/
7835 IWineD3DDeviceImpl_ResourceReleased,
7836 IWineD3DDeviceImpl_EnumResources
7839 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7840 WINED3DRS_ALPHABLENDENABLE ,
7841 WINED3DRS_ALPHAFUNC ,
7842 WINED3DRS_ALPHAREF ,
7843 WINED3DRS_ALPHATESTENABLE ,
7844 WINED3DRS_BLENDOP ,
7845 WINED3DRS_COLORWRITEENABLE ,
7846 WINED3DRS_DESTBLEND ,
7847 WINED3DRS_DITHERENABLE ,
7848 WINED3DRS_FILLMODE ,
7849 WINED3DRS_FOGDENSITY ,
7850 WINED3DRS_FOGEND ,
7851 WINED3DRS_FOGSTART ,
7852 WINED3DRS_LASTPIXEL ,
7853 WINED3DRS_SHADEMODE ,
7854 WINED3DRS_SRCBLEND ,
7855 WINED3DRS_STENCILENABLE ,
7856 WINED3DRS_STENCILFAIL ,
7857 WINED3DRS_STENCILFUNC ,
7858 WINED3DRS_STENCILMASK ,
7859 WINED3DRS_STENCILPASS ,
7860 WINED3DRS_STENCILREF ,
7861 WINED3DRS_STENCILWRITEMASK ,
7862 WINED3DRS_STENCILZFAIL ,
7863 WINED3DRS_TEXTUREFACTOR ,
7864 WINED3DRS_WRAP0 ,
7865 WINED3DRS_WRAP1 ,
7866 WINED3DRS_WRAP2 ,
7867 WINED3DRS_WRAP3 ,
7868 WINED3DRS_WRAP4 ,
7869 WINED3DRS_WRAP5 ,
7870 WINED3DRS_WRAP6 ,
7871 WINED3DRS_WRAP7 ,
7872 WINED3DRS_ZENABLE ,
7873 WINED3DRS_ZFUNC ,
7874 WINED3DRS_ZWRITEENABLE
7877 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7878 WINED3DTSS_ADDRESSW ,
7879 WINED3DTSS_ALPHAARG0 ,
7880 WINED3DTSS_ALPHAARG1 ,
7881 WINED3DTSS_ALPHAARG2 ,
7882 WINED3DTSS_ALPHAOP ,
7883 WINED3DTSS_BUMPENVLOFFSET ,
7884 WINED3DTSS_BUMPENVLSCALE ,
7885 WINED3DTSS_BUMPENVMAT00 ,
7886 WINED3DTSS_BUMPENVMAT01 ,
7887 WINED3DTSS_BUMPENVMAT10 ,
7888 WINED3DTSS_BUMPENVMAT11 ,
7889 WINED3DTSS_COLORARG0 ,
7890 WINED3DTSS_COLORARG1 ,
7891 WINED3DTSS_COLORARG2 ,
7892 WINED3DTSS_COLOROP ,
7893 WINED3DTSS_RESULTARG ,
7894 WINED3DTSS_TEXCOORDINDEX ,
7895 WINED3DTSS_TEXTURETRANSFORMFLAGS
7898 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7899 WINED3DSAMP_ADDRESSU ,
7900 WINED3DSAMP_ADDRESSV ,
7901 WINED3DSAMP_ADDRESSW ,
7902 WINED3DSAMP_BORDERCOLOR ,
7903 WINED3DSAMP_MAGFILTER ,
7904 WINED3DSAMP_MINFILTER ,
7905 WINED3DSAMP_MIPFILTER ,
7906 WINED3DSAMP_MIPMAPLODBIAS ,
7907 WINED3DSAMP_MAXMIPLEVEL ,
7908 WINED3DSAMP_MAXANISOTROPY ,
7909 WINED3DSAMP_SRGBTEXTURE ,
7910 WINED3DSAMP_ELEMENTINDEX
7913 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7914 WINED3DRS_AMBIENT ,
7915 WINED3DRS_AMBIENTMATERIALSOURCE ,
7916 WINED3DRS_CLIPPING ,
7917 WINED3DRS_CLIPPLANEENABLE ,
7918 WINED3DRS_COLORVERTEX ,
7919 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7920 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7921 WINED3DRS_FOGDENSITY ,
7922 WINED3DRS_FOGEND ,
7923 WINED3DRS_FOGSTART ,
7924 WINED3DRS_FOGTABLEMODE ,
7925 WINED3DRS_FOGVERTEXMODE ,
7926 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7927 WINED3DRS_LIGHTING ,
7928 WINED3DRS_LOCALVIEWER ,
7929 WINED3DRS_MULTISAMPLEANTIALIAS ,
7930 WINED3DRS_MULTISAMPLEMASK ,
7931 WINED3DRS_NORMALIZENORMALS ,
7932 WINED3DRS_PATCHEDGESTYLE ,
7933 WINED3DRS_POINTSCALE_A ,
7934 WINED3DRS_POINTSCALE_B ,
7935 WINED3DRS_POINTSCALE_C ,
7936 WINED3DRS_POINTSCALEENABLE ,
7937 WINED3DRS_POINTSIZE ,
7938 WINED3DRS_POINTSIZE_MAX ,
7939 WINED3DRS_POINTSIZE_MIN ,
7940 WINED3DRS_POINTSPRITEENABLE ,
7941 WINED3DRS_RANGEFOGENABLE ,
7942 WINED3DRS_SPECULARMATERIALSOURCE ,
7943 WINED3DRS_TWEENFACTOR ,
7944 WINED3DRS_VERTEXBLEND ,
7945 WINED3DRS_CULLMODE ,
7946 WINED3DRS_FOGCOLOR
7949 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7950 WINED3DTSS_TEXCOORDINDEX ,
7951 WINED3DTSS_TEXTURETRANSFORMFLAGS
7954 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7955 WINED3DSAMP_DMAPOFFSET
7958 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7959 DWORD rep = This->shader_backend->StateTable[state].representative;
7960 DWORD idx;
7961 BYTE shift;
7962 UINT i;
7963 WineD3DContext *context;
7965 if(!rep) return;
7966 for(i = 0; i < This->numContexts; i++) {
7967 context = This->contexts[i];
7968 if(isStateDirty(context, rep)) continue;
7970 context->dirtyArray[context->numDirtyEntries++] = rep;
7971 idx = rep >> 5;
7972 shift = rep & 0x1f;
7973 context->isStateDirty[idx] |= (1 << shift);
7977 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7978 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7979 /* The drawable size of a pbuffer render target is the current pbuffer size
7981 *width = dev->pbufferWidth;
7982 *height = dev->pbufferHeight;
7985 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7986 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7988 *width = This->pow2Width;
7989 *height = This->pow2Height;
7992 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7993 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7994 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7995 * current context's drawable, which is the size of the back buffer of the swapchain
7996 * the active context belongs to. The back buffer of the swapchain is stored as the
7997 * surface the context belongs to.
7999 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8000 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;