gdiplus: Implemented GdipGetPenEndCap.
[wine.git] / dlls / wined3d / device.c
blobf7301d73cfbe220671b1e8c1395aab3ceaabc5f2
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 usable 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 = SFLAG_NORMCOORD; /* Default to normalized coords */
667 object->Flags |= Discard ? SFLAG_DISCARD : 0;
668 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
669 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
672 if (WINED3DFMT_UNKNOWN != Format) {
673 object->bytesPerPixel = tableEntry->bpp;
674 } else {
675 object->bytesPerPixel = 0;
678 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
680 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
682 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
683 * this function is too deep to need to care about things like this.
684 * Levels need to be checked too, and possibly Type since they all affect what can be done.
685 * ****************************************/
686 switch(Pool) {
687 case WINED3DPOOL_SCRATCH:
688 if(!Lockable)
689 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
690 "which are mutually exclusive, setting lockable to TRUE\n");
691 Lockable = TRUE;
692 break;
693 case WINED3DPOOL_SYSTEMMEM:
694 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
695 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
696 case WINED3DPOOL_MANAGED:
697 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
698 "Usage of DYNAMIC which are mutually exclusive, not doing "
699 "anything just telling you.\n");
700 break;
701 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
702 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
703 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
704 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
705 break;
706 default:
707 FIXME("(%p) Unknown pool %d\n", This, Pool);
708 break;
711 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
712 FIXME("Trying to create a render target that isn't in the default pool\n");
715 /* mark the texture as dirty so that it gets loaded first time around*/
716 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
717 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
718 This, Width, Height, Format, debug_d3dformat(Format),
719 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
721 /* 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 if(This->depth_blt_texture) {
2289 glDeleteTextures(1, &This->depth_blt_texture);
2290 This->depth_blt_texture = 0;
2292 This->shader_backend->shader_destroy_depth_blt(iface);
2293 This->shader_backend->shader_free_private(iface);
2295 /* Release the update stateblock */
2296 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2297 if(This->updateStateBlock != This->stateBlock)
2298 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2300 This->updateStateBlock = NULL;
2302 { /* because were not doing proper internal refcounts releasing the primary state block
2303 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2304 to set this->stateBlock = NULL; first */
2305 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2306 This->stateBlock = NULL;
2308 /* Release the stateblock */
2309 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2310 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2314 /* Release the buffers (with sanity checks)*/
2315 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2316 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2317 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2318 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2320 This->stencilBufferTarget = NULL;
2322 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2323 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2324 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2326 TRACE("Setting rendertarget to NULL\n");
2327 This->render_targets[0] = NULL;
2329 if (This->auto_depth_stencil_buffer) {
2330 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2331 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2333 This->auto_depth_stencil_buffer = NULL;
2336 for(i=0; i < This->NumberOfSwapChains; i++) {
2337 TRACE("Releasing the implicit swapchain %d\n", i);
2338 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2339 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2343 HeapFree(GetProcessHeap(), 0, This->swapchains);
2344 This->swapchains = NULL;
2345 This->NumberOfSwapChains = 0;
2347 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2348 HeapFree(GetProcessHeap(), 0, This->palettes);
2349 This->palettes = NULL;
2350 This->NumberOfPalettes = 0;
2352 HeapFree(GetProcessHeap(), 0, This->render_targets);
2353 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2354 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2355 This->render_targets = NULL;
2356 This->fbo_color_attachments = NULL;
2357 This->draw_buffers = NULL;
2359 This->d3d_initialized = FALSE;
2360 return WINED3D_OK;
2363 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2365 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2367 /* Setup the window for fullscreen mode */
2368 if(fullscreen && !This->ddraw_fullscreen) {
2369 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2370 } else if(!fullscreen && This->ddraw_fullscreen) {
2371 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2374 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2375 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2376 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2377 * separately.
2379 This->ddraw_fullscreen = fullscreen;
2382 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2383 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2384 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2386 * There is no way to deactivate thread safety once it is enabled.
2388 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2391 /*For now just store the flag(needed in case of ddraw) */
2392 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2394 return;
2397 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2398 DEVMODEW devmode;
2399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2400 LONG ret;
2401 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2402 RECT clip_rc;
2404 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2406 /* Resize the screen even without a window:
2407 * The app could have unset it with SetCooperativeLevel, but not called
2408 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2409 * but we don't have any hwnd
2412 memset(&devmode, 0, sizeof(devmode));
2413 devmode.dmSize = sizeof(devmode);
2414 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2415 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2416 devmode.dmPelsWidth = pMode->Width;
2417 devmode.dmPelsHeight = pMode->Height;
2419 devmode.dmDisplayFrequency = pMode->RefreshRate;
2420 if (pMode->RefreshRate != 0) {
2421 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2424 /* Only change the mode if necessary */
2425 if( (This->ddraw_width == pMode->Width) &&
2426 (This->ddraw_height == pMode->Height) &&
2427 (This->ddraw_format == pMode->Format) &&
2428 (pMode->RefreshRate == 0) ) {
2429 return WINED3D_OK;
2432 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2433 if (ret != DISP_CHANGE_SUCCESSFUL) {
2434 if(devmode.dmDisplayFrequency != 0) {
2435 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2436 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2437 devmode.dmDisplayFrequency = 0;
2438 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2440 if(ret != DISP_CHANGE_SUCCESSFUL) {
2441 return WINED3DERR_NOTAVAILABLE;
2445 /* Store the new values */
2446 This->ddraw_width = pMode->Width;
2447 This->ddraw_height = pMode->Height;
2448 This->ddraw_format = pMode->Format;
2450 /* Only do this with a window of course, and only if we're fullscreened */
2451 if(This->ddraw_window && This->ddraw_fullscreen)
2452 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2454 /* And finally clip mouse to our screen */
2455 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2456 ClipCursor(&clip_rc);
2458 return WINED3D_OK;
2461 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2463 *ppD3D= This->wineD3D;
2464 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2465 IWineD3D_AddRef(*ppD3D);
2466 return WINED3D_OK;
2469 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2470 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2472 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2473 (This->adapter->TextureRam/(1024*1024)),
2474 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2475 /* return simulated texture memory left */
2476 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2481 /*****
2482 * Get / Set FVF
2483 *****/
2484 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2487 /* Update the current state block */
2488 This->updateStateBlock->changed.fvf = TRUE;
2490 if(This->updateStateBlock->fvf == fvf) {
2491 TRACE("Application is setting the old fvf over, nothing to do\n");
2492 return WINED3D_OK;
2495 This->updateStateBlock->fvf = fvf;
2496 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2497 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2498 return WINED3D_OK;
2502 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2504 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2505 *pfvf = This->stateBlock->fvf;
2506 return WINED3D_OK;
2509 /*****
2510 * Get / Set Stream Source
2511 *****/
2512 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2514 IWineD3DVertexBuffer *oldSrc;
2516 if (StreamNumber >= MAX_STREAMS) {
2517 WARN("Stream out of range %d\n", StreamNumber);
2518 return WINED3DERR_INVALIDCALL;
2519 } else if(OffsetInBytes & 0x3) {
2520 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2521 return WINED3DERR_INVALIDCALL;
2524 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2525 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2527 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2529 if(oldSrc == pStreamData &&
2530 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2531 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2532 TRACE("Application is setting the old values over, nothing to do\n");
2533 return WINED3D_OK;
2536 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2537 if (pStreamData) {
2538 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2539 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2542 /* Handle recording of state blocks */
2543 if (This->isRecordingState) {
2544 TRACE("Recording... not performing anything\n");
2545 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2546 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2547 return WINED3D_OK;
2550 /* Need to do a getParent and pass the references up */
2551 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2552 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2553 so for now, just count internally */
2554 if (pStreamData != NULL) {
2555 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2556 InterlockedIncrement(&vbImpl->bindCount);
2557 IWineD3DVertexBuffer_AddRef(pStreamData);
2559 if (oldSrc != NULL) {
2560 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2561 IWineD3DVertexBuffer_Release(oldSrc);
2564 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2566 return WINED3D_OK;
2569 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2572 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2573 This->stateBlock->streamSource[StreamNumber],
2574 This->stateBlock->streamOffset[StreamNumber],
2575 This->stateBlock->streamStride[StreamNumber]);
2577 if (StreamNumber >= MAX_STREAMS) {
2578 WARN("Stream out of range %d\n", StreamNumber);
2579 return WINED3DERR_INVALIDCALL;
2581 *pStream = This->stateBlock->streamSource[StreamNumber];
2582 *pStride = This->stateBlock->streamStride[StreamNumber];
2583 if (pOffset) {
2584 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2587 if (*pStream != NULL) {
2588 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2590 return WINED3D_OK;
2593 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2595 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2596 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2598 /* Verify input at least in d3d9 this is invalid*/
2599 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2600 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2601 return WINED3DERR_INVALIDCALL;
2603 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2604 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2605 return WINED3DERR_INVALIDCALL;
2607 if( Divider == 0 ){
2608 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2609 return WINED3DERR_INVALIDCALL;
2612 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2613 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2615 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2616 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2618 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2619 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2620 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2623 return WINED3D_OK;
2626 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2629 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2630 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2632 TRACE("(%p) : returning %d\n", This, *Divider);
2634 return WINED3D_OK;
2637 /*****
2638 * Get / Set & Multiply Transform
2639 *****/
2640 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2643 /* Most of this routine, comments included copied from ddraw tree initially: */
2644 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2646 /* Handle recording of state blocks */
2647 if (This->isRecordingState) {
2648 TRACE("Recording... not performing anything\n");
2649 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2650 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2651 return WINED3D_OK;
2655 * If the new matrix is the same as the current one,
2656 * we cut off any further processing. this seems to be a reasonable
2657 * optimization because as was noticed, some apps (warcraft3 for example)
2658 * tend towards setting the same matrix repeatedly for some reason.
2660 * From here on we assume that the new matrix is different, wherever it matters.
2662 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2663 TRACE("The app is setting the same matrix over again\n");
2664 return WINED3D_OK;
2665 } else {
2666 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2670 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2671 where ViewMat = Camera space, WorldMat = world space.
2673 In OpenGL, camera and world space is combined into GL_MODELVIEW
2674 matrix. The Projection matrix stay projection matrix.
2677 /* Capture the times we can just ignore the change for now */
2678 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2679 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2680 /* Handled by the state manager */
2683 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2684 return WINED3D_OK;
2687 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2689 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2690 *pMatrix = This->stateBlock->transforms[State];
2691 return WINED3D_OK;
2694 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2695 WINED3DMATRIX *mat = NULL;
2696 WINED3DMATRIX temp;
2698 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2699 * below means it will be recorded in a state block change, but it
2700 * works regardless where it is recorded.
2701 * If this is found to be wrong, change to StateBlock.
2703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2704 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2706 if (State < HIGHEST_TRANSFORMSTATE)
2708 mat = &This->updateStateBlock->transforms[State];
2709 } else {
2710 FIXME("Unhandled transform state!!\n");
2713 multiply_matrix(&temp, mat, pMatrix);
2715 /* Apply change via set transform - will reapply to eg. lights this way */
2716 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2719 /*****
2720 * Get / Set Light
2721 *****/
2722 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2723 you can reference any indexes you want as long as that number max are enabled at any
2724 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2725 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2726 but when recording, just build a chain pretty much of commands to be replayed. */
2728 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2729 float rho;
2730 PLIGHTINFOEL *object = NULL;
2731 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2732 struct list *e;
2734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2735 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2737 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2738 * the gl driver.
2740 if(!pLight) {
2741 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2742 return WINED3DERR_INVALIDCALL;
2745 switch(pLight->Type) {
2746 case WINED3DLIGHT_POINT:
2747 case WINED3DLIGHT_SPOT:
2748 case WINED3DLIGHT_PARALLELPOINT:
2749 case WINED3DLIGHT_GLSPOT:
2750 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2751 * most wanted
2753 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2754 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2755 return WINED3DERR_INVALIDCALL;
2757 break;
2759 case WINED3DLIGHT_DIRECTIONAL:
2760 /* Ignores attenuation */
2761 break;
2763 default:
2764 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2765 return WINED3DERR_INVALIDCALL;
2768 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2769 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2770 if(object->OriginalIndex == Index) break;
2771 object = NULL;
2774 if(!object) {
2775 TRACE("Adding new light\n");
2776 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2777 if(!object) {
2778 ERR("Out of memory error when allocating a light\n");
2779 return E_OUTOFMEMORY;
2781 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2782 object->glIndex = -1;
2783 object->OriginalIndex = Index;
2784 object->changed = TRUE;
2787 /* Initialize the object */
2788 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,
2789 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2790 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2791 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2792 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2793 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2794 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2796 /* Save away the information */
2797 object->OriginalParms = *pLight;
2799 switch (pLight->Type) {
2800 case WINED3DLIGHT_POINT:
2801 /* Position */
2802 object->lightPosn[0] = pLight->Position.x;
2803 object->lightPosn[1] = pLight->Position.y;
2804 object->lightPosn[2] = pLight->Position.z;
2805 object->lightPosn[3] = 1.0f;
2806 object->cutoff = 180.0f;
2807 /* FIXME: Range */
2808 break;
2810 case WINED3DLIGHT_DIRECTIONAL:
2811 /* Direction */
2812 object->lightPosn[0] = -pLight->Direction.x;
2813 object->lightPosn[1] = -pLight->Direction.y;
2814 object->lightPosn[2] = -pLight->Direction.z;
2815 object->lightPosn[3] = 0.0;
2816 object->exponent = 0.0f;
2817 object->cutoff = 180.0f;
2818 break;
2820 case WINED3DLIGHT_SPOT:
2821 /* Position */
2822 object->lightPosn[0] = pLight->Position.x;
2823 object->lightPosn[1] = pLight->Position.y;
2824 object->lightPosn[2] = pLight->Position.z;
2825 object->lightPosn[3] = 1.0;
2827 /* Direction */
2828 object->lightDirn[0] = pLight->Direction.x;
2829 object->lightDirn[1] = pLight->Direction.y;
2830 object->lightDirn[2] = pLight->Direction.z;
2831 object->lightDirn[3] = 1.0;
2834 * opengl-ish and d3d-ish spot lights use too different models for the
2835 * light "intensity" as a function of the angle towards the main light direction,
2836 * so we only can approximate very roughly.
2837 * however spot lights are rather rarely used in games (if ever used at all).
2838 * furthermore if still used, probably nobody pays attention to such details.
2840 if (pLight->Falloff == 0) {
2841 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2842 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2843 * will always be 1.0 for both of them, and we don't have to care for the
2844 * rest of the rather complex calculation
2846 object->exponent = 0;
2847 } else {
2848 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2849 if (rho < 0.0001) rho = 0.0001f;
2850 object->exponent = -0.3/log(cos(rho/2));
2852 if (object->exponent > 128.0) {
2853 object->exponent = 128.0;
2855 object->cutoff = pLight->Phi*90/M_PI;
2857 /* FIXME: Range */
2858 break;
2860 default:
2861 FIXME("Unrecognized light type %d\n", pLight->Type);
2864 /* Update the live definitions if the light is currently assigned a glIndex */
2865 if (object->glIndex != -1 && !This->isRecordingState) {
2866 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2868 return WINED3D_OK;
2871 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2872 PLIGHTINFOEL *lightInfo = NULL;
2873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2874 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2875 struct list *e;
2876 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2878 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2879 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2880 if(lightInfo->OriginalIndex == Index) break;
2881 lightInfo = NULL;
2884 if (lightInfo == NULL) {
2885 TRACE("Light information requested but light not defined\n");
2886 return WINED3DERR_INVALIDCALL;
2889 *pLight = lightInfo->OriginalParms;
2890 return WINED3D_OK;
2893 /*****
2894 * Get / Set Light Enable
2895 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2896 *****/
2897 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2898 PLIGHTINFOEL *lightInfo = NULL;
2899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2900 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2901 struct list *e;
2902 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2904 /* Tests show true = 128...not clear why */
2905 Enable = Enable? 128: 0;
2907 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2908 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2909 if(lightInfo->OriginalIndex == Index) break;
2910 lightInfo = NULL;
2912 TRACE("Found light: %p\n", lightInfo);
2914 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2915 if (lightInfo == NULL) {
2917 TRACE("Light enabled requested but light not defined, so defining one!\n");
2918 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2920 /* Search for it again! Should be fairly quick as near head of list */
2921 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2922 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2923 if(lightInfo->OriginalIndex == Index) break;
2924 lightInfo = NULL;
2926 if (lightInfo == NULL) {
2927 FIXME("Adding default lights has failed dismally\n");
2928 return WINED3DERR_INVALIDCALL;
2932 lightInfo->enabledChanged = TRUE;
2933 if(!Enable) {
2934 if(lightInfo->glIndex != -1) {
2935 if(!This->isRecordingState) {
2936 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2939 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2940 lightInfo->glIndex = -1;
2941 } else {
2942 TRACE("Light already disabled, nothing to do\n");
2944 lightInfo->enabled = FALSE;
2945 } else {
2946 lightInfo->enabled = TRUE;
2947 if (lightInfo->glIndex != -1) {
2948 /* nop */
2949 TRACE("Nothing to do as light was enabled\n");
2950 } else {
2951 int i;
2952 /* Find a free gl light */
2953 for(i = 0; i < This->maxConcurrentLights; i++) {
2954 if(This->stateBlock->activeLights[i] == NULL) {
2955 This->stateBlock->activeLights[i] = lightInfo;
2956 lightInfo->glIndex = i;
2957 break;
2960 if(lightInfo->glIndex == -1) {
2961 /* Our tests show that Windows returns D3D_OK in this situation, even with
2962 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2963 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2964 * as well for those lights.
2966 * TODO: Test how this affects rendering
2968 FIXME("Too many concurrently active lights\n");
2969 return WINED3D_OK;
2972 /* i == lightInfo->glIndex */
2973 if(!This->isRecordingState) {
2974 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2979 return WINED3D_OK;
2982 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2984 PLIGHTINFOEL *lightInfo = NULL;
2985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2986 struct list *e;
2987 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2988 TRACE("(%p) : for idx(%d)\n", This, Index);
2990 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2991 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2992 if(lightInfo->OriginalIndex == Index) break;
2993 lightInfo = NULL;
2996 if (lightInfo == NULL) {
2997 TRACE("Light enabled state requested but light not defined\n");
2998 return WINED3DERR_INVALIDCALL;
3000 /* true is 128 according to SetLightEnable */
3001 *pEnable = lightInfo->enabled ? 128 : 0;
3002 return WINED3D_OK;
3005 /*****
3006 * Get / Set Clip Planes
3007 *****/
3008 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3010 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3012 /* Validate Index */
3013 if (Index >= GL_LIMITS(clipplanes)) {
3014 TRACE("Application has requested clipplane this device doesn't support\n");
3015 return WINED3DERR_INVALIDCALL;
3018 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3020 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3021 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3022 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3023 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3024 TRACE("Application is setting old values over, nothing to do\n");
3025 return WINED3D_OK;
3028 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3029 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3030 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3031 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3033 /* Handle recording of state blocks */
3034 if (This->isRecordingState) {
3035 TRACE("Recording... not performing anything\n");
3036 return WINED3D_OK;
3039 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3041 return WINED3D_OK;
3044 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3046 TRACE("(%p) : for idx %d\n", This, Index);
3048 /* Validate Index */
3049 if (Index >= GL_LIMITS(clipplanes)) {
3050 TRACE("Application has requested clipplane this device doesn't support\n");
3051 return WINED3DERR_INVALIDCALL;
3054 pPlane[0] = This->stateBlock->clipplane[Index][0];
3055 pPlane[1] = This->stateBlock->clipplane[Index][1];
3056 pPlane[2] = This->stateBlock->clipplane[Index][2];
3057 pPlane[3] = This->stateBlock->clipplane[Index][3];
3058 return WINED3D_OK;
3061 /*****
3062 * Get / Set Clip Plane Status
3063 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3064 *****/
3065 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3067 FIXME("(%p) : stub\n", This);
3068 if (NULL == pClipStatus) {
3069 return WINED3DERR_INVALIDCALL;
3071 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3072 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3073 return WINED3D_OK;
3076 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3078 FIXME("(%p) : stub\n", This);
3079 if (NULL == pClipStatus) {
3080 return WINED3DERR_INVALIDCALL;
3082 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3083 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3084 return WINED3D_OK;
3087 /*****
3088 * Get / Set Material
3089 *****/
3090 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3093 if (!pMaterial) return WINED3DERR_INVALIDCALL;
3095 This->updateStateBlock->changed.material = TRUE;
3096 This->updateStateBlock->material = *pMaterial;
3098 /* Handle recording of state blocks */
3099 if (This->isRecordingState) {
3100 TRACE("Recording... not performing anything\n");
3101 return WINED3D_OK;
3104 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3105 return WINED3D_OK;
3108 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3110 *pMaterial = This->updateStateBlock->material;
3111 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3112 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3113 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3114 pMaterial->Ambient.b, pMaterial->Ambient.a);
3115 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3116 pMaterial->Specular.b, pMaterial->Specular.a);
3117 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3118 pMaterial->Emissive.b, pMaterial->Emissive.a);
3119 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3121 return WINED3D_OK;
3124 /*****
3125 * Get / Set Indices
3126 *****/
3127 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3129 IWineD3DIndexBuffer *oldIdxs;
3131 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3132 oldIdxs = This->updateStateBlock->pIndexData;
3134 This->updateStateBlock->changed.indices = TRUE;
3135 This->updateStateBlock->pIndexData = pIndexData;
3137 /* Handle recording of state blocks */
3138 if (This->isRecordingState) {
3139 TRACE("Recording... not performing anything\n");
3140 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3141 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3142 return WINED3D_OK;
3145 if(oldIdxs != pIndexData) {
3146 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3147 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3148 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3150 return WINED3D_OK;
3153 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3156 *ppIndexData = This->stateBlock->pIndexData;
3158 /* up ref count on ppindexdata */
3159 if (*ppIndexData) {
3160 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3161 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3162 }else{
3163 TRACE("(%p) No index data set\n", This);
3165 TRACE("Returning %p\n", *ppIndexData);
3167 return WINED3D_OK;
3170 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3171 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3173 TRACE("(%p)->(%d)\n", This, BaseIndex);
3175 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3176 TRACE("Application is setting the old value over, nothing to do\n");
3177 return WINED3D_OK;
3180 This->updateStateBlock->baseVertexIndex = BaseIndex;
3182 if (This->isRecordingState) {
3183 TRACE("Recording... not performing anything\n");
3184 return WINED3D_OK;
3186 /* The base vertex index affects the stream sources */
3187 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3188 return WINED3D_OK;
3191 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3193 TRACE("(%p) : base_index %p\n", This, base_index);
3195 *base_index = This->stateBlock->baseVertexIndex;
3197 TRACE("Returning %u\n", *base_index);
3199 return WINED3D_OK;
3202 /*****
3203 * Get / Set Viewports
3204 *****/
3205 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3208 TRACE("(%p)\n", This);
3209 This->updateStateBlock->changed.viewport = TRUE;
3210 This->updateStateBlock->viewport = *pViewport;
3212 /* Handle recording of state blocks */
3213 if (This->isRecordingState) {
3214 TRACE("Recording... not performing anything\n");
3215 return WINED3D_OK;
3218 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3219 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3221 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3222 return WINED3D_OK;
3226 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3228 TRACE("(%p)\n", This);
3229 *pViewport = This->stateBlock->viewport;
3230 return WINED3D_OK;
3233 /*****
3234 * Get / Set Render States
3235 * TODO: Verify against dx9 definitions
3236 *****/
3237 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3240 DWORD oldValue = This->stateBlock->renderState[State];
3242 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3244 This->updateStateBlock->changed.renderState[State] = TRUE;
3245 This->updateStateBlock->renderState[State] = Value;
3247 /* Handle recording of state blocks */
3248 if (This->isRecordingState) {
3249 TRACE("Recording... not performing anything\n");
3250 return WINED3D_OK;
3253 /* Compared here and not before the assignment to allow proper stateblock recording */
3254 if(Value == oldValue) {
3255 TRACE("Application is setting the old value over, nothing to do\n");
3256 } else {
3257 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3260 return WINED3D_OK;
3263 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3265 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3266 *pValue = This->stateBlock->renderState[State];
3267 return WINED3D_OK;
3270 /*****
3271 * Get / Set Sampler States
3272 * TODO: Verify against dx9 definitions
3273 *****/
3275 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3277 DWORD oldValue;
3279 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3280 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3282 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3283 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3286 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3287 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3288 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3291 * SetSampler is designed to allow for more than the standard up to 8 textures
3292 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3293 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3295 * http://developer.nvidia.com/object/General_FAQ.html#t6
3297 * There are two new settings for GForce
3298 * the sampler one:
3299 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3300 * and the texture one:
3301 * GL_MAX_TEXTURE_COORDS_ARB.
3302 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3303 ******************/
3305 oldValue = This->stateBlock->samplerState[Sampler][Type];
3306 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3307 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3309 /* Handle recording of state blocks */
3310 if (This->isRecordingState) {
3311 TRACE("Recording... not performing anything\n");
3312 return WINED3D_OK;
3315 if(oldValue == Value) {
3316 TRACE("Application is setting the old value over, nothing to do\n");
3317 return WINED3D_OK;
3320 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3322 return WINED3D_OK;
3325 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3328 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3329 This, Sampler, debug_d3dsamplerstate(Type), Type);
3331 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3332 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3335 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3336 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3337 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3339 *Value = This->stateBlock->samplerState[Sampler][Type];
3340 TRACE("(%p) : Returning %#x\n", This, *Value);
3342 return WINED3D_OK;
3345 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3348 This->updateStateBlock->changed.scissorRect = TRUE;
3349 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3350 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3351 return WINED3D_OK;
3353 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3355 if(This->isRecordingState) {
3356 TRACE("Recording... not performing anything\n");
3357 return WINED3D_OK;
3360 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3362 return WINED3D_OK;
3365 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3368 *pRect = This->updateStateBlock->scissorRect;
3369 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3370 return WINED3D_OK;
3373 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3375 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3377 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3379 This->updateStateBlock->vertexDecl = pDecl;
3380 This->updateStateBlock->changed.vertexDecl = TRUE;
3382 if (This->isRecordingState) {
3383 TRACE("Recording... not performing anything\n");
3384 return WINED3D_OK;
3385 } else if(pDecl == oldDecl) {
3386 /* Checked after the assignment to allow proper stateblock recording */
3387 TRACE("Application is setting the old declaration over, nothing to do\n");
3388 return WINED3D_OK;
3391 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3392 return WINED3D_OK;
3395 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3398 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3400 *ppDecl = This->stateBlock->vertexDecl;
3401 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3402 return WINED3D_OK;
3405 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3407 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3409 This->updateStateBlock->vertexShader = pShader;
3410 This->updateStateBlock->changed.vertexShader = TRUE;
3412 if (This->isRecordingState) {
3413 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3414 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3415 TRACE("Recording... not performing anything\n");
3416 return WINED3D_OK;
3417 } else if(oldShader == pShader) {
3418 /* Checked here to allow proper stateblock recording */
3419 TRACE("App is setting the old shader over, nothing to do\n");
3420 return WINED3D_OK;
3423 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3424 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3425 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3427 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3429 return WINED3D_OK;
3432 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3435 if (NULL == ppShader) {
3436 return WINED3DERR_INVALIDCALL;
3438 *ppShader = This->stateBlock->vertexShader;
3439 if( NULL != *ppShader)
3440 IWineD3DVertexShader_AddRef(*ppShader);
3442 TRACE("(%p) : returning %p\n", This, *ppShader);
3443 return WINED3D_OK;
3446 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3447 IWineD3DDevice *iface,
3448 UINT start,
3449 CONST BOOL *srcData,
3450 UINT count) {
3452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3453 int i, cnt = min(count, MAX_CONST_B - start);
3455 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3456 iface, srcData, start, count);
3458 if (srcData == NULL || cnt < 0)
3459 return WINED3DERR_INVALIDCALL;
3461 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3462 for (i = 0; i < cnt; i++)
3463 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3465 for (i = start; i < cnt + start; ++i) {
3466 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3469 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3471 return WINED3D_OK;
3474 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3475 IWineD3DDevice *iface,
3476 UINT start,
3477 BOOL *dstData,
3478 UINT count) {
3480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3481 int cnt = min(count, MAX_CONST_B - start);
3483 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3484 iface, dstData, start, count);
3486 if (dstData == NULL || cnt < 0)
3487 return WINED3DERR_INVALIDCALL;
3489 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3490 return WINED3D_OK;
3493 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3494 IWineD3DDevice *iface,
3495 UINT start,
3496 CONST int *srcData,
3497 UINT count) {
3499 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3500 int i, cnt = min(count, MAX_CONST_I - start);
3502 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3503 iface, srcData, start, count);
3505 if (srcData == NULL || cnt < 0)
3506 return WINED3DERR_INVALIDCALL;
3508 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3509 for (i = 0; i < cnt; i++)
3510 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3511 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3513 for (i = start; i < cnt + start; ++i) {
3514 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3519 return WINED3D_OK;
3522 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3523 IWineD3DDevice *iface,
3524 UINT start,
3525 int *dstData,
3526 UINT count) {
3528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3529 int cnt = min(count, MAX_CONST_I - start);
3531 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3532 iface, dstData, start, count);
3534 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3535 return WINED3DERR_INVALIDCALL;
3537 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3538 return WINED3D_OK;
3541 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3542 IWineD3DDevice *iface,
3543 UINT start,
3544 CONST float *srcData,
3545 UINT count) {
3547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3548 int i;
3550 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3551 iface, srcData, start, count);
3553 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3554 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3555 return WINED3DERR_INVALIDCALL;
3557 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3558 if(TRACE_ON(d3d)) {
3559 for (i = 0; i < count; i++)
3560 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3561 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3564 for (i = start; i < count + start; ++i) {
3565 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3566 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3567 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3568 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3569 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3571 ptr->idx[ptr->count++] = i;
3572 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3576 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3578 return WINED3D_OK;
3581 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3582 IWineD3DDevice *iface,
3583 UINT start,
3584 CONST float *srcData,
3585 UINT count) {
3587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3588 int i;
3590 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3591 iface, srcData, start, count);
3593 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3594 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3595 return WINED3DERR_INVALIDCALL;
3597 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3598 if(TRACE_ON(d3d)) {
3599 for (i = 0; i < count; i++)
3600 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3601 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3604 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3605 * context. On a context switch the old context will be fully dirtified
3607 memset(This->activeContext->vshader_const_dirty + start, 1,
3608 sizeof(*This->activeContext->vshader_const_dirty) * count);
3609 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count);
3611 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3613 return WINED3D_OK;
3616 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3617 IWineD3DDevice *iface,
3618 UINT start,
3619 float *dstData,
3620 UINT count) {
3622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3623 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3625 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3626 iface, dstData, start, count);
3628 if (dstData == NULL || cnt < 0)
3629 return WINED3DERR_INVALIDCALL;
3631 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3632 return WINED3D_OK;
3635 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3636 DWORD i;
3637 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3638 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3642 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3643 int i = This->rev_tex_unit_map[unit];
3644 int j = This->texUnitMap[stage];
3646 This->texUnitMap[stage] = unit;
3647 if (i != -1 && i != stage) {
3648 This->texUnitMap[i] = -1;
3651 This->rev_tex_unit_map[unit] = stage;
3652 if (j != -1 && j != unit) {
3653 This->rev_tex_unit_map[j] = -1;
3657 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3658 int i;
3660 for (i = 0; i < MAX_TEXTURES; ++i) {
3661 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3662 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3663 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3664 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3665 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3666 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3667 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3668 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3670 if (color_op == WINED3DTOP_DISABLE) {
3671 /* Not used, and disable higher stages */
3672 while (i < MAX_TEXTURES) {
3673 This->fixed_function_usage_map[i] = FALSE;
3674 ++i;
3676 break;
3679 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3680 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3681 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3682 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3683 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3684 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3685 This->fixed_function_usage_map[i] = TRUE;
3686 } else {
3687 This->fixed_function_usage_map[i] = FALSE;
3690 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3691 This->fixed_function_usage_map[i+1] = TRUE;
3696 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3697 int i, tex;
3699 device_update_fixed_function_usage_map(This);
3701 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3702 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3703 if (!This->fixed_function_usage_map[i]) continue;
3705 if (This->texUnitMap[i] != i) {
3706 device_map_stage(This, i, i);
3707 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3708 markTextureStagesDirty(This, i);
3711 return;
3714 /* Now work out the mapping */
3715 tex = 0;
3716 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3717 if (!This->fixed_function_usage_map[i]) continue;
3719 if (This->texUnitMap[i] != tex) {
3720 device_map_stage(This, i, tex);
3721 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3722 markTextureStagesDirty(This, i);
3725 ++tex;
3729 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3730 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3731 int i;
3733 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3734 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3735 device_map_stage(This, i, i);
3736 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3737 if (i < MAX_TEXTURES) {
3738 markTextureStagesDirty(This, i);
3744 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3745 int current_mapping = This->rev_tex_unit_map[unit];
3747 if (current_mapping == -1) {
3748 /* Not currently used */
3749 return TRUE;
3752 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3753 /* Used by a fragment sampler */
3755 if (!pshader_sampler_tokens) {
3756 /* No pixel shader, check fixed function */
3757 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3760 /* Pixel shader, check the shader's sampler map */
3761 return !pshader_sampler_tokens[current_mapping];
3764 /* Used by a vertex sampler */
3765 return !vshader_sampler_tokens[current_mapping];
3768 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3769 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3770 DWORD *pshader_sampler_tokens = NULL;
3771 int start = GL_LIMITS(combined_samplers) - 1;
3772 int i;
3774 if (ps) {
3775 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3777 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3778 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3779 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3782 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3783 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3784 if (vshader_sampler_tokens[i]) {
3785 if (This->texUnitMap[vsampler_idx] != -1) {
3786 /* Already mapped somewhere */
3787 continue;
3790 while (start >= 0) {
3791 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3792 device_map_stage(This, vsampler_idx, start);
3793 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3795 --start;
3796 break;
3799 --start;
3805 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3806 BOOL vs = use_vs(This);
3807 BOOL ps = use_ps(This);
3809 * Rules are:
3810 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3811 * that would be really messy and require shader recompilation
3812 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3813 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3815 if (ps) {
3816 device_map_psamplers(This);
3817 } else {
3818 device_map_fixed_function_samplers(This);
3821 if (vs) {
3822 device_map_vsamplers(This, ps);
3826 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3828 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3829 This->updateStateBlock->pixelShader = pShader;
3830 This->updateStateBlock->changed.pixelShader = TRUE;
3832 /* Handle recording of state blocks */
3833 if (This->isRecordingState) {
3834 TRACE("Recording... not performing anything\n");
3837 if (This->isRecordingState) {
3838 TRACE("Recording... not performing anything\n");
3839 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3840 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3841 return WINED3D_OK;
3844 if(pShader == oldShader) {
3845 TRACE("App is setting the old pixel shader over, nothing to do\n");
3846 return WINED3D_OK;
3849 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3850 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3852 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3853 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3855 return WINED3D_OK;
3858 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3861 if (NULL == ppShader) {
3862 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3863 return WINED3DERR_INVALIDCALL;
3866 *ppShader = This->stateBlock->pixelShader;
3867 if (NULL != *ppShader) {
3868 IWineD3DPixelShader_AddRef(*ppShader);
3870 TRACE("(%p) : returning %p\n", This, *ppShader);
3871 return WINED3D_OK;
3874 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3875 IWineD3DDevice *iface,
3876 UINT start,
3877 CONST BOOL *srcData,
3878 UINT count) {
3880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3881 int i, cnt = min(count, MAX_CONST_B - start);
3883 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3884 iface, srcData, start, count);
3886 if (srcData == NULL || cnt < 0)
3887 return WINED3DERR_INVALIDCALL;
3889 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3890 for (i = 0; i < cnt; i++)
3891 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3893 for (i = start; i < cnt + start; ++i) {
3894 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3897 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3899 return WINED3D_OK;
3902 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3903 IWineD3DDevice *iface,
3904 UINT start,
3905 BOOL *dstData,
3906 UINT count) {
3908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3909 int cnt = min(count, MAX_CONST_B - start);
3911 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3912 iface, dstData, start, count);
3914 if (dstData == NULL || cnt < 0)
3915 return WINED3DERR_INVALIDCALL;
3917 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3918 return WINED3D_OK;
3921 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3922 IWineD3DDevice *iface,
3923 UINT start,
3924 CONST int *srcData,
3925 UINT count) {
3927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3928 int i, cnt = min(count, MAX_CONST_I - start);
3930 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3931 iface, srcData, start, count);
3933 if (srcData == NULL || cnt < 0)
3934 return WINED3DERR_INVALIDCALL;
3936 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3937 for (i = 0; i < cnt; i++)
3938 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3939 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3941 for (i = start; i < cnt + start; ++i) {
3942 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3945 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3947 return WINED3D_OK;
3950 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3951 IWineD3DDevice *iface,
3952 UINT start,
3953 int *dstData,
3954 UINT count) {
3956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3957 int cnt = min(count, MAX_CONST_I - start);
3959 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3960 iface, dstData, start, count);
3962 if (dstData == NULL || cnt < 0)
3963 return WINED3DERR_INVALIDCALL;
3965 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3966 return WINED3D_OK;
3969 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3970 IWineD3DDevice *iface,
3971 UINT start,
3972 CONST float *srcData,
3973 UINT count) {
3975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3976 int i;
3978 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3979 iface, srcData, start, count);
3981 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3982 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3983 return WINED3DERR_INVALIDCALL;
3985 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3986 if(TRACE_ON(d3d)) {
3987 for (i = 0; i < count; i++)
3988 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3989 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3992 for (i = start; i < count + start; ++i) {
3993 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3994 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3995 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3996 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3997 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3999 ptr->idx[ptr->count++] = i;
4000 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4004 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4006 return WINED3D_OK;
4009 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4010 IWineD3DDevice *iface,
4011 UINT start,
4012 CONST float *srcData,
4013 UINT count) {
4015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4016 int i;
4018 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4019 iface, srcData, start, count);
4021 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4022 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4023 return WINED3DERR_INVALIDCALL;
4025 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4026 if(TRACE_ON(d3d)) {
4027 for (i = 0; i < count; i++)
4028 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4029 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4032 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4033 * context. On a context switch the old context will be fully dirtified
4035 memset(This->activeContext->pshader_const_dirty + start, 1,
4036 sizeof(*This->activeContext->pshader_const_dirty) * count);
4037 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count);
4039 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4041 return WINED3D_OK;
4044 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4045 IWineD3DDevice *iface,
4046 UINT start,
4047 float *dstData,
4048 UINT count) {
4050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4051 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4053 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4054 iface, dstData, start, count);
4056 if (dstData == NULL || cnt < 0)
4057 return WINED3DERR_INVALIDCALL;
4059 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4060 return WINED3D_OK;
4063 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4064 static HRESULT
4065 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4066 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4067 unsigned int i;
4068 DWORD DestFVF = dest->fvf;
4069 WINED3DVIEWPORT vp;
4070 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4071 BOOL doClip;
4072 int numTextures;
4074 if (lpStrideData->u.s.normal.lpData) {
4075 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4078 if (lpStrideData->u.s.position.lpData == NULL) {
4079 ERR("Source has no position mask\n");
4080 return WINED3DERR_INVALIDCALL;
4083 /* We might access VBOs from this code, so hold the lock */
4084 ENTER_GL();
4086 if (dest->resource.allocatedMemory == NULL) {
4087 /* This may happen if we do direct locking into a vbo. Unlikely,
4088 * but theoretically possible(ddraw processvertices test)
4090 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4091 if(!dest->resource.allocatedMemory) {
4092 LEAVE_GL();
4093 ERR("Out of memory\n");
4094 return E_OUTOFMEMORY;
4096 if(dest->vbo) {
4097 void *src;
4098 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4099 checkGLcall("glBindBufferARB");
4100 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4101 if(src) {
4102 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4104 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4105 checkGLcall("glUnmapBufferARB");
4109 /* Get a pointer into the destination vbo(create one if none exists) and
4110 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4112 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4113 dest->Flags |= VBFLAG_CREATEVBO;
4114 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4117 if(dest->vbo) {
4118 unsigned char extrabytes = 0;
4119 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4120 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4121 * this may write 4 extra bytes beyond the area that should be written
4123 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4124 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4125 if(!dest_conv_addr) {
4126 ERR("Out of memory\n");
4127 /* Continue without storing converted vertices */
4129 dest_conv = dest_conv_addr;
4132 /* Should I clip?
4133 * a) WINED3DRS_CLIPPING is enabled
4134 * b) WINED3DVOP_CLIP is passed
4136 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4137 static BOOL warned = FALSE;
4139 * The clipping code is not quite correct. Some things need
4140 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4141 * so disable clipping for now.
4142 * (The graphics in Half-Life are broken, and my processvertices
4143 * test crashes with IDirect3DDevice3)
4144 doClip = TRUE;
4146 doClip = FALSE;
4147 if(!warned) {
4148 warned = TRUE;
4149 FIXME("Clipping is broken and disabled for now\n");
4151 } else doClip = FALSE;
4152 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4154 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4155 WINED3DTS_VIEW,
4156 &view_mat);
4157 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4158 WINED3DTS_PROJECTION,
4159 &proj_mat);
4160 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4161 WINED3DTS_WORLDMATRIX(0),
4162 &world_mat);
4164 TRACE("View mat:\n");
4165 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);
4166 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);
4167 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);
4168 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);
4170 TRACE("Proj mat:\n");
4171 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);
4172 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);
4173 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);
4174 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);
4176 TRACE("World mat:\n");
4177 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);
4178 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);
4179 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);
4180 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);
4182 /* Get the viewport */
4183 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4184 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4185 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4187 multiply_matrix(&mat,&view_mat,&world_mat);
4188 multiply_matrix(&mat,&proj_mat,&mat);
4190 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4192 for (i = 0; i < dwCount; i+= 1) {
4193 unsigned int tex_index;
4195 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4196 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4197 /* The position first */
4198 float *p =
4199 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4200 float x, y, z, rhw;
4201 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4203 /* Multiplication with world, view and projection matrix */
4204 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);
4205 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);
4206 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);
4207 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);
4209 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4211 /* WARNING: The following things are taken from d3d7 and were not yet checked
4212 * against d3d8 or d3d9!
4215 /* Clipping conditions: From msdn
4217 * A vertex is clipped if it does not match the following requirements
4218 * -rhw < x <= rhw
4219 * -rhw < y <= rhw
4220 * 0 < z <= rhw
4221 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4223 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4224 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4228 if( !doClip ||
4229 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4230 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4231 ( rhw > eps ) ) ) {
4233 /* "Normal" viewport transformation (not clipped)
4234 * 1) The values are divided by rhw
4235 * 2) The y axis is negative, so multiply it with -1
4236 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4237 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4238 * 4) Multiply x with Width/2 and add Width/2
4239 * 5) The same for the height
4240 * 6) Add the viewpoint X and Y to the 2D coordinates and
4241 * The minimum Z value to z
4242 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4244 * Well, basically it's simply a linear transformation into viewport
4245 * coordinates
4248 x /= rhw;
4249 y /= rhw;
4250 z /= rhw;
4252 y *= -1;
4254 x *= vp.Width / 2;
4255 y *= vp.Height / 2;
4256 z *= vp.MaxZ - vp.MinZ;
4258 x += vp.Width / 2 + vp.X;
4259 y += vp.Height / 2 + vp.Y;
4260 z += vp.MinZ;
4262 rhw = 1 / rhw;
4263 } else {
4264 /* That vertex got clipped
4265 * Contrary to OpenGL it is not dropped completely, it just
4266 * undergoes a different calculation.
4268 TRACE("Vertex got clipped\n");
4269 x += rhw;
4270 y += rhw;
4272 x /= 2;
4273 y /= 2;
4275 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4276 * outside of the main vertex buffer memory. That needs some more
4277 * investigation...
4281 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4284 ( (float *) dest_ptr)[0] = x;
4285 ( (float *) dest_ptr)[1] = y;
4286 ( (float *) dest_ptr)[2] = z;
4287 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4289 dest_ptr += 3 * sizeof(float);
4291 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4292 dest_ptr += sizeof(float);
4295 if(dest_conv) {
4296 float w = 1 / rhw;
4297 ( (float *) dest_conv)[0] = x * w;
4298 ( (float *) dest_conv)[1] = y * w;
4299 ( (float *) dest_conv)[2] = z * w;
4300 ( (float *) dest_conv)[3] = w;
4302 dest_conv += 3 * sizeof(float);
4304 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4305 dest_conv += sizeof(float);
4309 if (DestFVF & WINED3DFVF_PSIZE) {
4310 dest_ptr += sizeof(DWORD);
4311 if(dest_conv) dest_conv += sizeof(DWORD);
4313 if (DestFVF & WINED3DFVF_NORMAL) {
4314 float *normal =
4315 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4316 /* AFAIK this should go into the lighting information */
4317 FIXME("Didn't expect the destination to have a normal\n");
4318 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4319 if(dest_conv) {
4320 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4324 if (DestFVF & WINED3DFVF_DIFFUSE) {
4325 DWORD *color_d =
4326 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4327 if(!color_d) {
4328 static BOOL warned = FALSE;
4330 if(!warned) {
4331 ERR("No diffuse color in source, but destination has one\n");
4332 warned = TRUE;
4335 *( (DWORD *) dest_ptr) = 0xffffffff;
4336 dest_ptr += sizeof(DWORD);
4338 if(dest_conv) {
4339 *( (DWORD *) dest_conv) = 0xffffffff;
4340 dest_conv += sizeof(DWORD);
4343 else {
4344 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4345 if(dest_conv) {
4346 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4347 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4348 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4349 dest_conv += sizeof(DWORD);
4354 if (DestFVF & WINED3DFVF_SPECULAR) {
4355 /* What's the color value in the feedback buffer? */
4356 DWORD *color_s =
4357 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4358 if(!color_s) {
4359 static BOOL warned = FALSE;
4361 if(!warned) {
4362 ERR("No specular color in source, but destination has one\n");
4363 warned = TRUE;
4366 *( (DWORD *) dest_ptr) = 0xFF000000;
4367 dest_ptr += sizeof(DWORD);
4369 if(dest_conv) {
4370 *( (DWORD *) dest_conv) = 0xFF000000;
4371 dest_conv += sizeof(DWORD);
4374 else {
4375 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4376 if(dest_conv) {
4377 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4378 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4379 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4380 dest_conv += sizeof(DWORD);
4385 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4386 float *tex_coord =
4387 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4388 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4389 if(!tex_coord) {
4390 ERR("No source texture, but destination requests one\n");
4391 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4392 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4394 else {
4395 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4396 if(dest_conv) {
4397 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4403 if(dest_conv) {
4404 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4405 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4406 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4407 dwCount * get_flexible_vertex_size(DestFVF),
4408 dest_conv_addr));
4409 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4410 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4413 LEAVE_GL();
4415 return WINED3D_OK;
4417 #undef copy_and_next
4419 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4421 WineDirect3DVertexStridedData strided;
4422 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4423 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4425 if(pVertexDecl) {
4426 ERR("Output vertex declaration not implemented yet\n");
4429 /* Need any context to write to the vbo. */
4430 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4432 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4433 * control the streamIsUP flag, thus restore it afterwards.
4435 This->stateBlock->streamIsUP = FALSE;
4436 memset(&strided, 0, sizeof(strided));
4437 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4438 This->stateBlock->streamIsUP = streamWasUP;
4440 if(vbo || SrcStartIndex) {
4441 unsigned int i;
4442 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4443 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4445 * Also get the start index in, but only loop over all elements if there's something to add at all.
4447 #define FIXSRC(type) \
4448 if(strided.u.s.type.VBO) { \
4449 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4450 strided.u.s.type.VBO = 0; \
4451 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4452 ENTER_GL(); \
4453 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4454 vb->vbo = 0; \
4455 LEAVE_GL(); \
4457 if(strided.u.s.type.lpData) { \
4458 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4460 FIXSRC(position);
4461 FIXSRC(blendWeights);
4462 FIXSRC(blendMatrixIndices);
4463 FIXSRC(normal);
4464 FIXSRC(pSize);
4465 FIXSRC(diffuse);
4466 FIXSRC(specular);
4467 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4468 FIXSRC(texCoords[i]);
4470 FIXSRC(position2);
4471 FIXSRC(normal2);
4472 FIXSRC(tangent);
4473 FIXSRC(binormal);
4474 FIXSRC(tessFactor);
4475 FIXSRC(fog);
4476 FIXSRC(depth);
4477 FIXSRC(sample);
4478 #undef FIXSRC
4481 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4484 /*****
4485 * Get / Set Texture Stage States
4486 * TODO: Verify against dx9 definitions
4487 *****/
4488 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4490 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4492 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4494 if (Stage >= MAX_TEXTURES) {
4495 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4496 return WINED3D_OK;
4499 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4500 This->updateStateBlock->textureState[Stage][Type] = Value;
4502 if (This->isRecordingState) {
4503 TRACE("Recording... not performing anything\n");
4504 return WINED3D_OK;
4507 /* Checked after the assignments to allow proper stateblock recording */
4508 if(oldValue == Value) {
4509 TRACE("App is setting the old value over, nothing to do\n");
4510 return WINED3D_OK;
4513 if(Stage > This->stateBlock->lowest_disabled_stage &&
4514 This->shader_backend->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4515 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4516 * Changes in other states are important on disabled stages too
4518 return WINED3D_OK;
4521 if(Type == WINED3DTSS_COLOROP) {
4522 int i;
4524 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4525 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4526 * they have to be disabled
4528 * The current stage is dirtified below.
4530 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4531 TRACE("Additionally dirtifying stage %d\n", i);
4532 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4534 This->stateBlock->lowest_disabled_stage = Stage;
4535 TRACE("New lowest disabled: %d\n", Stage);
4536 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4537 /* Previously disabled stage enabled. Stages above it may need enabling
4538 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4539 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4541 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4544 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4545 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4546 break;
4548 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4549 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4551 This->stateBlock->lowest_disabled_stage = i;
4552 TRACE("New lowest disabled: %d\n", i);
4554 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4555 /* TODO: Built a stage -> texture unit mapping for register combiners */
4559 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4561 return WINED3D_OK;
4564 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4566 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4567 *pValue = This->updateStateBlock->textureState[Stage][Type];
4568 return WINED3D_OK;
4571 /*****
4572 * Get / Set Texture
4573 *****/
4574 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4576 IWineD3DBaseTexture *oldTexture;
4578 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4580 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4581 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4584 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4585 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4586 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4589 oldTexture = This->updateStateBlock->textures[Stage];
4591 if(pTexture != NULL) {
4592 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4594 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4595 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4596 return WINED3DERR_INVALIDCALL;
4598 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4601 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4602 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4604 This->updateStateBlock->changed.textures[Stage] = TRUE;
4605 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4606 This->updateStateBlock->textures[Stage] = pTexture;
4608 /* Handle recording of state blocks */
4609 if (This->isRecordingState) {
4610 TRACE("Recording... not performing anything\n");
4611 return WINED3D_OK;
4614 if(oldTexture == pTexture) {
4615 TRACE("App is setting the same texture again, nothing to do\n");
4616 return WINED3D_OK;
4619 /** NOTE: MSDN says that setTexture increases the reference count,
4620 * and that the application must set the texture back to null (or have a leaky application),
4621 * This means we should pass the refcount up to the parent
4622 *******************************/
4623 if (NULL != This->updateStateBlock->textures[Stage]) {
4624 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4625 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4627 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4628 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4629 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4630 * so the COLOROP and ALPHAOP have to be dirtified.
4632 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4633 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4635 if(bindCount == 1) {
4636 new->baseTexture.sampler = Stage;
4638 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4642 if (NULL != oldTexture) {
4643 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4644 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4646 IWineD3DBaseTexture_Release(oldTexture);
4647 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4648 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4649 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4652 if(bindCount && old->baseTexture.sampler == Stage) {
4653 int i;
4654 /* Have to do a search for the other sampler(s) where the texture is bound to
4655 * Shouldn't happen as long as apps bind a texture only to one stage
4657 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4658 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4659 if(This->updateStateBlock->textures[i] == oldTexture) {
4660 old->baseTexture.sampler = i;
4661 break;
4667 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4669 return WINED3D_OK;
4672 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4675 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4677 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4678 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4681 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4682 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4683 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4686 *ppTexture=This->stateBlock->textures[Stage];
4687 if (*ppTexture)
4688 IWineD3DBaseTexture_AddRef(*ppTexture);
4690 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4692 return WINED3D_OK;
4695 /*****
4696 * Get Back Buffer
4697 *****/
4698 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4699 IWineD3DSurface **ppBackBuffer) {
4700 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4701 IWineD3DSwapChain *swapChain;
4702 HRESULT hr;
4704 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4706 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4707 if (hr == WINED3D_OK) {
4708 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4709 IWineD3DSwapChain_Release(swapChain);
4710 } else {
4711 *ppBackBuffer = NULL;
4713 return hr;
4716 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4718 WARN("(%p) : stub, calling idirect3d for now\n", This);
4719 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4722 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4724 IWineD3DSwapChain *swapChain;
4725 HRESULT hr;
4727 if(iSwapChain > 0) {
4728 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4729 if (hr == WINED3D_OK) {
4730 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4731 IWineD3DSwapChain_Release(swapChain);
4732 } else {
4733 FIXME("(%p) Error getting display mode\n", This);
4735 } else {
4736 /* Don't read the real display mode,
4737 but return the stored mode instead. X11 can't change the color
4738 depth, and some apps are pretty angry if they SetDisplayMode from
4739 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4741 Also don't relay to the swapchain because with ddraw it's possible
4742 that there isn't a swapchain at all */
4743 pMode->Width = This->ddraw_width;
4744 pMode->Height = This->ddraw_height;
4745 pMode->Format = This->ddraw_format;
4746 pMode->RefreshRate = 0;
4747 hr = WINED3D_OK;
4750 return hr;
4753 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4755 TRACE("(%p)->(%p)\n", This, hWnd);
4757 if(This->ddraw_fullscreen) {
4758 if(This->ddraw_window && This->ddraw_window != hWnd) {
4759 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4761 if(hWnd && This->ddraw_window != hWnd) {
4762 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4766 This->ddraw_window = hWnd;
4767 return WINED3D_OK;
4770 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4772 TRACE("(%p)->(%p)\n", This, hWnd);
4774 *hWnd = This->ddraw_window;
4775 return WINED3D_OK;
4778 /*****
4779 * Stateblock related functions
4780 *****/
4782 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4784 IWineD3DStateBlockImpl *object;
4785 HRESULT temp_result;
4786 int i;
4788 TRACE("(%p)\n", This);
4790 if (This->isRecordingState) {
4791 return WINED3DERR_INVALIDCALL;
4794 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4795 if (NULL == object ) {
4796 FIXME("(%p)Error allocating memory for stateblock\n", This);
4797 return E_OUTOFMEMORY;
4799 TRACE("(%p) created object %p\n", This, object);
4800 object->wineD3DDevice= This;
4801 /** FIXME: object->parent = parent; **/
4802 object->parent = NULL;
4803 object->blockType = WINED3DSBT_RECORDED;
4804 object->ref = 1;
4805 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4807 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4808 list_init(&object->lightMap[i]);
4811 temp_result = allocate_shader_constants(object);
4812 if (WINED3D_OK != temp_result)
4813 return temp_result;
4815 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4816 This->updateStateBlock = object;
4817 This->isRecordingState = TRUE;
4819 TRACE("(%p) recording stateblock %p\n",This , object);
4820 return WINED3D_OK;
4823 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4825 unsigned int i, j;
4826 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4828 if (!This->isRecordingState) {
4829 FIXME("(%p) not recording! returning error\n", This);
4830 *ppStateBlock = NULL;
4831 return WINED3DERR_INVALIDCALL;
4834 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4835 if(object->changed.renderState[i]) {
4836 object->contained_render_states[object->num_contained_render_states] = i;
4837 object->num_contained_render_states++;
4840 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4841 if(object->changed.transform[i]) {
4842 object->contained_transform_states[object->num_contained_transform_states] = i;
4843 object->num_contained_transform_states++;
4846 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4847 if(object->changed.vertexShaderConstantsF[i]) {
4848 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4849 object->num_contained_vs_consts_f++;
4852 for(i = 0; i < MAX_CONST_I; i++) {
4853 if(object->changed.vertexShaderConstantsI[i]) {
4854 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4855 object->num_contained_vs_consts_i++;
4858 for(i = 0; i < MAX_CONST_B; i++) {
4859 if(object->changed.vertexShaderConstantsB[i]) {
4860 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4861 object->num_contained_vs_consts_b++;
4864 for(i = 0; i < MAX_CONST_I; i++) {
4865 if(object->changed.pixelShaderConstantsI[i]) {
4866 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4867 object->num_contained_ps_consts_i++;
4870 for(i = 0; i < MAX_CONST_B; i++) {
4871 if(object->changed.pixelShaderConstantsB[i]) {
4872 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4873 object->num_contained_ps_consts_b++;
4876 for(i = 0; i < MAX_TEXTURES; i++) {
4877 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4878 if(object->changed.textureState[i][j]) {
4879 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4880 object->contained_tss_states[object->num_contained_tss_states].state = j;
4881 object->num_contained_tss_states++;
4885 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4886 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4887 if(object->changed.samplerState[i][j]) {
4888 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4889 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4890 object->num_contained_sampler_states++;
4895 *ppStateBlock = (IWineD3DStateBlock*) object;
4896 This->isRecordingState = FALSE;
4897 This->updateStateBlock = This->stateBlock;
4898 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4899 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4900 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4901 return WINED3D_OK;
4904 /*****
4905 * Scene related functions
4906 *****/
4907 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4908 /* At the moment we have no need for any functionality at the beginning
4909 of a scene */
4910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4911 TRACE("(%p)\n", This);
4913 if(This->inScene) {
4914 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4915 return WINED3DERR_INVALIDCALL;
4917 This->inScene = TRUE;
4918 return WINED3D_OK;
4921 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4923 TRACE("(%p)\n", This);
4925 if(!This->inScene) {
4926 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4927 return WINED3DERR_INVALIDCALL;
4930 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4931 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4932 ENTER_GL();
4933 glFlush();
4934 checkGLcall("glFlush");
4935 LEAVE_GL();
4937 This->inScene = FALSE;
4938 return WINED3D_OK;
4941 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4942 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4943 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4945 IWineD3DSwapChain *swapChain = NULL;
4946 int i;
4947 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4949 TRACE("(%p) Presenting the frame\n", This);
4951 for(i = 0 ; i < swapchains ; i ++) {
4953 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4954 TRACE("presentinng chain %d, %p\n", i, swapChain);
4955 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4956 IWineD3DSwapChain_Release(swapChain);
4959 return WINED3D_OK;
4962 /* Not called from the VTable (internal subroutine) */
4963 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4964 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4965 float Z, DWORD Stencil) {
4966 GLbitfield glMask = 0;
4967 unsigned int i;
4968 WINED3DRECT curRect;
4969 RECT vp_rect;
4970 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4971 UINT drawable_width, drawable_height;
4972 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4974 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4975 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4976 * for the cleared parts, and the untouched parts.
4978 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4979 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4980 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4981 * checking all this if the dest surface is in the drawable anyway.
4983 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4984 while(1) {
4985 if(vp->X != 0 || vp->Y != 0 ||
4986 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4987 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4988 break;
4990 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4991 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4992 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4993 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4994 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4995 break;
4997 if(Count > 0 && pRects && (
4998 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4999 pRects[0].x2 < target->currentDesc.Width ||
5000 pRects[0].y2 < target->currentDesc.Height)) {
5001 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5002 break;
5004 break;
5008 target->get_drawable_size(target, &drawable_width, &drawable_height);
5010 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5011 ENTER_GL();
5013 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5014 apply_fbo_state((IWineD3DDevice *) This);
5017 /* Only set the values up once, as they are not changing */
5018 if (Flags & WINED3DCLEAR_STENCIL) {
5019 glClearStencil(Stencil);
5020 checkGLcall("glClearStencil");
5021 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5022 glStencilMask(0xFFFFFFFF);
5025 if (Flags & WINED3DCLEAR_ZBUFFER) {
5026 glDepthMask(GL_TRUE);
5027 glClearDepth(Z);
5028 checkGLcall("glClearDepth");
5029 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5030 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5032 if(This->depth_copy_state == WINED3D_DCS_COPY) {
5033 if(vp->X != 0 || vp->Y != 0 ||
5034 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5035 depth_copy((IWineD3DDevice *) This);
5037 else if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5038 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5039 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5040 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5041 depth_copy((IWineD3DDevice *) This);
5043 else if(Count > 0 && pRects && (
5044 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5045 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5046 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5047 depth_copy((IWineD3DDevice *) This);
5050 This->depth_copy_state = WINED3D_DCS_INITIAL;
5053 if (Flags & WINED3DCLEAR_TARGET) {
5054 TRACE("Clearing screen with glClear to color %x\n", Color);
5055 glClearColor(D3DCOLOR_R(Color),
5056 D3DCOLOR_G(Color),
5057 D3DCOLOR_B(Color),
5058 D3DCOLOR_A(Color));
5059 checkGLcall("glClearColor");
5061 /* Clear ALL colors! */
5062 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5063 glMask = glMask | GL_COLOR_BUFFER_BIT;
5066 vp_rect.left = vp->X;
5067 vp_rect.top = vp->Y;
5068 vp_rect.right = vp->X + vp->Width;
5069 vp_rect.bottom = vp->Y + vp->Height;
5070 if (!(Count > 0 && pRects)) {
5071 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5072 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5074 if(This->render_offscreen) {
5075 glScissor(vp_rect.left, vp_rect.top,
5076 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5077 } else {
5078 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5079 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5081 checkGLcall("glScissor");
5082 glClear(glMask);
5083 checkGLcall("glClear");
5084 } else {
5085 /* Now process each rect in turn */
5086 for (i = 0; i < Count; i++) {
5087 /* Note gl uses lower left, width/height */
5088 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5089 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5090 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5092 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5093 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5094 curRect.x1, (target->currentDesc.Height - curRect.y2),
5095 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5097 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5098 * The rectangle is not cleared, no error is returned, but further rectanlges are
5099 * still cleared if they are valid
5101 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5102 TRACE("Rectangle with negative dimensions, ignoring\n");
5103 continue;
5106 if(This->render_offscreen) {
5107 glScissor(curRect.x1, curRect.y1,
5108 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5109 } else {
5110 glScissor(curRect.x1, drawable_height - curRect.y2,
5111 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5113 checkGLcall("glScissor");
5115 glClear(glMask);
5116 checkGLcall("glClear");
5120 /* Restore the old values (why..?) */
5121 if (Flags & WINED3DCLEAR_STENCIL) {
5122 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5124 if (Flags & WINED3DCLEAR_TARGET) {
5125 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5126 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5127 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5128 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5129 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5131 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5132 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5134 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5135 /* TODO: Move the fbo logic into ModifyLocation() */
5136 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5137 target->Flags |= SFLAG_INTEXTURE;
5140 LEAVE_GL();
5142 return WINED3D_OK;
5145 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5146 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5148 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5150 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5151 Count, pRects, Flags, Color, Z, Stencil);
5153 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5154 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5155 /* TODO: What about depth stencil buffers without stencil bits? */
5156 return WINED3DERR_INVALIDCALL;
5159 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5162 /*****
5163 * Drawing functions
5164 *****/
5165 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5166 UINT PrimitiveCount) {
5168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5170 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5171 debug_d3dprimitivetype(PrimitiveType),
5172 StartVertex, PrimitiveCount);
5174 if(!This->stateBlock->vertexDecl) {
5175 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5176 return WINED3DERR_INVALIDCALL;
5179 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5180 if(This->stateBlock->streamIsUP) {
5181 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5182 This->stateBlock->streamIsUP = FALSE;
5185 if(This->stateBlock->loadBaseVertexIndex != 0) {
5186 This->stateBlock->loadBaseVertexIndex = 0;
5187 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5189 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5190 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5191 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5192 return WINED3D_OK;
5195 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5196 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5197 WINED3DPRIMITIVETYPE PrimitiveType,
5198 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5201 UINT idxStride = 2;
5202 IWineD3DIndexBuffer *pIB;
5203 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5204 GLuint vbo;
5206 pIB = This->stateBlock->pIndexData;
5207 if (!pIB) {
5208 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5209 * without an index buffer set. (The first time at least...)
5210 * D3D8 simply dies, but I doubt it can do much harm to return
5211 * D3DERR_INVALIDCALL there as well. */
5212 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5213 return WINED3DERR_INVALIDCALL;
5216 if(!This->stateBlock->vertexDecl) {
5217 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5218 return WINED3DERR_INVALIDCALL;
5221 if(This->stateBlock->streamIsUP) {
5222 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5223 This->stateBlock->streamIsUP = FALSE;
5225 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5227 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5228 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5229 minIndex, NumVertices, startIndex, primCount);
5231 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5232 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5233 idxStride = 2;
5234 } else {
5235 idxStride = 4;
5238 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5239 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5240 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5243 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5244 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5246 return WINED3D_OK;
5249 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5250 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5251 UINT VertexStreamZeroStride) {
5252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5253 IWineD3DVertexBuffer *vb;
5255 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5256 debug_d3dprimitivetype(PrimitiveType),
5257 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5259 if(!This->stateBlock->vertexDecl) {
5260 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5261 return WINED3DERR_INVALIDCALL;
5264 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5265 vb = This->stateBlock->streamSource[0];
5266 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5267 if(vb) IWineD3DVertexBuffer_Release(vb);
5268 This->stateBlock->streamOffset[0] = 0;
5269 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5270 This->stateBlock->streamIsUP = TRUE;
5271 This->stateBlock->loadBaseVertexIndex = 0;
5273 /* TODO: Only mark dirty if drawing from a different UP address */
5274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5276 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5277 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5279 /* MSDN specifies stream zero settings must be set to NULL */
5280 This->stateBlock->streamStride[0] = 0;
5281 This->stateBlock->streamSource[0] = NULL;
5283 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5284 * the new stream sources or use UP drawing again
5286 return WINED3D_OK;
5289 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5290 UINT MinVertexIndex, UINT NumVertices,
5291 UINT PrimitiveCount, CONST void* pIndexData,
5292 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5293 UINT VertexStreamZeroStride) {
5294 int idxStride;
5295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5296 IWineD3DVertexBuffer *vb;
5297 IWineD3DIndexBuffer *ib;
5299 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5300 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5301 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5302 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5304 if(!This->stateBlock->vertexDecl) {
5305 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5306 return WINED3DERR_INVALIDCALL;
5309 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5310 idxStride = 2;
5311 } else {
5312 idxStride = 4;
5315 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5316 vb = This->stateBlock->streamSource[0];
5317 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5318 if(vb) IWineD3DVertexBuffer_Release(vb);
5319 This->stateBlock->streamIsUP = TRUE;
5320 This->stateBlock->streamOffset[0] = 0;
5321 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5323 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5324 This->stateBlock->baseVertexIndex = 0;
5325 This->stateBlock->loadBaseVertexIndex = 0;
5326 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5327 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5328 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5330 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5332 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5333 This->stateBlock->streamSource[0] = NULL;
5334 This->stateBlock->streamStride[0] = 0;
5335 ib = This->stateBlock->pIndexData;
5336 if(ib) {
5337 IWineD3DIndexBuffer_Release(ib);
5338 This->stateBlock->pIndexData = NULL;
5340 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5341 * SetStreamSource to specify a vertex buffer
5344 return WINED3D_OK;
5347 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5350 /* Mark the state dirty until we have nicer tracking
5351 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5352 * that value.
5354 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5355 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5356 This->stateBlock->baseVertexIndex = 0;
5357 This->up_strided = DrawPrimStrideData;
5358 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5359 This->up_strided = NULL;
5360 return WINED3D_OK;
5363 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5365 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5367 /* Mark the state dirty until we have nicer tracking
5368 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5369 * that value.
5371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5372 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5373 This->stateBlock->streamIsUP = TRUE;
5374 This->stateBlock->baseVertexIndex = 0;
5375 This->up_strided = DrawPrimStrideData;
5376 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5377 This->up_strided = NULL;
5378 return WINED3D_OK;
5381 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5382 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5383 * not callable by the app directly no parameter validation checks are needed here.
5385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5386 WINED3DLOCKED_BOX src;
5387 WINED3DLOCKED_BOX dst;
5388 HRESULT hr;
5389 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5391 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5392 * dirtification to improve loading performance.
5394 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5395 if(FAILED(hr)) return hr;
5396 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5397 if(FAILED(hr)) {
5398 IWineD3DVolume_UnlockBox(pSourceVolume);
5399 return hr;
5402 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5404 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5405 if(FAILED(hr)) {
5406 IWineD3DVolume_UnlockBox(pSourceVolume);
5407 } else {
5408 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5410 return hr;
5413 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5414 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5416 HRESULT hr = WINED3D_OK;
5417 WINED3DRESOURCETYPE sourceType;
5418 WINED3DRESOURCETYPE destinationType;
5419 int i ,levels;
5421 /* TODO: think about moving the code into IWineD3DBaseTexture */
5423 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5425 /* verify that the source and destination textures aren't NULL */
5426 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5427 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5428 This, pSourceTexture, pDestinationTexture);
5429 hr = WINED3DERR_INVALIDCALL;
5432 if (pSourceTexture == pDestinationTexture) {
5433 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5434 This, pSourceTexture, pDestinationTexture);
5435 hr = WINED3DERR_INVALIDCALL;
5437 /* Verify that the source and destination textures are the same type */
5438 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5439 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5441 if (sourceType != destinationType) {
5442 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5443 This);
5444 hr = WINED3DERR_INVALIDCALL;
5447 /* check that both textures have the identical numbers of levels */
5448 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5449 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5450 hr = WINED3DERR_INVALIDCALL;
5453 if (WINED3D_OK == hr) {
5455 /* Make sure that the destination texture is loaded */
5456 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5458 /* Update every surface level of the texture */
5459 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5461 switch (sourceType) {
5462 case WINED3DRTYPE_TEXTURE:
5464 IWineD3DSurface *srcSurface;
5465 IWineD3DSurface *destSurface;
5467 for (i = 0 ; i < levels ; ++i) {
5468 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5469 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5470 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5471 IWineD3DSurface_Release(srcSurface);
5472 IWineD3DSurface_Release(destSurface);
5473 if (WINED3D_OK != hr) {
5474 WARN("(%p) : Call to update surface failed\n", This);
5475 return hr;
5479 break;
5480 case WINED3DRTYPE_CUBETEXTURE:
5482 IWineD3DSurface *srcSurface;
5483 IWineD3DSurface *destSurface;
5484 WINED3DCUBEMAP_FACES faceType;
5486 for (i = 0 ; i < levels ; ++i) {
5487 /* Update each cube face */
5488 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5489 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5490 if (WINED3D_OK != hr) {
5491 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5492 } else {
5493 TRACE("Got srcSurface %p\n", srcSurface);
5495 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5496 if (WINED3D_OK != hr) {
5497 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5498 } else {
5499 TRACE("Got desrSurface %p\n", destSurface);
5501 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5502 IWineD3DSurface_Release(srcSurface);
5503 IWineD3DSurface_Release(destSurface);
5504 if (WINED3D_OK != hr) {
5505 WARN("(%p) : Call to update surface failed\n", This);
5506 return hr;
5511 break;
5513 case WINED3DRTYPE_VOLUMETEXTURE:
5515 IWineD3DVolume *srcVolume = NULL;
5516 IWineD3DVolume *destVolume = NULL;
5518 for (i = 0 ; i < levels ; ++i) {
5519 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5520 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5521 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5522 IWineD3DVolume_Release(srcVolume);
5523 IWineD3DVolume_Release(destVolume);
5524 if (WINED3D_OK != hr) {
5525 WARN("(%p) : Call to update volume failed\n", This);
5526 return hr;
5530 break;
5532 default:
5533 FIXME("(%p) : Unsupported source and destination type\n", This);
5534 hr = WINED3DERR_INVALIDCALL;
5538 return hr;
5541 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5542 IWineD3DSwapChain *swapChain;
5543 HRESULT hr;
5544 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5545 if(hr == WINED3D_OK) {
5546 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5547 IWineD3DSwapChain_Release(swapChain);
5549 return hr;
5552 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5554 /* return a sensible default */
5555 *pNumPasses = 1;
5556 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5557 FIXME("(%p) : stub\n", This);
5558 return WINED3D_OK;
5561 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5563 int i;
5565 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5566 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5567 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5568 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5573 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5575 int j;
5576 UINT NewSize;
5577 PALETTEENTRY **palettes;
5579 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5581 if (PaletteNumber >= MAX_PALETTES) {
5582 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5583 return WINED3DERR_INVALIDCALL;
5586 if (PaletteNumber >= This->NumberOfPalettes) {
5587 NewSize = This->NumberOfPalettes;
5588 do {
5589 NewSize *= 2;
5590 } while(PaletteNumber >= NewSize);
5591 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5592 if (!palettes) {
5593 ERR("Out of memory!\n");
5594 return E_OUTOFMEMORY;
5596 This->palettes = palettes;
5597 This->NumberOfPalettes = NewSize;
5600 if (!This->palettes[PaletteNumber]) {
5601 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5602 if (!This->palettes[PaletteNumber]) {
5603 ERR("Out of memory!\n");
5604 return E_OUTOFMEMORY;
5608 for (j = 0; j < 256; ++j) {
5609 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5610 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5611 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5612 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5614 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5615 TRACE("(%p) : returning\n", This);
5616 return WINED3D_OK;
5619 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5621 int j;
5622 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5623 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5624 /* What happens in such situation isn't documented; Native seems to silently abort
5625 on such conditions. Return Invalid Call. */
5626 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5627 return WINED3DERR_INVALIDCALL;
5629 for (j = 0; j < 256; ++j) {
5630 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5631 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5632 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5633 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5635 TRACE("(%p) : returning\n", This);
5636 return WINED3D_OK;
5639 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5641 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5642 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5643 (tested with reference rasterizer). Return Invalid Call. */
5644 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5645 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5646 return WINED3DERR_INVALIDCALL;
5648 /*TODO: stateblocks */
5649 if (This->currentPalette != PaletteNumber) {
5650 This->currentPalette = PaletteNumber;
5651 dirtify_p8_texture_samplers(This);
5653 TRACE("(%p) : returning\n", This);
5654 return WINED3D_OK;
5657 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5659 if (PaletteNumber == NULL) {
5660 WARN("(%p) : returning Invalid Call\n", This);
5661 return WINED3DERR_INVALIDCALL;
5663 /*TODO: stateblocks */
5664 *PaletteNumber = This->currentPalette;
5665 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5666 return WINED3D_OK;
5669 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5670 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5671 static BOOL showFixmes = TRUE;
5672 if (showFixmes) {
5673 FIXME("(%p) : stub\n", This);
5674 showFixmes = FALSE;
5677 This->softwareVertexProcessing = bSoftware;
5678 return WINED3D_OK;
5682 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5684 static BOOL showFixmes = TRUE;
5685 if (showFixmes) {
5686 FIXME("(%p) : stub\n", This);
5687 showFixmes = FALSE;
5689 return This->softwareVertexProcessing;
5693 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5695 IWineD3DSwapChain *swapChain;
5696 HRESULT hr;
5698 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5700 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5701 if(hr == WINED3D_OK){
5702 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5703 IWineD3DSwapChain_Release(swapChain);
5704 }else{
5705 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5707 return hr;
5711 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5713 static BOOL showfixmes = TRUE;
5714 if(nSegments != 0.0f) {
5715 if( showfixmes) {
5716 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5717 showfixmes = FALSE;
5720 return WINED3D_OK;
5723 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5725 static BOOL showfixmes = TRUE;
5726 if( showfixmes) {
5727 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5728 showfixmes = FALSE;
5730 return 0.0f;
5733 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5735 /** TODO: remove casts to IWineD3DSurfaceImpl
5736 * NOTE: move code to surface to accomplish this
5737 ****************************************/
5738 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5739 int srcWidth, srcHeight;
5740 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5741 WINED3DFORMAT destFormat, srcFormat;
5742 UINT destSize;
5743 int srcLeft, destLeft, destTop;
5744 WINED3DPOOL srcPool, destPool;
5745 int offset = 0;
5746 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5747 glDescriptor *glDescription = NULL;
5748 GLenum dummy;
5749 int bpp;
5750 CONVERT_TYPES convert = NO_CONVERSION;
5752 WINED3DSURFACE_DESC winedesc;
5754 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5755 memset(&winedesc, 0, sizeof(winedesc));
5756 winedesc.Width = &srcSurfaceWidth;
5757 winedesc.Height = &srcSurfaceHeight;
5758 winedesc.Pool = &srcPool;
5759 winedesc.Format = &srcFormat;
5761 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5763 winedesc.Width = &destSurfaceWidth;
5764 winedesc.Height = &destSurfaceHeight;
5765 winedesc.Pool = &destPool;
5766 winedesc.Format = &destFormat;
5767 winedesc.Size = &destSize;
5769 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5771 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5772 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5773 return WINED3DERR_INVALIDCALL;
5776 /* This call loads the opengl surface directly, instead of copying the surface to the
5777 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5778 * copy in sysmem and use regular surface loading.
5780 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5781 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5782 if(convert != NO_CONVERSION) {
5783 return IWineD3DSurface_BltFast(pDestinationSurface,
5784 pDestPoint ? pDestPoint->x : 0,
5785 pDestPoint ? pDestPoint->y : 0,
5786 pSourceSurface, (RECT *) pSourceRect, 0);
5789 if (destFormat == WINED3DFMT_UNKNOWN) {
5790 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5791 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5793 /* Get the update surface description */
5794 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5797 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5799 ENTER_GL();
5801 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5802 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5803 checkGLcall("glActiveTextureARB");
5806 /* Make sure the surface is loaded and up to date */
5807 IWineD3DSurface_PreLoad(pDestinationSurface);
5809 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5811 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5812 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5813 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5814 srcLeft = pSourceRect ? pSourceRect->left : 0;
5815 destLeft = pDestPoint ? pDestPoint->x : 0;
5816 destTop = pDestPoint ? pDestPoint->y : 0;
5819 /* This function doesn't support compressed textures
5820 the pitch is just bytesPerPixel * width */
5821 if(srcWidth != srcSurfaceWidth || srcLeft ){
5822 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5823 offset += srcLeft * pSrcSurface->bytesPerPixel;
5824 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5826 /* TODO DXT formats */
5828 if(pSourceRect != NULL && pSourceRect->top != 0){
5829 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5831 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5832 ,This
5833 ,glDescription->level
5834 ,destLeft
5835 ,destTop
5836 ,srcWidth
5837 ,srcHeight
5838 ,glDescription->glFormat
5839 ,glDescription->glType
5840 ,IWineD3DSurface_GetData(pSourceSurface)
5843 /* Sanity check */
5844 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5846 /* need to lock the surface to get the data */
5847 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5850 /* TODO: Cube and volume support */
5851 if(rowoffset != 0){
5852 /* not a whole row so we have to do it a line at a time */
5853 int j;
5855 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5856 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5858 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5860 glTexSubImage2D(glDescription->target
5861 ,glDescription->level
5862 ,destLeft
5864 ,srcWidth
5866 ,glDescription->glFormat
5867 ,glDescription->glType
5868 ,data /* could be quicker using */
5870 data += rowoffset;
5873 } else { /* Full width, so just write out the whole texture */
5875 if (WINED3DFMT_DXT1 == destFormat ||
5876 WINED3DFMT_DXT2 == destFormat ||
5877 WINED3DFMT_DXT3 == destFormat ||
5878 WINED3DFMT_DXT4 == destFormat ||
5879 WINED3DFMT_DXT5 == destFormat) {
5880 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5881 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5882 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5883 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5884 } if (destFormat != srcFormat) {
5885 FIXME("Updating mixed format compressed texture is not curretly support\n");
5886 } else {
5887 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5888 glDescription->level,
5889 glDescription->glFormatInternal,
5890 srcWidth,
5891 srcHeight,
5893 destSize,
5894 IWineD3DSurface_GetData(pSourceSurface));
5896 } else {
5897 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5901 } else {
5902 glTexSubImage2D(glDescription->target
5903 ,glDescription->level
5904 ,destLeft
5905 ,destTop
5906 ,srcWidth
5907 ,srcHeight
5908 ,glDescription->glFormat
5909 ,glDescription->glType
5910 ,IWineD3DSurface_GetData(pSourceSurface)
5914 checkGLcall("glTexSubImage2D");
5916 LEAVE_GL();
5918 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5919 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5921 return WINED3D_OK;
5924 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5926 struct WineD3DRectPatch *patch;
5927 unsigned int i;
5928 struct list *e;
5929 BOOL found;
5930 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5932 if(!(Handle || pRectPatchInfo)) {
5933 /* TODO: Write a test for the return value, thus the FIXME */
5934 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5935 return WINED3DERR_INVALIDCALL;
5938 if(Handle) {
5939 i = PATCHMAP_HASHFUNC(Handle);
5940 found = FALSE;
5941 LIST_FOR_EACH(e, &This->patches[i]) {
5942 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5943 if(patch->Handle == Handle) {
5944 found = TRUE;
5945 break;
5949 if(!found) {
5950 TRACE("Patch does not exist. Creating a new one\n");
5951 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5952 patch->Handle = Handle;
5953 list_add_head(&This->patches[i], &patch->entry);
5954 } else {
5955 TRACE("Found existing patch %p\n", patch);
5957 } else {
5958 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5959 * attributes we have to tesselate, read back, and draw. This needs a patch
5960 * management structure instance. Create one.
5962 * A possible improvement is to check if a vertex shader is used, and if not directly
5963 * draw the patch.
5965 FIXME("Drawing an uncached patch. This is slow\n");
5966 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5969 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5970 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5971 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5972 HRESULT hr;
5973 TRACE("Tesselation density or patch info changed, retesselating\n");
5975 if(pRectPatchInfo) {
5976 patch->RectPatchInfo = *pRectPatchInfo;
5978 patch->numSegs[0] = pNumSegs[0];
5979 patch->numSegs[1] = pNumSegs[1];
5980 patch->numSegs[2] = pNumSegs[2];
5981 patch->numSegs[3] = pNumSegs[3];
5983 hr = tesselate_rectpatch(This, patch);
5984 if(FAILED(hr)) {
5985 WARN("Patch tesselation failed\n");
5987 /* Do not release the handle to store the params of the patch */
5988 if(!Handle) {
5989 HeapFree(GetProcessHeap(), 0, patch);
5991 return hr;
5995 This->currentPatch = patch;
5996 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5997 This->currentPatch = NULL;
5999 /* Destroy uncached patches */
6000 if(!Handle) {
6001 HeapFree(GetProcessHeap(), 0, patch->mem);
6002 HeapFree(GetProcessHeap(), 0, patch);
6004 return WINED3D_OK;
6007 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6009 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6010 FIXME("(%p) : Stub\n", This);
6011 return WINED3D_OK;
6014 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6016 int i;
6017 struct WineD3DRectPatch *patch;
6018 struct list *e;
6019 TRACE("(%p) Handle(%d)\n", This, Handle);
6021 i = PATCHMAP_HASHFUNC(Handle);
6022 LIST_FOR_EACH(e, &This->patches[i]) {
6023 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6024 if(patch->Handle == Handle) {
6025 TRACE("Deleting patch %p\n", patch);
6026 list_remove(&patch->entry);
6027 HeapFree(GetProcessHeap(), 0, patch->mem);
6028 HeapFree(GetProcessHeap(), 0, patch);
6029 return WINED3D_OK;
6033 /* TODO: Write a test for the return value */
6034 FIXME("Attempt to destroy nonexistent patch\n");
6035 return WINED3DERR_INVALIDCALL;
6038 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6039 HRESULT hr;
6040 IWineD3DSwapChain *swapchain;
6042 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6043 if (SUCCEEDED(hr)) {
6044 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6045 return swapchain;
6048 return NULL;
6051 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
6052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6054 if (!*fbo) {
6055 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
6056 checkGLcall("glGenFramebuffersEXT()");
6058 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
6059 checkGLcall("glBindFramebuffer()");
6062 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
6063 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
6064 IWineD3DBaseTextureImpl *texture_impl;
6065 GLenum texttarget, target;
6066 GLint old_binding;
6068 texttarget = surface_impl->glDescription.target;
6069 if(texttarget == GL_TEXTURE_2D) {
6070 target = GL_TEXTURE_2D;
6071 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6072 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6073 target = GL_TEXTURE_RECTANGLE_ARB;
6074 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6075 } else {
6076 target = GL_TEXTURE_CUBE_MAP_ARB;
6077 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6080 IWineD3DSurface_PreLoad(surface);
6082 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6083 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6084 glBindTexture(target, old_binding);
6086 /* Update base texture states array */
6087 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6088 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6089 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6090 if (texture_impl->baseTexture.bindCount) {
6091 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6094 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6097 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6098 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6100 checkGLcall("attach_surface_fbo");
6103 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6105 IWineD3DSwapChain *swapchain;
6107 swapchain = get_swapchain(surface);
6108 if (swapchain) {
6109 GLenum buffer;
6111 TRACE("Surface %p is onscreen\n", surface);
6113 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6114 buffer = surface_get_gl_buffer(surface, swapchain);
6115 glDrawBuffer(buffer);
6116 checkGLcall("glDrawBuffer()");
6117 } else {
6118 TRACE("Surface %p is offscreen\n", surface);
6119 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
6120 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6123 if (rect) {
6124 glEnable(GL_SCISSOR_TEST);
6125 if(!swapchain) {
6126 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6127 } else {
6128 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6129 rect->x2 - rect->x1, rect->y2 - rect->y1);
6131 checkGLcall("glScissor");
6132 } else {
6133 glDisable(GL_SCISSOR_TEST);
6135 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6137 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6138 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6140 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6141 glClear(GL_COLOR_BUFFER_BIT);
6142 checkGLcall("glClear");
6144 if (This->render_offscreen) {
6145 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6146 } else {
6147 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6148 checkGLcall("glBindFramebuffer()");
6151 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6152 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6153 glDrawBuffer(GL_BACK);
6154 checkGLcall("glDrawBuffer()");
6158 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6159 unsigned int r, g, b, a;
6160 DWORD ret;
6162 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6163 destfmt == WINED3DFMT_R8G8B8)
6164 return color;
6166 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6168 a = (color & 0xff000000) >> 24;
6169 r = (color & 0x00ff0000) >> 16;
6170 g = (color & 0x0000ff00) >> 8;
6171 b = (color & 0x000000ff) >> 0;
6173 switch(destfmt)
6175 case WINED3DFMT_R5G6B5:
6176 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6177 r = (r * 32) / 256;
6178 g = (g * 64) / 256;
6179 b = (b * 32) / 256;
6180 ret = r << 11;
6181 ret |= g << 5;
6182 ret |= b;
6183 TRACE("Returning %08x\n", ret);
6184 return ret;
6186 case WINED3DFMT_X1R5G5B5:
6187 case WINED3DFMT_A1R5G5B5:
6188 a = (a * 2) / 256;
6189 r = (r * 32) / 256;
6190 g = (g * 32) / 256;
6191 b = (b * 32) / 256;
6192 ret = a << 15;
6193 ret |= r << 10;
6194 ret |= g << 5;
6195 ret |= b << 0;
6196 TRACE("Returning %08x\n", ret);
6197 return ret;
6199 case WINED3DFMT_A8:
6200 TRACE("Returning %08x\n", a);
6201 return a;
6203 case WINED3DFMT_X4R4G4B4:
6204 case WINED3DFMT_A4R4G4B4:
6205 a = (a * 16) / 256;
6206 r = (r * 16) / 256;
6207 g = (g * 16) / 256;
6208 b = (b * 16) / 256;
6209 ret = a << 12;
6210 ret |= r << 8;
6211 ret |= g << 4;
6212 ret |= b << 0;
6213 TRACE("Returning %08x\n", ret);
6214 return ret;
6216 case WINED3DFMT_R3G3B2:
6217 r = (r * 8) / 256;
6218 g = (g * 8) / 256;
6219 b = (b * 4) / 256;
6220 ret = r << 5;
6221 ret |= g << 2;
6222 ret |= b << 0;
6223 TRACE("Returning %08x\n", ret);
6224 return ret;
6226 case WINED3DFMT_X8B8G8R8:
6227 case WINED3DFMT_A8B8G8R8:
6228 ret = a << 24;
6229 ret |= b << 16;
6230 ret |= g << 8;
6231 ret |= r << 0;
6232 TRACE("Returning %08x\n", ret);
6233 return ret;
6235 case WINED3DFMT_A2R10G10B10:
6236 a = (a * 4) / 256;
6237 r = (r * 1024) / 256;
6238 g = (g * 1024) / 256;
6239 b = (b * 1024) / 256;
6240 ret = a << 30;
6241 ret |= r << 20;
6242 ret |= g << 10;
6243 ret |= b << 0;
6244 TRACE("Returning %08x\n", ret);
6245 return ret;
6247 case WINED3DFMT_A2B10G10R10:
6248 a = (a * 4) / 256;
6249 r = (r * 1024) / 256;
6250 g = (g * 1024) / 256;
6251 b = (b * 1024) / 256;
6252 ret = a << 30;
6253 ret |= b << 20;
6254 ret |= g << 10;
6255 ret |= r << 0;
6256 TRACE("Returning %08x\n", ret);
6257 return ret;
6259 default:
6260 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6261 return 0;
6265 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6267 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6268 WINEDDBLTFX BltFx;
6269 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6271 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6272 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6273 return WINED3DERR_INVALIDCALL;
6276 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6277 ENTER_GL();
6278 color_fill_fbo(iface, pSurface, pRect, color);
6279 LEAVE_GL();
6280 return WINED3D_OK;
6281 } else {
6282 /* Just forward this to the DirectDraw blitting engine */
6283 memset(&BltFx, 0, sizeof(BltFx));
6284 BltFx.dwSize = sizeof(BltFx);
6285 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6286 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6290 /* rendertarget and depth stencil functions */
6291 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6294 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6295 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6296 return WINED3DERR_INVALIDCALL;
6299 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6300 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6301 /* Note inc ref on returned surface */
6302 if(*ppRenderTarget != NULL)
6303 IWineD3DSurface_AddRef(*ppRenderTarget);
6304 return WINED3D_OK;
6307 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6309 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6310 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6311 IWineD3DSwapChainImpl *Swapchain;
6312 HRESULT hr;
6314 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6316 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6317 if(hr != WINED3D_OK) {
6318 ERR("Can't get the swapchain\n");
6319 return hr;
6322 /* Make sure to release the swapchain */
6323 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6325 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6326 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6327 return WINED3DERR_INVALIDCALL;
6329 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6330 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6331 return WINED3DERR_INVALIDCALL;
6334 if(Swapchain->frontBuffer != Front) {
6335 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6337 if(Swapchain->frontBuffer)
6338 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6339 Swapchain->frontBuffer = Front;
6341 if(Swapchain->frontBuffer) {
6342 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6346 if(Back && !Swapchain->backBuffer) {
6347 /* We need memory for the back buffer array - only one back buffer this way */
6348 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6349 if(!Swapchain->backBuffer) {
6350 ERR("Out of memory\n");
6351 return E_OUTOFMEMORY;
6355 if(Swapchain->backBuffer[0] != Back) {
6356 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6358 /* What to do about the context here in the case of multithreading? Not sure.
6359 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6361 ENTER_GL();
6362 if(!Swapchain->backBuffer[0]) {
6363 /* GL was told to draw to the front buffer at creation,
6364 * undo that
6366 glDrawBuffer(GL_BACK);
6367 checkGLcall("glDrawBuffer(GL_BACK)");
6368 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6369 Swapchain->presentParms.BackBufferCount = 1;
6370 } else if (!Back) {
6371 /* That makes problems - disable for now */
6372 /* glDrawBuffer(GL_FRONT); */
6373 checkGLcall("glDrawBuffer(GL_FRONT)");
6374 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6375 Swapchain->presentParms.BackBufferCount = 0;
6377 LEAVE_GL();
6379 if(Swapchain->backBuffer[0])
6380 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6381 Swapchain->backBuffer[0] = Back;
6383 if(Swapchain->backBuffer[0]) {
6384 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6385 } else {
6386 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6387 Swapchain->backBuffer = NULL;
6392 return WINED3D_OK;
6395 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6397 *ppZStencilSurface = This->stencilBufferTarget;
6398 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6400 if(*ppZStencilSurface != NULL) {
6401 /* Note inc ref on returned surface */
6402 IWineD3DSurface_AddRef(*ppZStencilSurface);
6403 return WINED3D_OK;
6404 } else {
6405 return WINED3DERR_NOTFOUND;
6409 /* TODO: Handle stencil attachments */
6410 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6411 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6412 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6414 TRACE("Set depth stencil to %p\n", depth_stencil);
6416 if (depth_stencil_impl) {
6417 if (depth_stencil_impl->current_renderbuffer) {
6418 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6419 checkGLcall("glFramebufferRenderbufferEXT()");
6420 } else {
6421 IWineD3DBaseTextureImpl *texture_impl;
6422 GLenum texttarget, target;
6423 GLint old_binding = 0;
6425 texttarget = depth_stencil_impl->glDescription.target;
6426 if(texttarget == GL_TEXTURE_2D) {
6427 target = GL_TEXTURE_2D;
6428 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6429 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6430 target = GL_TEXTURE_RECTANGLE_ARB;
6431 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6432 } else {
6433 target = GL_TEXTURE_CUBE_MAP_ARB;
6434 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6437 IWineD3DSurface_PreLoad(depth_stencil);
6439 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6440 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6441 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6442 glBindTexture(target, old_binding);
6444 /* Update base texture states array */
6445 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6446 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6447 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6448 if (texture_impl->baseTexture.bindCount) {
6449 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6452 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6455 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6456 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6457 checkGLcall("glFramebufferTexture2DEXT()");
6459 } else {
6460 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6461 checkGLcall("glFramebufferTexture2DEXT()");
6465 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6467 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6469 TRACE("Set render target %u to %p\n", idx, render_target);
6471 if (rtimpl) {
6472 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6473 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6474 } else {
6475 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6476 checkGLcall("glFramebufferTexture2DEXT()");
6478 This->draw_buffers[idx] = GL_NONE;
6482 static void check_fbo_status(IWineD3DDevice *iface) {
6483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6484 GLenum status;
6486 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6487 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6488 TRACE("FBO complete\n");
6489 } else {
6490 IWineD3DSurfaceImpl *attachment;
6491 int i;
6492 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6494 /* Dump the FBO attachments */
6495 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6496 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6497 if (attachment) {
6498 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6499 attachment->pow2Width, attachment->pow2Height);
6502 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6503 if (attachment) {
6504 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6505 attachment->pow2Width, attachment->pow2Height);
6510 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6511 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6512 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6513 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6515 if (!ds_impl) return FALSE;
6517 if (ds_impl->current_renderbuffer) {
6518 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6519 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6522 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6523 rt_impl->pow2Height != ds_impl->pow2Height);
6526 void apply_fbo_state(IWineD3DDevice *iface) {
6527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6528 unsigned int i;
6530 if (This->render_offscreen) {
6531 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6533 /* Apply render targets */
6534 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6535 IWineD3DSurface *render_target = This->render_targets[i];
6536 if (This->fbo_color_attachments[i] != render_target) {
6537 set_render_target_fbo(iface, i, render_target);
6538 This->fbo_color_attachments[i] = render_target;
6542 /* Apply depth targets */
6543 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6544 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6545 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6547 if (This->stencilBufferTarget) {
6548 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6550 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6551 This->fbo_depth_attachment = This->stencilBufferTarget;
6554 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6555 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6556 checkGLcall("glDrawBuffers()");
6557 } else {
6558 glDrawBuffer(This->draw_buffers[0]);
6559 checkGLcall("glDrawBuffer()");
6561 } else {
6562 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6565 check_fbo_status(iface);
6568 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6569 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6571 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6572 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6573 GLenum gl_filter;
6575 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6576 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6577 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6578 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6580 switch (filter) {
6581 case WINED3DTEXF_LINEAR:
6582 gl_filter = GL_LINEAR;
6583 break;
6585 default:
6586 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6587 case WINED3DTEXF_NONE:
6588 case WINED3DTEXF_POINT:
6589 gl_filter = GL_NEAREST;
6590 break;
6593 /* Attach src surface to src fbo */
6594 src_swapchain = get_swapchain(src_surface);
6595 if (src_swapchain) {
6596 GLenum buffer;
6598 TRACE("Source surface %p is onscreen\n", src_surface);
6599 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6600 /* Make sure the drawable is up to date. In the offscreen case
6601 * attach_surface_fbo() implicitly takes care of this. */
6602 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6604 ENTER_GL();
6605 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6606 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6607 glReadBuffer(buffer);
6608 checkGLcall("glReadBuffer()");
6610 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6611 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6612 } else {
6613 TRACE("Source surface %p is offscreen\n", src_surface);
6614 ENTER_GL();
6615 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6616 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6617 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6618 checkGLcall("glReadBuffer()");
6620 LEAVE_GL();
6622 /* Attach dst surface to dst fbo */
6623 dst_swapchain = get_swapchain(dst_surface);
6624 if (dst_swapchain) {
6625 GLenum buffer;
6627 TRACE("Destination surface %p is onscreen\n", dst_surface);
6628 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6629 /* Make sure the drawable is up to date. In the offscreen case
6630 * attach_surface_fbo() implicitly takes care of this. */
6631 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6633 ENTER_GL();
6634 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6635 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6636 glDrawBuffer(buffer);
6637 checkGLcall("glDrawBuffer()");
6639 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6640 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6641 } else {
6642 TRACE("Destination surface %p is offscreen\n", dst_surface);
6644 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6645 if(!src_swapchain) {
6646 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6649 ENTER_GL();
6650 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6651 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6652 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6653 checkGLcall("glDrawBuffer()");
6655 glDisable(GL_SCISSOR_TEST);
6656 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6658 if (flip) {
6659 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6660 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6661 checkGLcall("glBlitFramebuffer()");
6662 } else {
6663 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6664 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6665 checkGLcall("glBlitFramebuffer()");
6668 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6670 if (This->render_offscreen) {
6671 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6672 } else {
6673 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6674 checkGLcall("glBindFramebuffer()");
6677 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6678 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6679 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6680 glDrawBuffer(GL_BACK);
6681 checkGLcall("glDrawBuffer()");
6683 LEAVE_GL();
6686 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6688 WINED3DVIEWPORT viewport;
6690 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6692 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6693 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6694 This, RenderTargetIndex, GL_LIMITS(buffers));
6695 return WINED3DERR_INVALIDCALL;
6698 /* MSDN says that null disables the render target
6699 but a device must always be associated with a render target
6700 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6702 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6703 FIXME("Trying to set render target 0 to NULL\n");
6704 return WINED3DERR_INVALIDCALL;
6706 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6707 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);
6708 return WINED3DERR_INVALIDCALL;
6711 /* If we are trying to set what we already have, don't bother */
6712 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6713 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6714 return WINED3D_OK;
6716 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6717 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6718 This->render_targets[RenderTargetIndex] = pRenderTarget;
6720 /* Render target 0 is special */
6721 if(RenderTargetIndex == 0) {
6722 /* Finally, reset the viewport as the MSDN states. */
6723 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6724 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6725 viewport.X = 0;
6726 viewport.Y = 0;
6727 viewport.MaxZ = 1.0f;
6728 viewport.MinZ = 0.0f;
6729 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6730 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6731 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6733 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6735 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6736 * ctx properly.
6737 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6738 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6740 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6742 return WINED3D_OK;
6745 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6747 HRESULT hr = WINED3D_OK;
6748 IWineD3DSurface *tmp;
6750 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6752 if (pNewZStencil == This->stencilBufferTarget) {
6753 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6754 } else {
6755 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6756 * depending on the renter target implementation being used.
6757 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6758 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6759 * stencil buffer and incur an extra memory overhead
6760 ******************************************************/
6762 tmp = This->stencilBufferTarget;
6763 This->stencilBufferTarget = pNewZStencil;
6764 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6765 /* should we be calling the parent or the wined3d surface? */
6766 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6767 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6768 hr = WINED3D_OK;
6770 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6771 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6772 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6773 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6774 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6778 return hr;
6781 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6782 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6784 /* TODO: the use of Impl is deprecated. */
6785 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6786 WINED3DLOCKED_RECT lockedRect;
6788 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6790 /* some basic validation checks */
6791 if(This->cursorTexture) {
6792 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6793 ENTER_GL();
6794 glDeleteTextures(1, &This->cursorTexture);
6795 LEAVE_GL();
6796 This->cursorTexture = 0;
6799 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6800 This->haveHardwareCursor = TRUE;
6801 else
6802 This->haveHardwareCursor = FALSE;
6804 if(pCursorBitmap) {
6805 WINED3DLOCKED_RECT rect;
6807 /* MSDN: Cursor must be A8R8G8B8 */
6808 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6809 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6810 return WINED3DERR_INVALIDCALL;
6813 /* MSDN: Cursor must be smaller than the display mode */
6814 if(pSur->currentDesc.Width > This->ddraw_width ||
6815 pSur->currentDesc.Height > This->ddraw_height) {
6816 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);
6817 return WINED3DERR_INVALIDCALL;
6820 if (!This->haveHardwareCursor) {
6821 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6823 /* Do not store the surface's pointer because the application may
6824 * release it after setting the cursor image. Windows doesn't
6825 * addref the set surface, so we can't do this either without
6826 * creating circular refcount dependencies. Copy out the gl texture
6827 * instead.
6829 This->cursorWidth = pSur->currentDesc.Width;
6830 This->cursorHeight = pSur->currentDesc.Height;
6831 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6833 const GlPixelFormatDesc *glDesc;
6834 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6835 char *mem, *bits = (char *)rect.pBits;
6836 GLint intfmt = glDesc->glInternal;
6837 GLint format = glDesc->glFormat;
6838 GLint type = glDesc->glType;
6839 INT height = This->cursorHeight;
6840 INT width = This->cursorWidth;
6841 INT bpp = tableEntry->bpp;
6842 INT i;
6844 /* Reformat the texture memory (pitch and width can be
6845 * different) */
6846 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6847 for(i = 0; i < height; i++)
6848 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6849 IWineD3DSurface_UnlockRect(pCursorBitmap);
6850 ENTER_GL();
6852 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6853 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6854 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6857 /* Make sure that a proper texture unit is selected */
6858 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6859 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6860 checkGLcall("glActiveTextureARB");
6862 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6863 /* Create a new cursor texture */
6864 glGenTextures(1, &This->cursorTexture);
6865 checkGLcall("glGenTextures");
6866 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6867 checkGLcall("glBindTexture");
6868 /* Copy the bitmap memory into the cursor texture */
6869 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6870 HeapFree(GetProcessHeap(), 0, mem);
6871 checkGLcall("glTexImage2D");
6873 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6874 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6875 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6878 LEAVE_GL();
6880 else
6882 FIXME("A cursor texture was not returned.\n");
6883 This->cursorTexture = 0;
6886 else
6888 /* Draw a hardware cursor */
6889 ICONINFO cursorInfo;
6890 HCURSOR cursor;
6891 /* Create and clear maskBits because it is not needed for
6892 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6893 * chunks. */
6894 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6895 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6896 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6897 WINED3DLOCK_NO_DIRTY_UPDATE |
6898 WINED3DLOCK_READONLY
6900 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6901 pSur->currentDesc.Height);
6903 cursorInfo.fIcon = FALSE;
6904 cursorInfo.xHotspot = XHotSpot;
6905 cursorInfo.yHotspot = YHotSpot;
6906 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6907 pSur->currentDesc.Height, 1,
6908 1, &maskBits);
6909 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6910 pSur->currentDesc.Height, 1,
6911 32, lockedRect.pBits);
6912 IWineD3DSurface_UnlockRect(pCursorBitmap);
6913 /* Create our cursor and clean up. */
6914 cursor = CreateIconIndirect(&cursorInfo);
6915 SetCursor(cursor);
6916 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6917 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6918 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6919 This->hardwareCursor = cursor;
6920 HeapFree(GetProcessHeap(), 0, maskBits);
6924 This->xHotSpot = XHotSpot;
6925 This->yHotSpot = YHotSpot;
6926 return WINED3D_OK;
6929 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6931 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6933 This->xScreenSpace = XScreenSpace;
6934 This->yScreenSpace = YScreenSpace;
6936 return;
6940 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6942 BOOL oldVisible = This->bCursorVisible;
6943 POINT pt;
6945 TRACE("(%p) : visible(%d)\n", This, bShow);
6948 * When ShowCursor is first called it should make the cursor appear at the OS's last
6949 * known cursor position. Because of this, some applications just repetitively call
6950 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6952 GetCursorPos(&pt);
6953 This->xScreenSpace = pt.x;
6954 This->yScreenSpace = pt.y;
6956 if (This->haveHardwareCursor) {
6957 This->bCursorVisible = bShow;
6958 if (bShow)
6959 SetCursor(This->hardwareCursor);
6960 else
6961 SetCursor(NULL);
6963 else
6965 if (This->cursorTexture)
6966 This->bCursorVisible = bShow;
6969 return oldVisible;
6972 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6974 IWineD3DResourceImpl *resource;
6975 TRACE("(%p) : state (%u)\n", This, This->state);
6977 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6978 switch (This->state) {
6979 case WINED3D_OK:
6980 return WINED3D_OK;
6981 case WINED3DERR_DEVICELOST:
6983 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6984 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6985 return WINED3DERR_DEVICENOTRESET;
6987 return WINED3DERR_DEVICELOST;
6989 case WINED3DERR_DRIVERINTERNALERROR:
6990 return WINED3DERR_DRIVERINTERNALERROR;
6993 /* Unknown state */
6994 return WINED3DERR_DRIVERINTERNALERROR;
6998 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7000 /** FIXME: Resource tracking needs to be done,
7001 * The closes we can do to this is set the priorities of all managed textures low
7002 * and then reset them.
7003 ***********************************************************/
7004 FIXME("(%p) : stub\n", This);
7005 return WINED3D_OK;
7008 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7009 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7011 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7012 if(surface->Flags & SFLAG_DIBSECTION) {
7013 /* Release the DC */
7014 SelectObject(surface->hDC, surface->dib.holdbitmap);
7015 DeleteDC(surface->hDC);
7016 /* Release the DIB section */
7017 DeleteObject(surface->dib.DIBsection);
7018 surface->dib.bitmap_data = NULL;
7019 surface->resource.allocatedMemory = NULL;
7020 surface->Flags &= ~SFLAG_DIBSECTION;
7022 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7023 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7024 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE)) {
7025 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7026 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7027 } else {
7028 surface->pow2Width = surface->pow2Height = 1;
7029 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7030 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7032 surface->glRect.left = 0;
7033 surface->glRect.top = 0;
7034 surface->glRect.right = surface->pow2Width;
7035 surface->glRect.bottom = surface->pow2Height;
7037 if(surface->glDescription.textureName) {
7038 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7039 ENTER_GL();
7040 glDeleteTextures(1, &surface->glDescription.textureName);
7041 LEAVE_GL();
7042 surface->glDescription.textureName = 0;
7043 surface->Flags &= ~SFLAG_CLIENT;
7045 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7046 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7047 surface->Flags |= SFLAG_NONPOW2;
7048 } else {
7049 surface->Flags &= ~SFLAG_NONPOW2;
7051 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7052 surface->resource.allocatedMemory = NULL;
7053 surface->resource.heapMemory = NULL;
7054 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7055 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7056 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7057 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7058 } else {
7059 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7063 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7064 TRACE("Unloading resource %p\n", resource);
7065 IWineD3DResource_UnLoad(resource);
7066 IWineD3DResource_Release(resource);
7067 return S_OK;
7070 static void reset_fbo_state(IWineD3DDevice *iface) {
7071 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7072 unsigned int i;
7074 ENTER_GL();
7075 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7076 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
7078 if (This->fbo) {
7079 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
7080 This->fbo = 0;
7082 if (This->src_fbo) {
7083 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
7084 This->src_fbo = 0;
7086 if (This->dst_fbo) {
7087 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
7088 This->dst_fbo = 0;
7090 checkGLcall("Tear down FBOs\n");
7091 LEAVE_GL();
7093 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7094 This->fbo_color_attachments[i] = NULL;
7096 This->fbo_depth_attachment = NULL;
7099 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7100 UINT i, count;
7101 WINED3DDISPLAYMODE m;
7102 HRESULT hr;
7104 /* All Windowed modes are supported, as is leaving the current mode */
7105 if(pp->Windowed) return TRUE;
7106 if(!pp->BackBufferWidth) return TRUE;
7107 if(!pp->BackBufferHeight) return TRUE;
7109 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7110 for(i = 0; i < count; i++) {
7111 memset(&m, 0, sizeof(m));
7112 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7113 if(FAILED(hr)) {
7114 ERR("EnumAdapterModes failed\n");
7116 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7117 /* Mode found, it is supported */
7118 return TRUE;
7121 /* Mode not found -> not supported */
7122 return FALSE;
7125 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7127 IWineD3DSwapChainImpl *swapchain;
7128 HRESULT hr;
7129 BOOL DisplayModeChanged = FALSE;
7130 WINED3DDISPLAYMODE mode;
7131 IWineD3DBaseShaderImpl *shader;
7132 IWineD3DSurfaceImpl *target;
7133 UINT i;
7134 TRACE("(%p)\n", This);
7136 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7137 if(FAILED(hr)) {
7138 ERR("Failed to get the first implicit swapchain\n");
7139 return hr;
7142 if(!is_display_mode_supported(This, pPresentationParameters)) {
7143 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7144 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7145 pPresentationParameters->BackBufferHeight);
7146 return WINED3DERR_INVALIDCALL;
7149 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7150 * on an existing gl context, so there's no real need for recreation.
7152 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7154 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7156 TRACE("New params:\n");
7157 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7158 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7159 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7160 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7161 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7162 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7163 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7164 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7165 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7166 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7167 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7168 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7169 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7171 /* No special treatment of these parameters. Just store them */
7172 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7173 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7174 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7175 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7177 /* What to do about these? */
7178 if(pPresentationParameters->BackBufferCount != 0 &&
7179 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7180 ERR("Cannot change the back buffer count yet\n");
7182 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7183 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7184 ERR("Cannot change the back buffer format yet\n");
7186 if(pPresentationParameters->hDeviceWindow != NULL &&
7187 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7188 ERR("Cannot change the device window yet\n");
7190 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7191 ERR("What do do about a changed auto depth stencil parameter?\n");
7194 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7195 reset_fbo_state((IWineD3DDevice *) This);
7198 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7199 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7200 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7203 ENTER_GL();
7204 if(This->depth_blt_texture) {
7205 glDeleteTextures(1, &This->depth_blt_texture);
7206 This->depth_blt_texture = 0;
7208 This->shader_backend->shader_destroy_depth_blt(iface);
7209 This->shader_backend->shader_free_private(iface);
7211 for (i = 0; i < GL_LIMITS(textures); i++) {
7212 /* Textures are recreated below */
7213 glDeleteTextures(1, &This->dummyTextureName[i]);
7214 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7215 This->dummyTextureName[i] = 0;
7217 LEAVE_GL();
7219 while(This->numContexts) {
7220 DestroyContext(This, This->contexts[0]);
7222 This->activeContext = NULL;
7223 HeapFree(GetProcessHeap(), 0, swapchain->context);
7224 swapchain->context = NULL;
7225 swapchain->num_contexts = 0;
7227 if(pPresentationParameters->Windowed) {
7228 mode.Width = swapchain->orig_width;
7229 mode.Height = swapchain->orig_height;
7230 mode.RefreshRate = 0;
7231 mode.Format = swapchain->presentParms.BackBufferFormat;
7232 } else {
7233 mode.Width = pPresentationParameters->BackBufferWidth;
7234 mode.Height = pPresentationParameters->BackBufferHeight;
7235 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7236 mode.Format = swapchain->presentParms.BackBufferFormat;
7239 /* Should Width == 800 && Height == 0 set 800x600? */
7240 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7241 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7242 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7244 WINED3DVIEWPORT vp;
7245 int i;
7247 vp.X = 0;
7248 vp.Y = 0;
7249 vp.Width = pPresentationParameters->BackBufferWidth;
7250 vp.Height = pPresentationParameters->BackBufferHeight;
7251 vp.MinZ = 0;
7252 vp.MaxZ = 1;
7254 if(!pPresentationParameters->Windowed) {
7255 DisplayModeChanged = TRUE;
7257 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7258 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7260 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7261 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7262 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7264 if(This->auto_depth_stencil_buffer) {
7265 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7269 /* Now set the new viewport */
7270 IWineD3DDevice_SetViewport(iface, &vp);
7273 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7274 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7275 DisplayModeChanged) {
7277 IWineD3DDevice_SetFullscreen(iface, !pPresentationParameters->Windowed);
7278 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7279 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7280 } else if(!pPresentationParameters->Windowed) {
7281 DWORD style = This->style, exStyle = This->exStyle;
7282 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7283 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7284 * Reset to clear up their mess. Guild Wars also loses the device during that.
7286 This->style = 0;
7287 This->exStyle = 0;
7288 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
7289 This->style = style;
7290 This->exStyle = exStyle;
7293 /* Recreate the primary swapchain's context */
7294 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7295 if(swapchain->backBuffer) {
7296 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7297 } else {
7298 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7300 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7301 &swapchain->presentParms);
7302 swapchain->num_contexts = 1;
7303 This->activeContext = swapchain->context[0];
7304 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7306 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7307 if(FAILED(hr)) {
7308 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7310 create_dummy_textures(This);
7313 hr = This->shader_backend->shader_alloc_private(iface);
7314 if(FAILED(hr)) {
7315 ERR("Failed to recreate shader private data\n");
7316 return hr;
7319 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7320 * first use
7322 return WINED3D_OK;
7325 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7327 /** FIXME: always true at the moment **/
7328 if(!bEnableDialogs) {
7329 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7331 return WINED3D_OK;
7335 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7337 TRACE("(%p) : pParameters %p\n", This, pParameters);
7339 *pParameters = This->createParms;
7340 return WINED3D_OK;
7343 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7344 IWineD3DSwapChain *swapchain;
7346 TRACE("Relaying to swapchain\n");
7348 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7349 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7350 IWineD3DSwapChain_Release(swapchain);
7352 return;
7355 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7356 IWineD3DSwapChain *swapchain;
7358 TRACE("Relaying to swapchain\n");
7360 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7361 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7362 IWineD3DSwapChain_Release(swapchain);
7364 return;
7368 /** ********************************************************
7369 * Notification functions
7370 ** ********************************************************/
7371 /** This function must be called in the release of a resource when ref == 0,
7372 * the contents of resource must still be correct,
7373 * any handles to other resource held by the caller must be closed
7374 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7375 *****************************************************/
7376 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7379 TRACE("(%p) : Adding Resource %p\n", This, resource);
7380 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7383 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7386 TRACE("(%p) : Removing resource %p\n", This, resource);
7388 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7392 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7394 int counter;
7396 TRACE("(%p) : resource %p\n", This, resource);
7397 switch(IWineD3DResource_GetType(resource)){
7398 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7399 case WINED3DRTYPE_SURFACE: {
7400 unsigned int i;
7402 /* Cleanup any FBO attachments if d3d is enabled */
7403 if(This->d3d_initialized) {
7404 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7405 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7407 TRACE("Last active render target destroyed\n");
7408 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7409 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7410 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7411 * and the lastActiveRenderTarget member shouldn't matter
7413 if(swapchain) {
7414 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7415 TRACE("Activating primary back buffer\n");
7416 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7417 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7418 /* Single buffering environment */
7419 TRACE("Activating primary front buffer\n");
7420 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7421 } else {
7422 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7423 /* Implicit render target destroyed, that means the device is being destroyed
7424 * whatever we set here, it shouldn't matter
7426 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7428 } else {
7429 /* May happen during ddraw uninitialization */
7430 TRACE("Render target set, but swapchain does not exist!\n");
7431 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7435 ENTER_GL();
7436 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7437 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7438 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7439 set_render_target_fbo(iface, i, NULL);
7440 This->fbo_color_attachments[i] = NULL;
7443 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7444 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7445 set_depth_stencil_fbo(iface, NULL);
7446 This->fbo_depth_attachment = NULL;
7448 LEAVE_GL();
7451 break;
7453 case WINED3DRTYPE_TEXTURE:
7454 case WINED3DRTYPE_CUBETEXTURE:
7455 case WINED3DRTYPE_VOLUMETEXTURE:
7456 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7457 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7458 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7459 This->stateBlock->textures[counter] = NULL;
7461 if (This->updateStateBlock != This->stateBlock ){
7462 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7463 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7464 This->updateStateBlock->textures[counter] = NULL;
7468 break;
7469 case WINED3DRTYPE_VOLUME:
7470 /* TODO: nothing really? */
7471 break;
7472 case WINED3DRTYPE_VERTEXBUFFER:
7473 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7475 int streamNumber;
7476 TRACE("Cleaning up stream pointers\n");
7478 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7479 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7480 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7482 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7483 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7484 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7485 This->updateStateBlock->streamSource[streamNumber] = 0;
7486 /* Set changed flag? */
7489 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) */
7490 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7491 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7492 This->stateBlock->streamSource[streamNumber] = 0;
7495 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7496 else { /* This shouldn't happen */
7497 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7499 #endif
7503 break;
7504 case WINED3DRTYPE_INDEXBUFFER:
7505 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7506 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7507 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7508 This->updateStateBlock->pIndexData = NULL;
7511 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7512 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7513 This->stateBlock->pIndexData = NULL;
7517 break;
7518 default:
7519 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7520 break;
7524 /* Remove the resource from the resourceStore */
7525 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7527 TRACE("Resource released\n");
7531 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7533 IWineD3DResourceImpl *resource, *cursor;
7534 HRESULT ret;
7535 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7537 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7538 TRACE("enumerating resource %p\n", resource);
7539 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7540 ret = pCallback((IWineD3DResource *) resource, pData);
7541 if(ret == S_FALSE) {
7542 TRACE("Canceling enumeration\n");
7543 break;
7546 return WINED3D_OK;
7549 /**********************************************************
7550 * IWineD3DDevice VTbl follows
7551 **********************************************************/
7553 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7555 /*** IUnknown methods ***/
7556 IWineD3DDeviceImpl_QueryInterface,
7557 IWineD3DDeviceImpl_AddRef,
7558 IWineD3DDeviceImpl_Release,
7559 /*** IWineD3DDevice methods ***/
7560 IWineD3DDeviceImpl_GetParent,
7561 /*** Creation methods**/
7562 IWineD3DDeviceImpl_CreateVertexBuffer,
7563 IWineD3DDeviceImpl_CreateIndexBuffer,
7564 IWineD3DDeviceImpl_CreateStateBlock,
7565 IWineD3DDeviceImpl_CreateSurface,
7566 IWineD3DDeviceImpl_CreateTexture,
7567 IWineD3DDeviceImpl_CreateVolumeTexture,
7568 IWineD3DDeviceImpl_CreateVolume,
7569 IWineD3DDeviceImpl_CreateCubeTexture,
7570 IWineD3DDeviceImpl_CreateQuery,
7571 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7572 IWineD3DDeviceImpl_CreateVertexDeclaration,
7573 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7574 IWineD3DDeviceImpl_CreateVertexShader,
7575 IWineD3DDeviceImpl_CreatePixelShader,
7576 IWineD3DDeviceImpl_CreatePalette,
7577 /*** Odd functions **/
7578 IWineD3DDeviceImpl_Init3D,
7579 IWineD3DDeviceImpl_Uninit3D,
7580 IWineD3DDeviceImpl_SetFullscreen,
7581 IWineD3DDeviceImpl_SetMultithreaded,
7582 IWineD3DDeviceImpl_EvictManagedResources,
7583 IWineD3DDeviceImpl_GetAvailableTextureMem,
7584 IWineD3DDeviceImpl_GetBackBuffer,
7585 IWineD3DDeviceImpl_GetCreationParameters,
7586 IWineD3DDeviceImpl_GetDeviceCaps,
7587 IWineD3DDeviceImpl_GetDirect3D,
7588 IWineD3DDeviceImpl_GetDisplayMode,
7589 IWineD3DDeviceImpl_SetDisplayMode,
7590 IWineD3DDeviceImpl_GetHWND,
7591 IWineD3DDeviceImpl_SetHWND,
7592 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7593 IWineD3DDeviceImpl_GetRasterStatus,
7594 IWineD3DDeviceImpl_GetSwapChain,
7595 IWineD3DDeviceImpl_Reset,
7596 IWineD3DDeviceImpl_SetDialogBoxMode,
7597 IWineD3DDeviceImpl_SetCursorProperties,
7598 IWineD3DDeviceImpl_SetCursorPosition,
7599 IWineD3DDeviceImpl_ShowCursor,
7600 IWineD3DDeviceImpl_TestCooperativeLevel,
7601 /*** Getters and setters **/
7602 IWineD3DDeviceImpl_SetClipPlane,
7603 IWineD3DDeviceImpl_GetClipPlane,
7604 IWineD3DDeviceImpl_SetClipStatus,
7605 IWineD3DDeviceImpl_GetClipStatus,
7606 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7607 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7608 IWineD3DDeviceImpl_SetDepthStencilSurface,
7609 IWineD3DDeviceImpl_GetDepthStencilSurface,
7610 IWineD3DDeviceImpl_SetFVF,
7611 IWineD3DDeviceImpl_GetFVF,
7612 IWineD3DDeviceImpl_SetGammaRamp,
7613 IWineD3DDeviceImpl_GetGammaRamp,
7614 IWineD3DDeviceImpl_SetIndices,
7615 IWineD3DDeviceImpl_GetIndices,
7616 IWineD3DDeviceImpl_SetBaseVertexIndex,
7617 IWineD3DDeviceImpl_GetBaseVertexIndex,
7618 IWineD3DDeviceImpl_SetLight,
7619 IWineD3DDeviceImpl_GetLight,
7620 IWineD3DDeviceImpl_SetLightEnable,
7621 IWineD3DDeviceImpl_GetLightEnable,
7622 IWineD3DDeviceImpl_SetMaterial,
7623 IWineD3DDeviceImpl_GetMaterial,
7624 IWineD3DDeviceImpl_SetNPatchMode,
7625 IWineD3DDeviceImpl_GetNPatchMode,
7626 IWineD3DDeviceImpl_SetPaletteEntries,
7627 IWineD3DDeviceImpl_GetPaletteEntries,
7628 IWineD3DDeviceImpl_SetPixelShader,
7629 IWineD3DDeviceImpl_GetPixelShader,
7630 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7631 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7632 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7633 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7634 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7635 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7636 IWineD3DDeviceImpl_SetRenderState,
7637 IWineD3DDeviceImpl_GetRenderState,
7638 IWineD3DDeviceImpl_SetRenderTarget,
7639 IWineD3DDeviceImpl_GetRenderTarget,
7640 IWineD3DDeviceImpl_SetFrontBackBuffers,
7641 IWineD3DDeviceImpl_SetSamplerState,
7642 IWineD3DDeviceImpl_GetSamplerState,
7643 IWineD3DDeviceImpl_SetScissorRect,
7644 IWineD3DDeviceImpl_GetScissorRect,
7645 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7646 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7647 IWineD3DDeviceImpl_SetStreamSource,
7648 IWineD3DDeviceImpl_GetStreamSource,
7649 IWineD3DDeviceImpl_SetStreamSourceFreq,
7650 IWineD3DDeviceImpl_GetStreamSourceFreq,
7651 IWineD3DDeviceImpl_SetTexture,
7652 IWineD3DDeviceImpl_GetTexture,
7653 IWineD3DDeviceImpl_SetTextureStageState,
7654 IWineD3DDeviceImpl_GetTextureStageState,
7655 IWineD3DDeviceImpl_SetTransform,
7656 IWineD3DDeviceImpl_GetTransform,
7657 IWineD3DDeviceImpl_SetVertexDeclaration,
7658 IWineD3DDeviceImpl_GetVertexDeclaration,
7659 IWineD3DDeviceImpl_SetVertexShader,
7660 IWineD3DDeviceImpl_GetVertexShader,
7661 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7662 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7663 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7664 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7665 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7666 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7667 IWineD3DDeviceImpl_SetViewport,
7668 IWineD3DDeviceImpl_GetViewport,
7669 IWineD3DDeviceImpl_MultiplyTransform,
7670 IWineD3DDeviceImpl_ValidateDevice,
7671 IWineD3DDeviceImpl_ProcessVertices,
7672 /*** State block ***/
7673 IWineD3DDeviceImpl_BeginStateBlock,
7674 IWineD3DDeviceImpl_EndStateBlock,
7675 /*** Scene management ***/
7676 IWineD3DDeviceImpl_BeginScene,
7677 IWineD3DDeviceImpl_EndScene,
7678 IWineD3DDeviceImpl_Present,
7679 IWineD3DDeviceImpl_Clear,
7680 /*** Drawing ***/
7681 IWineD3DDeviceImpl_DrawPrimitive,
7682 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7683 IWineD3DDeviceImpl_DrawPrimitiveUP,
7684 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7685 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7686 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7687 IWineD3DDeviceImpl_DrawRectPatch,
7688 IWineD3DDeviceImpl_DrawTriPatch,
7689 IWineD3DDeviceImpl_DeletePatch,
7690 IWineD3DDeviceImpl_ColorFill,
7691 IWineD3DDeviceImpl_UpdateTexture,
7692 IWineD3DDeviceImpl_UpdateSurface,
7693 IWineD3DDeviceImpl_GetFrontBufferData,
7694 /*** object tracking ***/
7695 IWineD3DDeviceImpl_ResourceReleased,
7696 IWineD3DDeviceImpl_EnumResources
7699 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7701 /*** IUnknown methods ***/
7702 IWineD3DDeviceImpl_QueryInterface,
7703 IWineD3DDeviceImpl_AddRef,
7704 IWineD3DDeviceImpl_Release,
7705 /*** IWineD3DDevice methods ***/
7706 IWineD3DDeviceImpl_GetParent,
7707 /*** Creation methods**/
7708 IWineD3DDeviceImpl_CreateVertexBuffer,
7709 IWineD3DDeviceImpl_CreateIndexBuffer,
7710 IWineD3DDeviceImpl_CreateStateBlock,
7711 IWineD3DDeviceImpl_CreateSurface,
7712 IWineD3DDeviceImpl_CreateTexture,
7713 IWineD3DDeviceImpl_CreateVolumeTexture,
7714 IWineD3DDeviceImpl_CreateVolume,
7715 IWineD3DDeviceImpl_CreateCubeTexture,
7716 IWineD3DDeviceImpl_CreateQuery,
7717 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7718 IWineD3DDeviceImpl_CreateVertexDeclaration,
7719 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7720 IWineD3DDeviceImpl_CreateVertexShader,
7721 IWineD3DDeviceImpl_CreatePixelShader,
7722 IWineD3DDeviceImpl_CreatePalette,
7723 /*** Odd functions **/
7724 IWineD3DDeviceImpl_Init3D,
7725 IWineD3DDeviceImpl_Uninit3D,
7726 IWineD3DDeviceImpl_SetFullscreen,
7727 IWineD3DDeviceImpl_SetMultithreaded,
7728 IWineD3DDeviceImpl_EvictManagedResources,
7729 IWineD3DDeviceImpl_GetAvailableTextureMem,
7730 IWineD3DDeviceImpl_GetBackBuffer,
7731 IWineD3DDeviceImpl_GetCreationParameters,
7732 IWineD3DDeviceImpl_GetDeviceCaps,
7733 IWineD3DDeviceImpl_GetDirect3D,
7734 IWineD3DDeviceImpl_GetDisplayMode,
7735 IWineD3DDeviceImpl_SetDisplayMode,
7736 IWineD3DDeviceImpl_GetHWND,
7737 IWineD3DDeviceImpl_SetHWND,
7738 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7739 IWineD3DDeviceImpl_GetRasterStatus,
7740 IWineD3DDeviceImpl_GetSwapChain,
7741 IWineD3DDeviceImpl_Reset,
7742 IWineD3DDeviceImpl_SetDialogBoxMode,
7743 IWineD3DDeviceImpl_SetCursorProperties,
7744 IWineD3DDeviceImpl_SetCursorPosition,
7745 IWineD3DDeviceImpl_ShowCursor,
7746 IWineD3DDeviceImpl_TestCooperativeLevel,
7747 /*** Getters and setters **/
7748 IWineD3DDeviceImpl_SetClipPlane,
7749 IWineD3DDeviceImpl_GetClipPlane,
7750 IWineD3DDeviceImpl_SetClipStatus,
7751 IWineD3DDeviceImpl_GetClipStatus,
7752 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7753 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7754 IWineD3DDeviceImpl_SetDepthStencilSurface,
7755 IWineD3DDeviceImpl_GetDepthStencilSurface,
7756 IWineD3DDeviceImpl_SetFVF,
7757 IWineD3DDeviceImpl_GetFVF,
7758 IWineD3DDeviceImpl_SetGammaRamp,
7759 IWineD3DDeviceImpl_GetGammaRamp,
7760 IWineD3DDeviceImpl_SetIndices,
7761 IWineD3DDeviceImpl_GetIndices,
7762 IWineD3DDeviceImpl_SetBaseVertexIndex,
7763 IWineD3DDeviceImpl_GetBaseVertexIndex,
7764 IWineD3DDeviceImpl_SetLight,
7765 IWineD3DDeviceImpl_GetLight,
7766 IWineD3DDeviceImpl_SetLightEnable,
7767 IWineD3DDeviceImpl_GetLightEnable,
7768 IWineD3DDeviceImpl_SetMaterial,
7769 IWineD3DDeviceImpl_GetMaterial,
7770 IWineD3DDeviceImpl_SetNPatchMode,
7771 IWineD3DDeviceImpl_GetNPatchMode,
7772 IWineD3DDeviceImpl_SetPaletteEntries,
7773 IWineD3DDeviceImpl_GetPaletteEntries,
7774 IWineD3DDeviceImpl_SetPixelShader,
7775 IWineD3DDeviceImpl_GetPixelShader,
7776 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7777 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7778 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7779 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7780 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7781 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7782 IWineD3DDeviceImpl_SetRenderState,
7783 IWineD3DDeviceImpl_GetRenderState,
7784 IWineD3DDeviceImpl_SetRenderTarget,
7785 IWineD3DDeviceImpl_GetRenderTarget,
7786 IWineD3DDeviceImpl_SetFrontBackBuffers,
7787 IWineD3DDeviceImpl_SetSamplerState,
7788 IWineD3DDeviceImpl_GetSamplerState,
7789 IWineD3DDeviceImpl_SetScissorRect,
7790 IWineD3DDeviceImpl_GetScissorRect,
7791 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7792 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7793 IWineD3DDeviceImpl_SetStreamSource,
7794 IWineD3DDeviceImpl_GetStreamSource,
7795 IWineD3DDeviceImpl_SetStreamSourceFreq,
7796 IWineD3DDeviceImpl_GetStreamSourceFreq,
7797 IWineD3DDeviceImpl_SetTexture,
7798 IWineD3DDeviceImpl_GetTexture,
7799 IWineD3DDeviceImpl_SetTextureStageState,
7800 IWineD3DDeviceImpl_GetTextureStageState,
7801 IWineD3DDeviceImpl_SetTransform,
7802 IWineD3DDeviceImpl_GetTransform,
7803 IWineD3DDeviceImpl_SetVertexDeclaration,
7804 IWineD3DDeviceImpl_GetVertexDeclaration,
7805 IWineD3DDeviceImpl_SetVertexShader,
7806 IWineD3DDeviceImpl_GetVertexShader,
7807 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7808 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7809 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7810 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7811 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7812 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7813 IWineD3DDeviceImpl_SetViewport,
7814 IWineD3DDeviceImpl_GetViewport,
7815 IWineD3DDeviceImpl_MultiplyTransform,
7816 IWineD3DDeviceImpl_ValidateDevice,
7817 IWineD3DDeviceImpl_ProcessVertices,
7818 /*** State block ***/
7819 IWineD3DDeviceImpl_BeginStateBlock,
7820 IWineD3DDeviceImpl_EndStateBlock,
7821 /*** Scene management ***/
7822 IWineD3DDeviceImpl_BeginScene,
7823 IWineD3DDeviceImpl_EndScene,
7824 IWineD3DDeviceImpl_Present,
7825 IWineD3DDeviceImpl_Clear,
7826 /*** Drawing ***/
7827 IWineD3DDeviceImpl_DrawPrimitive,
7828 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7829 IWineD3DDeviceImpl_DrawPrimitiveUP,
7830 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7831 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7832 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7833 IWineD3DDeviceImpl_DrawRectPatch,
7834 IWineD3DDeviceImpl_DrawTriPatch,
7835 IWineD3DDeviceImpl_DeletePatch,
7836 IWineD3DDeviceImpl_ColorFill,
7837 IWineD3DDeviceImpl_UpdateTexture,
7838 IWineD3DDeviceImpl_UpdateSurface,
7839 IWineD3DDeviceImpl_GetFrontBufferData,
7840 /*** object tracking ***/
7841 IWineD3DDeviceImpl_ResourceReleased,
7842 IWineD3DDeviceImpl_EnumResources
7845 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7846 WINED3DRS_ALPHABLENDENABLE ,
7847 WINED3DRS_ALPHAFUNC ,
7848 WINED3DRS_ALPHAREF ,
7849 WINED3DRS_ALPHATESTENABLE ,
7850 WINED3DRS_BLENDOP ,
7851 WINED3DRS_COLORWRITEENABLE ,
7852 WINED3DRS_DESTBLEND ,
7853 WINED3DRS_DITHERENABLE ,
7854 WINED3DRS_FILLMODE ,
7855 WINED3DRS_FOGDENSITY ,
7856 WINED3DRS_FOGEND ,
7857 WINED3DRS_FOGSTART ,
7858 WINED3DRS_LASTPIXEL ,
7859 WINED3DRS_SHADEMODE ,
7860 WINED3DRS_SRCBLEND ,
7861 WINED3DRS_STENCILENABLE ,
7862 WINED3DRS_STENCILFAIL ,
7863 WINED3DRS_STENCILFUNC ,
7864 WINED3DRS_STENCILMASK ,
7865 WINED3DRS_STENCILPASS ,
7866 WINED3DRS_STENCILREF ,
7867 WINED3DRS_STENCILWRITEMASK ,
7868 WINED3DRS_STENCILZFAIL ,
7869 WINED3DRS_TEXTUREFACTOR ,
7870 WINED3DRS_WRAP0 ,
7871 WINED3DRS_WRAP1 ,
7872 WINED3DRS_WRAP2 ,
7873 WINED3DRS_WRAP3 ,
7874 WINED3DRS_WRAP4 ,
7875 WINED3DRS_WRAP5 ,
7876 WINED3DRS_WRAP6 ,
7877 WINED3DRS_WRAP7 ,
7878 WINED3DRS_ZENABLE ,
7879 WINED3DRS_ZFUNC ,
7880 WINED3DRS_ZWRITEENABLE
7883 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7884 WINED3DTSS_ADDRESSW ,
7885 WINED3DTSS_ALPHAARG0 ,
7886 WINED3DTSS_ALPHAARG1 ,
7887 WINED3DTSS_ALPHAARG2 ,
7888 WINED3DTSS_ALPHAOP ,
7889 WINED3DTSS_BUMPENVLOFFSET ,
7890 WINED3DTSS_BUMPENVLSCALE ,
7891 WINED3DTSS_BUMPENVMAT00 ,
7892 WINED3DTSS_BUMPENVMAT01 ,
7893 WINED3DTSS_BUMPENVMAT10 ,
7894 WINED3DTSS_BUMPENVMAT11 ,
7895 WINED3DTSS_COLORARG0 ,
7896 WINED3DTSS_COLORARG1 ,
7897 WINED3DTSS_COLORARG2 ,
7898 WINED3DTSS_COLOROP ,
7899 WINED3DTSS_RESULTARG ,
7900 WINED3DTSS_TEXCOORDINDEX ,
7901 WINED3DTSS_TEXTURETRANSFORMFLAGS
7904 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7905 WINED3DSAMP_ADDRESSU ,
7906 WINED3DSAMP_ADDRESSV ,
7907 WINED3DSAMP_ADDRESSW ,
7908 WINED3DSAMP_BORDERCOLOR ,
7909 WINED3DSAMP_MAGFILTER ,
7910 WINED3DSAMP_MINFILTER ,
7911 WINED3DSAMP_MIPFILTER ,
7912 WINED3DSAMP_MIPMAPLODBIAS ,
7913 WINED3DSAMP_MAXMIPLEVEL ,
7914 WINED3DSAMP_MAXANISOTROPY ,
7915 WINED3DSAMP_SRGBTEXTURE ,
7916 WINED3DSAMP_ELEMENTINDEX
7919 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7920 WINED3DRS_AMBIENT ,
7921 WINED3DRS_AMBIENTMATERIALSOURCE ,
7922 WINED3DRS_CLIPPING ,
7923 WINED3DRS_CLIPPLANEENABLE ,
7924 WINED3DRS_COLORVERTEX ,
7925 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7926 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7927 WINED3DRS_FOGDENSITY ,
7928 WINED3DRS_FOGEND ,
7929 WINED3DRS_FOGSTART ,
7930 WINED3DRS_FOGTABLEMODE ,
7931 WINED3DRS_FOGVERTEXMODE ,
7932 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7933 WINED3DRS_LIGHTING ,
7934 WINED3DRS_LOCALVIEWER ,
7935 WINED3DRS_MULTISAMPLEANTIALIAS ,
7936 WINED3DRS_MULTISAMPLEMASK ,
7937 WINED3DRS_NORMALIZENORMALS ,
7938 WINED3DRS_PATCHEDGESTYLE ,
7939 WINED3DRS_POINTSCALE_A ,
7940 WINED3DRS_POINTSCALE_B ,
7941 WINED3DRS_POINTSCALE_C ,
7942 WINED3DRS_POINTSCALEENABLE ,
7943 WINED3DRS_POINTSIZE ,
7944 WINED3DRS_POINTSIZE_MAX ,
7945 WINED3DRS_POINTSIZE_MIN ,
7946 WINED3DRS_POINTSPRITEENABLE ,
7947 WINED3DRS_RANGEFOGENABLE ,
7948 WINED3DRS_SPECULARMATERIALSOURCE ,
7949 WINED3DRS_TWEENFACTOR ,
7950 WINED3DRS_VERTEXBLEND ,
7951 WINED3DRS_CULLMODE ,
7952 WINED3DRS_FOGCOLOR
7955 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7956 WINED3DTSS_TEXCOORDINDEX ,
7957 WINED3DTSS_TEXTURETRANSFORMFLAGS
7960 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7961 WINED3DSAMP_DMAPOFFSET
7964 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7965 DWORD rep = This->shader_backend->StateTable[state].representative;
7966 DWORD idx;
7967 BYTE shift;
7968 UINT i;
7969 WineD3DContext *context;
7971 if(!rep) return;
7972 for(i = 0; i < This->numContexts; i++) {
7973 context = This->contexts[i];
7974 if(isStateDirty(context, rep)) continue;
7976 context->dirtyArray[context->numDirtyEntries++] = rep;
7977 idx = rep >> 5;
7978 shift = rep & 0x1f;
7979 context->isStateDirty[idx] |= (1 << shift);
7983 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7984 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7985 /* The drawable size of a pbuffer render target is the current pbuffer size
7987 *width = dev->pbufferWidth;
7988 *height = dev->pbufferHeight;
7991 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7992 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7994 *width = This->pow2Width;
7995 *height = This->pow2Height;
7998 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7999 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8000 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8001 * current context's drawable, which is the size of the back buffer of the swapchain
8002 * the active context belongs to. The back buffer of the swapchain is stored as the
8003 * surface the context belongs to.
8005 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8006 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;