wined3d: Fix the drawStridedSlow callback function calling convention.
[wine.git] / dlls / wined3d / device.c
blob350c6d5e56025ec402887050160b3c703ff20405
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /* helper macros */
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
66 object->ref = 1; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
99 *pp##type = NULL; \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 WineD3DAdapterChangeGLRam(This, _size); \
104 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
105 if (object->resource.heapMemory == NULL && _size != 0) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
108 *pp##type = NULL; \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
112 *pp##type = (IWineD3D##type *) object; \
113 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
114 TRACE("(%p) : Created resource %p\n", This, object); \
117 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
118 _basetexture.levels = Levels; \
119 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
120 _basetexture.LOD = 0; \
121 _basetexture.dirty = TRUE; \
122 _basetexture.is_srgb = FALSE; \
123 _basetexture.srgb_mode_change_count = 0; \
126 /**********************************************************
127 * Global variable / Constants follow
128 **********************************************************/
129 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
139 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
140 if (IsEqualGUID(riid, &IID_IUnknown)
141 || IsEqualGUID(riid, &IID_IWineD3DBase)
142 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
143 IUnknown_AddRef(iface);
144 *ppobj = This;
145 return S_OK;
147 *ppobj = NULL;
148 return E_NOINTERFACE;
151 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 ULONG refCount = InterlockedIncrement(&This->ref);
155 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
156 return refCount;
159 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 ULONG refCount = InterlockedDecrement(&This->ref);
163 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
165 if (!refCount) {
166 /* TODO: Clean up all the surfaces and textures! */
167 /* NOTE: You must release the parent if the object was created via a callback
168 ** ***************************/
170 if (!list_empty(&This->resources)) {
171 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
172 dumpResources(&This->resources);
175 if(This->contexts) ERR("Context array not freed!\n");
176 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
177 This->haveHardwareCursor = FALSE;
179 IWineD3D_Release(This->wineD3D);
180 This->wineD3D = NULL;
181 HeapFree(GetProcessHeap(), 0, This);
182 TRACE("Freed device %p\n", This);
183 This = NULL;
185 return refCount;
188 /**********************************************************
189 * IWineD3DDevice implementation follows
190 **********************************************************/
191 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
193 *pParent = This->parent;
194 IUnknown_AddRef(This->parent);
195 return WINED3D_OK;
198 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
199 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
200 IUnknown *parent) {
201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
202 IWineD3DVertexBufferImpl *object;
203 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
204 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
205 BOOL conv;
207 if(Size == 0) {
208 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
209 *ppVertexBuffer = NULL;
210 return WINED3DERR_INVALIDCALL;
211 } else if(Pool == WINED3DPOOL_SCRATCH) {
212 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
213 * anyway, SCRATCH vertex buffers aren't usable anywhere
215 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
216 *ppVertexBuffer = NULL;
217 return WINED3DERR_INVALIDCALL;
220 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
222 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
223 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
225 object->fvf = FVF;
227 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
228 * drawStridedFast (half-life 2).
230 * Basically converting the vertices in the buffer is quite expensive, and observations
231 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
232 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
234 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
235 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
236 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
237 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
238 * dx7 apps.
239 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
240 * more. In this call we can convert dx7 buffers too.
242 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
243 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
244 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
245 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
246 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
247 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
248 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
249 } else if(dxVersion <= 7 && conv) {
250 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
251 } else {
252 object->Flags |= VBFLAG_CREATEVBO;
254 return WINED3D_OK;
257 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
258 GLenum error, glUsage;
259 TRACE("Creating VBO for Index Buffer %p\n", object);
261 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
262 * restored on the next draw
264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
266 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
267 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
268 ENTER_GL();
270 while(glGetError());
272 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
273 error = glGetError();
274 if(error != GL_NO_ERROR || object->vbo == 0) {
275 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
276 goto out;
279 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
280 error = glGetError();
281 if(error != GL_NO_ERROR) {
282 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
283 goto out;
286 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
287 * copy no readback will be needed
289 glUsage = GL_STATIC_DRAW_ARB;
290 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
291 error = glGetError();
292 if(error != GL_NO_ERROR) {
293 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
294 goto out;
296 LEAVE_GL();
297 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
298 return;
300 out:
301 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
302 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
303 LEAVE_GL();
304 object->vbo = 0;
307 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
308 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
309 HANDLE *sharedHandle, IUnknown *parent) {
310 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
311 IWineD3DIndexBufferImpl *object;
312 TRACE("(%p) Creating index buffer\n", This);
314 /* Allocate the storage for the device */
315 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
317 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
318 CreateIndexBufferVBO(This, object);
321 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
322 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
323 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
325 return WINED3D_OK;
328 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
331 IWineD3DStateBlockImpl *object;
332 int i, j;
333 HRESULT temp_result;
335 D3DCREATEOBJECTINSTANCE(object, StateBlock)
336 object->blockType = Type;
338 for(i = 0; i < LIGHTMAP_SIZE; i++) {
339 list_init(&object->lightMap[i]);
342 /* Special case - Used during initialization to produce a placeholder stateblock
343 so other functions called can update a state block */
344 if (Type == WINED3DSBT_INIT) {
345 /* Don't bother increasing the reference count otherwise a device will never
346 be freed due to circular dependencies */
347 return WINED3D_OK;
350 temp_result = allocate_shader_constants(object);
351 if (WINED3D_OK != temp_result)
352 return temp_result;
354 /* Otherwise, might as well set the whole state block to the appropriate values */
355 if (This->stateBlock != NULL)
356 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
357 else
358 memset(object->streamFreq, 1, sizeof(object->streamFreq));
360 /* Reset the ref and type after kludging it */
361 object->wineD3DDevice = This;
362 object->ref = 1;
363 object->blockType = Type;
365 TRACE("Updating changed flags appropriate for type %d\n", Type);
367 if (Type == WINED3DSBT_ALL) {
369 TRACE("ALL => Pretend everything has changed\n");
370 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
372 /* Lights are not part of the changed / set structure */
373 for(j = 0; j < LIGHTMAP_SIZE; j++) {
374 struct list *e;
375 LIST_FOR_EACH(e, &object->lightMap[j]) {
376 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
377 light->changed = TRUE;
378 light->enabledChanged = TRUE;
381 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
382 object->contained_render_states[j - 1] = j;
384 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
385 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
386 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
387 object->contained_transform_states[j - 1] = j;
389 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
390 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
391 object->contained_vs_consts_f[j] = j;
393 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
394 for(j = 0; j < MAX_CONST_I; j++) {
395 object->contained_vs_consts_i[j] = j;
397 object->num_contained_vs_consts_i = MAX_CONST_I;
398 for(j = 0; j < MAX_CONST_B; j++) {
399 object->contained_vs_consts_b[j] = j;
401 object->num_contained_vs_consts_b = MAX_CONST_B;
402 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
403 object->contained_ps_consts_f[j] = j;
405 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
406 for(j = 0; j < MAX_CONST_I; j++) {
407 object->contained_ps_consts_i[j] = j;
409 object->num_contained_ps_consts_i = MAX_CONST_I;
410 for(j = 0; j < MAX_CONST_B; j++) {
411 object->contained_ps_consts_b[j] = j;
413 object->num_contained_ps_consts_b = MAX_CONST_B;
414 for(i = 0; i < MAX_TEXTURES; i++) {
415 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
416 object->contained_tss_states[object->num_contained_tss_states].stage = i;
417 object->contained_tss_states[object->num_contained_tss_states].state = j;
418 object->num_contained_tss_states++;
421 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
422 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
423 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
424 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
425 object->num_contained_sampler_states++;
429 for(i = 0; i < MAX_STREAMS; i++) {
430 if(object->streamSource[i]) {
431 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
434 if(object->pIndexData) {
435 IWineD3DIndexBuffer_AddRef(object->pIndexData);
437 if(object->vertexShader) {
438 IWineD3DVertexShader_AddRef(object->vertexShader);
440 if(object->pixelShader) {
441 IWineD3DPixelShader_AddRef(object->pixelShader);
444 } else if (Type == WINED3DSBT_PIXELSTATE) {
446 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
447 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
449 object->changed.pixelShader = TRUE;
451 /* Pixel Shader Constants */
452 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
453 object->contained_ps_consts_f[i] = i;
454 object->changed.pixelShaderConstantsF[i] = TRUE;
456 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
457 for (i = 0; i < MAX_CONST_B; ++i) {
458 object->contained_ps_consts_b[i] = i;
459 object->changed.pixelShaderConstantsB[i] = TRUE;
461 object->num_contained_ps_consts_b = MAX_CONST_B;
462 for (i = 0; i < MAX_CONST_I; ++i) {
463 object->contained_ps_consts_i[i] = i;
464 object->changed.pixelShaderConstantsI[i] = TRUE;
466 object->num_contained_ps_consts_i = MAX_CONST_I;
468 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
469 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
470 object->contained_render_states[i] = SavedPixelStates_R[i];
472 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
473 for (j = 0; j < MAX_TEXTURES; j++) {
474 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
475 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
476 object->contained_tss_states[object->num_contained_tss_states].stage = j;
477 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
478 object->num_contained_tss_states++;
481 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
482 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
483 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
484 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
485 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
486 object->num_contained_sampler_states++;
489 if(object->pixelShader) {
490 IWineD3DPixelShader_AddRef(object->pixelShader);
493 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
494 * on them. This makes releasing the buffer easier
496 for(i = 0; i < MAX_STREAMS; i++) {
497 object->streamSource[i] = NULL;
499 object->pIndexData = NULL;
500 object->vertexShader = NULL;
502 } else if (Type == WINED3DSBT_VERTEXSTATE) {
504 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
505 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
507 object->changed.vertexShader = TRUE;
509 /* Vertex Shader Constants */
510 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
511 object->changed.vertexShaderConstantsF[i] = TRUE;
512 object->contained_vs_consts_f[i] = i;
514 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
515 for (i = 0; i < MAX_CONST_B; ++i) {
516 object->changed.vertexShaderConstantsB[i] = TRUE;
517 object->contained_vs_consts_b[i] = i;
519 object->num_contained_vs_consts_b = MAX_CONST_B;
520 for (i = 0; i < MAX_CONST_I; ++i) {
521 object->changed.vertexShaderConstantsI[i] = TRUE;
522 object->contained_vs_consts_i[i] = i;
524 object->num_contained_vs_consts_i = MAX_CONST_I;
525 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
526 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
527 object->contained_render_states[i] = SavedVertexStates_R[i];
529 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
530 for (j = 0; j < MAX_TEXTURES; j++) {
531 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
532 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
533 object->contained_tss_states[object->num_contained_tss_states].stage = j;
534 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
535 object->num_contained_tss_states++;
538 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
539 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
540 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
541 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
542 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
543 object->num_contained_sampler_states++;
547 for(j = 0; j < LIGHTMAP_SIZE; j++) {
548 struct list *e;
549 LIST_FOR_EACH(e, &object->lightMap[j]) {
550 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
551 light->changed = TRUE;
552 light->enabledChanged = TRUE;
556 for(i = 0; i < MAX_STREAMS; i++) {
557 if(object->streamSource[i]) {
558 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
561 if(object->vertexShader) {
562 IWineD3DVertexShader_AddRef(object->vertexShader);
564 object->pIndexData = NULL;
565 object->pixelShader = NULL;
566 } else {
567 FIXME("Unrecognized state block type %d\n", Type);
570 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
571 return WINED3D_OK;
574 /* ************************************
575 MSDN:
576 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
578 Discard
579 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
581 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
583 ******************************** */
585 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
587 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
588 unsigned int Size = 1;
589 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
590 TRACE("(%p) Create surface\n",This);
592 /** FIXME: Check ranges on the inputs are valid
593 * MSDN
594 * MultisampleQuality
595 * [in] Quality level. The valid range is between zero and one less than the level
596 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
597 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
598 * values of paired render targets, depth stencil surfaces, and the MultiSample type
599 * must all match.
600 *******************************/
604 * TODO: Discard MSDN
605 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
607 * If this flag is set, the contents of the depth stencil buffer will be
608 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
609 * with a different depth surface.
611 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
612 ***************************/
614 if(MultisampleQuality > 0) {
615 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
616 MultisampleQuality=0;
619 /** FIXME: Check that the format is supported
620 * by the device.
621 *******************************/
623 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
624 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
625 * space!
626 *********************************/
627 if (WINED3DFMT_UNKNOWN == Format) {
628 Size = 0;
629 } else if (Format == WINED3DFMT_DXT1) {
630 /* DXT1 is half byte per pixel */
631 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
633 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
634 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
635 Format == WINED3DFMT_ATI2N) {
636 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
637 } else {
638 /* The pitch is a multiple of 4 bytes */
639 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
640 Size *= Height;
643 /** Create and initialise the surface resource **/
644 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
645 /* "Standalone" surface */
646 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
648 object->currentDesc.Width = Width;
649 object->currentDesc.Height = Height;
650 object->currentDesc.MultiSampleType = MultiSample;
651 object->currentDesc.MultiSampleQuality = MultisampleQuality;
652 object->glDescription.level = Level;
653 list_init(&object->overlays);
655 /* Flags */
656 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
657 object->Flags |= Discard ? SFLAG_DISCARD : 0;
658 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
659 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
662 if (WINED3DFMT_UNKNOWN != Format) {
663 object->bytesPerPixel = tableEntry->bpp;
664 } else {
665 object->bytesPerPixel = 0;
668 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
670 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
672 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
673 * this function is too deep to need to care about things like this.
674 * Levels need to be checked too, and possibly Type since they all affect what can be done.
675 * ****************************************/
676 switch(Pool) {
677 case WINED3DPOOL_SCRATCH:
678 if(!Lockable)
679 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
680 "which are mutually exclusive, setting lockable to TRUE\n");
681 Lockable = TRUE;
682 break;
683 case WINED3DPOOL_SYSTEMMEM:
684 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
685 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
686 case WINED3DPOOL_MANAGED:
687 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
688 "Usage of DYNAMIC which are mutually exclusive, not doing "
689 "anything just telling you.\n");
690 break;
691 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
692 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
693 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
694 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
695 break;
696 default:
697 FIXME("(%p) Unknown pool %d\n", This, Pool);
698 break;
701 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
702 FIXME("Trying to create a render target that isn't in the default pool\n");
705 /* mark the texture as dirty so that it gets loaded first time around*/
706 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
707 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
708 This, Width, Height, Format, debug_d3dformat(Format),
709 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
711 /* Look at the implementation and set the correct Vtable */
712 switch(Impl) {
713 case SURFACE_OPENGL:
714 /* Check if a 3D adapter is available when creating gl surfaces */
715 if(!This->adapter) {
716 ERR("OpenGL surfaces are not available without opengl\n");
717 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
718 HeapFree(GetProcessHeap(), 0, object);
719 return WINED3DERR_NOTAVAILABLE;
721 break;
723 case SURFACE_GDI:
724 object->lpVtbl = &IWineGDISurface_Vtbl;
725 break;
727 default:
728 /* To be sure to catch this */
729 ERR("Unknown requested surface implementation %d!\n", Impl);
730 IWineD3DSurface_Release((IWineD3DSurface *) object);
731 return WINED3DERR_INVALIDCALL;
734 list_init(&object->renderbuffers);
736 /* Call the private setup routine */
737 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
741 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
742 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
743 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
744 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
747 IWineD3DTextureImpl *object;
748 unsigned int i;
749 UINT tmpW;
750 UINT tmpH;
751 HRESULT hr;
752 unsigned int pow2Width;
753 unsigned int pow2Height;
754 const GlPixelFormatDesc *glDesc;
755 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
757 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
758 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
759 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
761 /* TODO: It should only be possible to create textures for formats
762 that are reported as supported */
763 if (WINED3DFMT_UNKNOWN >= Format) {
764 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
765 return WINED3DERR_INVALIDCALL;
768 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
769 D3DINITIALIZEBASETEXTURE(object->baseTexture);
770 object->width = Width;
771 object->height = Height;
773 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
774 object->baseTexture.minMipLookup = &minMipLookup;
775 object->baseTexture.magLookup = &magLookup;
776 } else {
777 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
778 object->baseTexture.magLookup = &magLookup_noFilter;
781 /** Non-power2 support **/
782 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
783 pow2Width = Width;
784 pow2Height = Height;
785 } else {
786 /* Find the nearest pow2 match */
787 pow2Width = pow2Height = 1;
788 while (pow2Width < Width) pow2Width <<= 1;
789 while (pow2Height < Height) pow2Height <<= 1;
791 if(pow2Width != Width || pow2Height != Height) {
792 if(Levels > 1) {
793 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
794 HeapFree(GetProcessHeap(), 0, object);
795 *ppTexture = NULL;
796 return WINED3DERR_INVALIDCALL;
797 } else {
798 Levels = 1;
803 /** FIXME: add support for real non-power-two if it's provided by the video card **/
804 /* Precalculated scaling for 'faked' non power of two texture coords.
805 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
806 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
807 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
809 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
810 object->baseTexture.pow2Matrix[0] = 1.0;
811 object->baseTexture.pow2Matrix[5] = 1.0;
812 object->baseTexture.pow2Matrix[10] = 1.0;
813 object->baseTexture.pow2Matrix[15] = 1.0;
814 object->target = GL_TEXTURE_2D;
815 object->cond_np2 = TRUE;
816 pow2Width = Width;
817 pow2Height = Height;
818 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
819 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
820 (Width != pow2Width || Height != pow2Height) &&
821 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
823 object->baseTexture.pow2Matrix[0] = (float)Width;
824 object->baseTexture.pow2Matrix[5] = (float)Height;
825 object->baseTexture.pow2Matrix[10] = 1.0;
826 object->baseTexture.pow2Matrix[15] = 1.0;
827 object->target = GL_TEXTURE_RECTANGLE_ARB;
828 object->cond_np2 = TRUE;
829 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
830 } else {
831 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
832 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
833 object->baseTexture.pow2Matrix[10] = 1.0;
834 object->baseTexture.pow2Matrix[15] = 1.0;
835 object->target = GL_TEXTURE_2D;
836 object->cond_np2 = FALSE;
838 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
840 /* Calculate levels for mip mapping */
841 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
842 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
843 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
844 return WINED3DERR_INVALIDCALL;
846 if(Levels > 1) {
847 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
848 return WINED3DERR_INVALIDCALL;
850 object->baseTexture.levels = 1;
851 } else if (Levels == 0) {
852 TRACE("calculating levels %d\n", object->baseTexture.levels);
853 object->baseTexture.levels++;
854 tmpW = Width;
855 tmpH = Height;
856 while (tmpW > 1 || tmpH > 1) {
857 tmpW = max(1, tmpW >> 1);
858 tmpH = max(1, tmpH >> 1);
859 object->baseTexture.levels++;
861 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
864 /* Generate all the surfaces */
865 tmpW = Width;
866 tmpH = Height;
867 for (i = 0; i < object->baseTexture.levels; i++)
869 /* use the callback to create the texture surface */
870 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
871 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
872 FIXME("Failed to create surface %p\n", object);
873 /* clean up */
874 object->surfaces[i] = NULL;
875 IWineD3DTexture_Release((IWineD3DTexture *)object);
877 *ppTexture = NULL;
878 return hr;
881 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
882 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
883 /* calculate the next mipmap level */
884 tmpW = max(1, tmpW >> 1);
885 tmpH = max(1, tmpH >> 1);
887 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
889 TRACE("(%p) : Created texture %p\n", This, object);
890 return WINED3D_OK;
893 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
894 UINT Width, UINT Height, UINT Depth,
895 UINT Levels, DWORD Usage,
896 WINED3DFORMAT Format, WINED3DPOOL Pool,
897 IWineD3DVolumeTexture **ppVolumeTexture,
898 HANDLE *pSharedHandle, IUnknown *parent,
899 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
902 IWineD3DVolumeTextureImpl *object;
903 unsigned int i;
904 UINT tmpW;
905 UINT tmpH;
906 UINT tmpD;
907 const GlPixelFormatDesc *glDesc;
909 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
911 /* TODO: It should only be possible to create textures for formats
912 that are reported as supported */
913 if (WINED3DFMT_UNKNOWN >= Format) {
914 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
915 return WINED3DERR_INVALIDCALL;
917 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
918 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
919 return WINED3DERR_INVALIDCALL;
922 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
923 D3DINITIALIZEBASETEXTURE(object->baseTexture);
925 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
926 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
928 object->width = Width;
929 object->height = Height;
930 object->depth = Depth;
932 /* Is NP2 support for volumes needed? */
933 object->baseTexture.pow2Matrix[ 0] = 1.0;
934 object->baseTexture.pow2Matrix[ 5] = 1.0;
935 object->baseTexture.pow2Matrix[10] = 1.0;
936 object->baseTexture.pow2Matrix[15] = 1.0;
938 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
939 object->baseTexture.minMipLookup = &minMipLookup;
940 object->baseTexture.magLookup = &magLookup;
941 } else {
942 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
943 object->baseTexture.magLookup = &magLookup_noFilter;
946 /* Calculate levels for mip mapping */
947 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
948 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
949 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
950 return WINED3DERR_INVALIDCALL;
952 if(Levels > 1) {
953 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
954 return WINED3DERR_INVALIDCALL;
956 Levels = 1;
957 } else if (Levels == 0) {
958 object->baseTexture.levels++;
959 tmpW = Width;
960 tmpH = Height;
961 tmpD = Depth;
962 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
963 tmpW = max(1, tmpW >> 1);
964 tmpH = max(1, tmpH >> 1);
965 tmpD = max(1, tmpD >> 1);
966 object->baseTexture.levels++;
968 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
971 /* Generate all the surfaces */
972 tmpW = Width;
973 tmpH = Height;
974 tmpD = Depth;
976 for (i = 0; i < object->baseTexture.levels; i++)
978 HRESULT hr;
979 /* Create the volume */
980 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
981 &object->volumes[i], pSharedHandle);
983 if(FAILED(hr)) {
984 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
985 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
986 *ppVolumeTexture = NULL;
987 return hr;
990 /* Set its container to this object */
991 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
993 /* calculate the next mipmap level */
994 tmpW = max(1, tmpW >> 1);
995 tmpH = max(1, tmpH >> 1);
996 tmpD = max(1, tmpD >> 1);
998 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1000 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1001 TRACE("(%p) : Created volume texture %p\n", This, object);
1002 return WINED3D_OK;
1005 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1006 UINT Width, UINT Height, UINT Depth,
1007 DWORD Usage,
1008 WINED3DFORMAT Format, WINED3DPOOL Pool,
1009 IWineD3DVolume** ppVolume,
1010 HANDLE* pSharedHandle, IUnknown *parent) {
1012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1013 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1014 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1016 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1017 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1018 return WINED3DERR_INVALIDCALL;
1021 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1023 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1024 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1026 object->currentDesc.Width = Width;
1027 object->currentDesc.Height = Height;
1028 object->currentDesc.Depth = Depth;
1029 object->bytesPerPixel = formatDesc->bpp;
1031 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1032 object->lockable = TRUE;
1033 object->locked = FALSE;
1034 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1035 object->dirty = TRUE;
1037 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1040 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1041 UINT Levels, DWORD Usage,
1042 WINED3DFORMAT Format, WINED3DPOOL Pool,
1043 IWineD3DCubeTexture **ppCubeTexture,
1044 HANDLE *pSharedHandle, IUnknown *parent,
1045 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1048 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1049 unsigned int i, j;
1050 UINT tmpW;
1051 HRESULT hr;
1052 unsigned int pow2EdgeLength = EdgeLength;
1053 const GlPixelFormatDesc *glDesc;
1054 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1056 /* TODO: It should only be possible to create textures for formats
1057 that are reported as supported */
1058 if (WINED3DFMT_UNKNOWN >= Format) {
1059 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1060 return WINED3DERR_INVALIDCALL;
1063 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1064 WARN("(%p) : Tried to create not supported cube texture\n", This);
1065 return WINED3DERR_INVALIDCALL;
1068 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1069 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1071 TRACE("(%p) Create Cube Texture\n", This);
1073 /** Non-power2 support **/
1075 /* Find the nearest pow2 match */
1076 pow2EdgeLength = 1;
1077 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1079 object->edgeLength = EdgeLength;
1080 /* TODO: support for native non-power 2 */
1081 /* Precalculated scaling for 'faked' non power of two texture coords */
1082 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1083 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1084 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1085 object->baseTexture.pow2Matrix[15] = 1.0;
1087 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1088 object->baseTexture.minMipLookup = &minMipLookup;
1089 object->baseTexture.magLookup = &magLookup;
1090 } else {
1091 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
1092 object->baseTexture.magLookup = &magLookup_noFilter;
1095 /* Calculate levels for mip mapping */
1096 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1097 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1098 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1099 HeapFree(GetProcessHeap(), 0, object);
1100 *ppCubeTexture = NULL;
1102 return WINED3DERR_INVALIDCALL;
1104 if(Levels > 1) {
1105 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1106 HeapFree(GetProcessHeap(), 0, object);
1107 *ppCubeTexture = NULL;
1109 return WINED3DERR_INVALIDCALL;
1111 Levels = 1;
1112 } else if (Levels == 0) {
1113 object->baseTexture.levels++;
1114 tmpW = EdgeLength;
1115 while (tmpW > 1) {
1116 tmpW = max(1, tmpW >> 1);
1117 object->baseTexture.levels++;
1119 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1122 /* Generate all the surfaces */
1123 tmpW = EdgeLength;
1124 for (i = 0; i < object->baseTexture.levels; i++) {
1126 /* Create the 6 faces */
1127 for (j = 0; j < 6; j++) {
1129 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1130 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1132 if(hr!= WINED3D_OK) {
1133 /* clean up */
1134 int k;
1135 int l;
1136 for (l = 0; l < j; l++) {
1137 IWineD3DSurface_Release(object->surfaces[l][i]);
1139 for (k = 0; k < i; k++) {
1140 for (l = 0; l < 6; l++) {
1141 IWineD3DSurface_Release(object->surfaces[l][k]);
1145 FIXME("(%p) Failed to create surface\n",object);
1146 HeapFree(GetProcessHeap(),0,object);
1147 *ppCubeTexture = NULL;
1148 return hr;
1150 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1151 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1153 tmpW = max(1, tmpW >> 1);
1155 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1157 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1158 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1159 return WINED3D_OK;
1162 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1164 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1165 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1166 const IWineD3DQueryVtbl *vtable;
1168 /* Just a check to see if we support this type of query */
1169 switch(Type) {
1170 case WINED3DQUERYTYPE_OCCLUSION:
1171 TRACE("(%p) occlusion query\n", This);
1172 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1173 hr = WINED3D_OK;
1174 else
1175 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1177 vtable = &IWineD3DOcclusionQuery_Vtbl;
1178 break;
1180 case WINED3DQUERYTYPE_EVENT:
1181 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1182 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1183 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1185 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1187 vtable = &IWineD3DEventQuery_Vtbl;
1188 hr = WINED3D_OK;
1189 break;
1191 case WINED3DQUERYTYPE_VCACHE:
1192 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1193 case WINED3DQUERYTYPE_VERTEXSTATS:
1194 case WINED3DQUERYTYPE_TIMESTAMP:
1195 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1196 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1197 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1198 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1199 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1200 case WINED3DQUERYTYPE_PIXELTIMINGS:
1201 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1202 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1203 default:
1204 /* Use the base Query vtable until we have a special one for each query */
1205 vtable = &IWineD3DQuery_Vtbl;
1206 FIXME("(%p) Unhandled query type %d\n", This, Type);
1208 if(NULL == ppQuery || hr != WINED3D_OK) {
1209 return hr;
1212 D3DCREATEOBJECTINSTANCE(object, Query)
1213 object->lpVtbl = vtable;
1214 object->type = Type;
1215 object->state = QUERY_CREATED;
1216 /* allocated the 'extended' data based on the type of query requested */
1217 switch(Type){
1218 case WINED3DQUERYTYPE_OCCLUSION:
1219 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1220 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1222 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1223 TRACE("(%p) Allocating data for an occlusion query\n", This);
1224 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1225 break;
1227 case WINED3DQUERYTYPE_EVENT:
1228 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1229 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1231 if(GL_SUPPORT(APPLE_FENCE)) {
1232 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1233 checkGLcall("glGenFencesAPPLE");
1234 } else if(GL_SUPPORT(NV_FENCE)) {
1235 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1236 checkGLcall("glGenFencesNV");
1238 break;
1240 case WINED3DQUERYTYPE_VCACHE:
1241 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1242 case WINED3DQUERYTYPE_VERTEXSTATS:
1243 case WINED3DQUERYTYPE_TIMESTAMP:
1244 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1245 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1246 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1247 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1248 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1249 case WINED3DQUERYTYPE_PIXELTIMINGS:
1250 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1251 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1252 default:
1253 object->extendedData = 0;
1254 FIXME("(%p) Unhandled query type %d\n",This , Type);
1256 TRACE("(%p) : Created Query %p\n", This, object);
1257 return WINED3D_OK;
1260 /*****************************************************************************
1261 * IWineD3DDeviceImpl_SetupFullscreenWindow
1263 * Helper function that modifies a HWND's Style and ExStyle for proper
1264 * fullscreen use.
1266 * Params:
1267 * iface: Pointer to the IWineD3DDevice interface
1268 * window: Window to setup
1270 *****************************************************************************/
1271 static LONG fullscreen_style(LONG orig_style) {
1272 LONG style = orig_style;
1273 style &= ~WS_CAPTION;
1274 style &= ~WS_THICKFRAME;
1276 /* Make sure the window is managed, otherwise we won't get keyboard input */
1277 style |= WS_POPUP | WS_SYSMENU;
1279 return style;
1282 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1283 LONG exStyle = orig_exStyle;
1285 /* Filter out window decorations */
1286 exStyle &= ~WS_EX_WINDOWEDGE;
1287 exStyle &= ~WS_EX_CLIENTEDGE;
1289 return exStyle;
1292 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1295 LONG style, exStyle;
1296 /* Don't do anything if an original style is stored.
1297 * That shouldn't happen
1299 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1300 if (This->style || This->exStyle) {
1301 ERR("(%p): Want to change the window parameters of HWND %p, but "
1302 "another style is stored for restoration afterwards\n", This, window);
1305 /* Get the parameters and save them */
1306 style = GetWindowLongW(window, GWL_STYLE);
1307 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1308 This->style = style;
1309 This->exStyle = exStyle;
1311 style = fullscreen_style(style);
1312 exStyle = fullscreen_exStyle(exStyle);
1314 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1315 This->style, This->exStyle, style, exStyle);
1317 SetWindowLongW(window, GWL_STYLE, style);
1318 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1320 /* Inform the window about the update. */
1321 SetWindowPos(window, HWND_TOP, 0, 0,
1322 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1325 /*****************************************************************************
1326 * IWineD3DDeviceImpl_RestoreWindow
1328 * Helper function that restores a windows' properties when taking it out
1329 * of fullscreen mode
1331 * Params:
1332 * iface: Pointer to the IWineD3DDevice interface
1333 * window: Window to setup
1335 *****************************************************************************/
1336 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1338 LONG style, exStyle;
1340 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1341 * switch, do nothing
1343 if (!This->style && !This->exStyle) return;
1345 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1346 This, window, This->style, This->exStyle);
1348 style = GetWindowLongW(window, GWL_STYLE);
1349 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1351 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1352 * Some applications change it before calling Reset() when switching between windowed and
1353 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1355 if(style == fullscreen_style(This->style) &&
1356 exStyle == fullscreen_style(This->exStyle)) {
1357 SetWindowLongW(window, GWL_STYLE, This->style);
1358 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1361 /* Delete the old values */
1362 This->style = 0;
1363 This->exStyle = 0;
1365 /* Inform the window about the update */
1366 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1367 0, 0, 0, 0, /* Pos, Size, ignored */
1368 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1371 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1372 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1373 IUnknown* parent,
1374 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1375 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil,
1376 WINED3DSURFTYPE surface_type) {
1377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1379 HDC hDc;
1380 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1381 HRESULT hr = WINED3D_OK;
1382 IUnknown *bufferParent;
1383 BOOL displaymode_set = FALSE;
1384 WINED3DDISPLAYMODE Mode;
1385 const StaticPixelFormatDesc *formatDesc;
1387 TRACE("(%p) : Created Additional Swap Chain\n", This);
1389 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1390 * does a device hold a reference to a swap chain giving them a lifetime of the device
1391 * or does the swap chain notify the device of its destruction.
1392 *******************************/
1394 /* Check the params */
1395 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1396 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1397 return WINED3DERR_INVALIDCALL;
1398 } else if (pPresentationParameters->BackBufferCount > 1) {
1399 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");
1402 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1403 switch(surface_type) {
1404 case SURFACE_GDI:
1405 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1406 break;
1407 case SURFACE_OPENGL:
1408 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1409 break;
1410 case SURFACE_UNKNOWN:
1411 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1412 return WINED3DERR_INVALIDCALL;
1415 /*********************
1416 * Lookup the window Handle and the relating X window handle
1417 ********************/
1419 /* Setup hwnd we are using, plus which display this equates to */
1420 object->win_handle = pPresentationParameters->hDeviceWindow;
1421 if (!object->win_handle) {
1422 object->win_handle = This->createParms.hFocusWindow;
1424 if(!pPresentationParameters->Windowed && object->win_handle) {
1425 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1426 pPresentationParameters->BackBufferWidth,
1427 pPresentationParameters->BackBufferHeight);
1430 hDc = GetDC(object->win_handle);
1431 TRACE("Using hDc %p\n", hDc);
1433 if (NULL == hDc) {
1434 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1435 return WINED3DERR_NOTAVAILABLE;
1438 /* Get info on the current display setup */
1439 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1440 object->orig_width = Mode.Width;
1441 object->orig_height = Mode.Height;
1442 object->orig_fmt = Mode.Format;
1443 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1445 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1446 * then the corresponding dimension of the client area of the hDeviceWindow
1447 * (or the focus window, if hDeviceWindow is NULL) is taken.
1448 **********************/
1450 if (pPresentationParameters->Windowed &&
1451 ((pPresentationParameters->BackBufferWidth == 0) ||
1452 (pPresentationParameters->BackBufferHeight == 0) ||
1453 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1455 RECT Rect;
1456 GetClientRect(object->win_handle, &Rect);
1458 if (pPresentationParameters->BackBufferWidth == 0) {
1459 pPresentationParameters->BackBufferWidth = Rect.right;
1460 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1462 if (pPresentationParameters->BackBufferHeight == 0) {
1463 pPresentationParameters->BackBufferHeight = Rect.bottom;
1464 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1466 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1467 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1468 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1472 /* Put the correct figures in the presentation parameters */
1473 TRACE("Copying across presentation parameters\n");
1474 object->presentParms = *pPresentationParameters;
1476 TRACE("calling rendertarget CB\n");
1477 hr = D3DCB_CreateRenderTarget(This->parent,
1478 parent,
1479 object->presentParms.BackBufferWidth,
1480 object->presentParms.BackBufferHeight,
1481 object->presentParms.BackBufferFormat,
1482 object->presentParms.MultiSampleType,
1483 object->presentParms.MultiSampleQuality,
1484 TRUE /* Lockable */,
1485 &object->frontBuffer,
1486 NULL /* pShared (always null)*/);
1487 if (object->frontBuffer != NULL) {
1488 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1489 if(surface_type == SURFACE_OPENGL) {
1490 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1492 } else {
1493 ERR("Failed to create the front buffer\n");
1494 goto error;
1497 /*********************
1498 * Windowed / Fullscreen
1499 *******************/
1502 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1503 * so we should really check to see if there is a fullscreen swapchain already
1504 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1505 **************************************/
1507 if (!pPresentationParameters->Windowed) {
1508 WINED3DDISPLAYMODE mode;
1511 /* Change the display settings */
1512 mode.Width = pPresentationParameters->BackBufferWidth;
1513 mode.Height = pPresentationParameters->BackBufferHeight;
1514 mode.Format = pPresentationParameters->BackBufferFormat;
1515 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1517 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1518 displaymode_set = TRUE;
1522 * Create an opengl context for the display visual
1523 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1524 * use different properties after that point in time. FIXME: How to handle when requested format
1525 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1526 * it chooses is identical to the one already being used!
1527 **********************************/
1528 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1530 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1531 if(!object->context)
1532 return E_OUTOFMEMORY;
1533 object->num_contexts = 1;
1535 if(surface_type == SURFACE_OPENGL) {
1536 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1537 if (!object->context[0]) {
1538 ERR("Failed to create a new context\n");
1539 hr = WINED3DERR_NOTAVAILABLE;
1540 goto error;
1541 } else {
1542 TRACE("Context created (HWND=%p, glContext=%p)\n",
1543 object->win_handle, object->context[0]->glCtx);
1547 /*********************
1548 * Create the back, front and stencil buffers
1549 *******************/
1550 if(object->presentParms.BackBufferCount > 0) {
1551 int i;
1553 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1554 if(!object->backBuffer) {
1555 ERR("Out of memory\n");
1556 hr = E_OUTOFMEMORY;
1557 goto error;
1560 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1561 TRACE("calling rendertarget CB\n");
1562 hr = D3DCB_CreateRenderTarget(This->parent,
1563 parent,
1564 object->presentParms.BackBufferWidth,
1565 object->presentParms.BackBufferHeight,
1566 object->presentParms.BackBufferFormat,
1567 object->presentParms.MultiSampleType,
1568 object->presentParms.MultiSampleQuality,
1569 TRUE /* Lockable */,
1570 &object->backBuffer[i],
1571 NULL /* pShared (always null)*/);
1572 if(hr == WINED3D_OK && object->backBuffer[i]) {
1573 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1574 } else {
1575 ERR("Cannot create new back buffer\n");
1576 goto error;
1578 if(surface_type == SURFACE_OPENGL) {
1579 ENTER_GL();
1580 glDrawBuffer(GL_BACK);
1581 checkGLcall("glDrawBuffer(GL_BACK)");
1582 LEAVE_GL();
1585 } else {
1586 object->backBuffer = NULL;
1588 /* Single buffering - draw to front buffer */
1589 if(surface_type == SURFACE_OPENGL) {
1590 ENTER_GL();
1591 glDrawBuffer(GL_FRONT);
1592 checkGLcall("glDrawBuffer(GL_FRONT)");
1593 LEAVE_GL();
1597 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1598 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK && surface_type == SURFACE_OPENGL) {
1599 TRACE("Creating depth stencil buffer\n");
1600 if (This->auto_depth_stencil_buffer == NULL ) {
1601 hr = D3DCB_CreateDepthStencil(This->parent,
1602 parent,
1603 object->presentParms.BackBufferWidth,
1604 object->presentParms.BackBufferHeight,
1605 object->presentParms.AutoDepthStencilFormat,
1606 object->presentParms.MultiSampleType,
1607 object->presentParms.MultiSampleQuality,
1608 FALSE /* FIXME: Discard */,
1609 &This->auto_depth_stencil_buffer,
1610 NULL /* pShared (always null)*/ );
1611 if (This->auto_depth_stencil_buffer != NULL)
1612 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1615 /** TODO: A check on width, height and multisample types
1616 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1617 ****************************/
1618 object->wantsDepthStencilBuffer = TRUE;
1619 } else {
1620 object->wantsDepthStencilBuffer = FALSE;
1623 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1625 TRACE("Created swapchain %p\n", object);
1626 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1627 return WINED3D_OK;
1629 error:
1630 if (displaymode_set) {
1631 DEVMODEW devmode;
1632 RECT clip_rc;
1634 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1635 ClipCursor(NULL);
1637 /* Change the display settings */
1638 memset(&devmode, 0, sizeof(devmode));
1639 devmode.dmSize = sizeof(devmode);
1640 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1641 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1642 devmode.dmPelsWidth = object->orig_width;
1643 devmode.dmPelsHeight = object->orig_height;
1644 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1647 if (object->backBuffer) {
1648 int i;
1649 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1650 if(object->backBuffer[i]) {
1651 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1652 IUnknown_Release(bufferParent); /* once for the get parent */
1653 if (IUnknown_Release(bufferParent) > 0) {
1654 FIXME("(%p) Something's still holding the back buffer\n",This);
1658 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1659 object->backBuffer = NULL;
1661 if(object->context[0])
1662 DestroyContext(This, object->context[0]);
1663 if(object->frontBuffer) {
1664 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1665 IUnknown_Release(bufferParent); /* once for the get parent */
1666 if (IUnknown_Release(bufferParent) > 0) {
1667 FIXME("(%p) Something's still holding the front buffer\n",This);
1670 HeapFree(GetProcessHeap(), 0, object);
1671 return hr;
1674 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1675 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1677 TRACE("(%p)\n", This);
1679 return This->NumberOfSwapChains;
1682 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1684 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1686 if(iSwapChain < This->NumberOfSwapChains) {
1687 *pSwapChain = This->swapchains[iSwapChain];
1688 IWineD3DSwapChain_AddRef(*pSwapChain);
1689 TRACE("(%p) returning %p\n", This, *pSwapChain);
1690 return WINED3D_OK;
1691 } else {
1692 TRACE("Swapchain out of range\n");
1693 *pSwapChain = NULL;
1694 return WINED3DERR_INVALIDCALL;
1698 /*****
1699 * Vertex Declaration
1700 *****/
1701 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1702 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1704 IWineD3DVertexDeclarationImpl *object = NULL;
1705 HRESULT hr = WINED3D_OK;
1707 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1708 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1710 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1712 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1713 if(FAILED(hr)) {
1714 *ppVertexDeclaration = NULL;
1715 HeapFree(GetProcessHeap(), 0, object);
1718 return hr;
1721 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1722 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1724 unsigned int idx, idx2;
1725 unsigned int offset;
1726 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1727 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1728 BOOL has_blend_idx = has_blend &&
1729 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1730 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1731 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1732 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1733 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1734 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1735 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1737 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1738 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1740 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1741 WINED3DVERTEXELEMENT *elements = NULL;
1743 unsigned int size;
1744 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1745 if (has_blend_idx) num_blends--;
1747 /* Compute declaration size */
1748 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1749 has_psize + has_diffuse + has_specular + num_textures + 1;
1751 /* convert the declaration */
1752 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1753 if (!elements)
1754 return 0;
1756 elements[size-1] = end_element;
1757 idx = 0;
1758 if (has_pos) {
1759 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1760 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1761 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1763 else {
1764 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1765 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1767 elements[idx].UsageIndex = 0;
1768 idx++;
1770 if (has_blend && (num_blends > 0)) {
1771 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1772 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1773 else
1774 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1775 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1776 elements[idx].UsageIndex = 0;
1777 idx++;
1779 if (has_blend_idx) {
1780 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1781 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1782 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1783 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1784 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1785 else
1786 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1787 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1788 elements[idx].UsageIndex = 0;
1789 idx++;
1791 if (has_normal) {
1792 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1793 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1794 elements[idx].UsageIndex = 0;
1795 idx++;
1797 if (has_psize) {
1798 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1799 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1800 elements[idx].UsageIndex = 0;
1801 idx++;
1803 if (has_diffuse) {
1804 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1805 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1806 elements[idx].UsageIndex = 0;
1807 idx++;
1809 if (has_specular) {
1810 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1811 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1812 elements[idx].UsageIndex = 1;
1813 idx++;
1815 for (idx2 = 0; idx2 < num_textures; idx2++) {
1816 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1817 switch (numcoords) {
1818 case WINED3DFVF_TEXTUREFORMAT1:
1819 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1820 break;
1821 case WINED3DFVF_TEXTUREFORMAT2:
1822 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1823 break;
1824 case WINED3DFVF_TEXTUREFORMAT3:
1825 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1826 break;
1827 case WINED3DFVF_TEXTUREFORMAT4:
1828 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1829 break;
1831 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1832 elements[idx].UsageIndex = idx2;
1833 idx++;
1836 /* Now compute offsets, and initialize the rest of the fields */
1837 for (idx = 0, offset = 0; idx < size-1; idx++) {
1838 elements[idx].Stream = 0;
1839 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1840 elements[idx].Offset = offset;
1841 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1844 *ppVertexElements = elements;
1845 return size;
1848 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1849 WINED3DVERTEXELEMENT* elements = NULL;
1850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1851 unsigned int size;
1852 DWORD hr;
1854 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1855 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1857 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1858 HeapFree(GetProcessHeap(), 0, elements);
1859 if (hr != S_OK) return hr;
1861 return WINED3D_OK;
1864 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1866 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1867 HRESULT hr = WINED3D_OK;
1868 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1869 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1871 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1873 if (vertex_declaration) {
1874 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1877 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1879 if (WINED3D_OK != hr) {
1880 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1881 IWineD3DVertexShader_Release(*ppVertexShader);
1882 return WINED3DERR_INVALIDCALL;
1884 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1886 return WINED3D_OK;
1889 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1891 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1892 HRESULT hr = WINED3D_OK;
1894 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1895 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1896 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1897 if (WINED3D_OK == hr) {
1898 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1899 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1900 } else {
1901 WARN("(%p) : Failed to create pixel shader\n", This);
1904 return hr;
1907 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1909 IWineD3DPaletteImpl *object;
1910 HRESULT hr;
1911 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1913 /* Create the new object */
1914 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1915 if(!object) {
1916 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1917 return E_OUTOFMEMORY;
1920 object->lpVtbl = &IWineD3DPalette_Vtbl;
1921 object->ref = 1;
1922 object->Flags = Flags;
1923 object->parent = Parent;
1924 object->wineD3DDevice = This;
1925 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1927 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1929 if(!object->hpal) {
1930 HeapFree( GetProcessHeap(), 0, object);
1931 return E_OUTOFMEMORY;
1934 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1935 if(FAILED(hr)) {
1936 IWineD3DPalette_Release((IWineD3DPalette *) object);
1937 return hr;
1940 *Palette = (IWineD3DPalette *) object;
1942 return WINED3D_OK;
1945 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1946 HBITMAP hbm;
1947 BITMAP bm;
1948 HRESULT hr;
1949 HDC dcb = NULL, dcs = NULL;
1950 WINEDDCOLORKEY colorkey;
1952 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1953 if(hbm)
1955 GetObjectA(hbm, sizeof(BITMAP), &bm);
1956 dcb = CreateCompatibleDC(NULL);
1957 if(!dcb) goto out;
1958 SelectObject(dcb, hbm);
1960 else
1962 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1963 * couldn't be loaded
1965 memset(&bm, 0, sizeof(bm));
1966 bm.bmWidth = 32;
1967 bm.bmHeight = 32;
1970 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1971 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1972 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1973 if(FAILED(hr)) {
1974 ERR("Wine logo requested, but failed to create surface\n");
1975 goto out;
1978 if(dcb) {
1979 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1980 if(FAILED(hr)) goto out;
1981 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1982 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1984 colorkey.dwColorSpaceLowValue = 0;
1985 colorkey.dwColorSpaceHighValue = 0;
1986 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1987 } else {
1988 /* Fill the surface with a white color to show that wined3d is there */
1989 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1992 out:
1993 if(dcb) {
1994 DeleteDC(dcb);
1996 if(hbm) {
1997 DeleteObject(hbm);
1999 return;
2002 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2003 unsigned int i;
2004 /* Under DirectX you can have texture stage operations even if no texture is
2005 bound, whereas opengl will only do texture operations when a valid texture is
2006 bound. We emulate this by creating dummy textures and binding them to each
2007 texture stage, but disable all stages by default. Hence if a stage is enabled
2008 then the default texture will kick in until replaced by a SetTexture call */
2009 ENTER_GL();
2011 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2012 /* The dummy texture does not have client storage backing */
2013 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2014 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2016 for (i = 0; i < GL_LIMITS(textures); i++) {
2017 GLubyte white = 255;
2019 /* Make appropriate texture active */
2020 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2021 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2022 checkGLcall("glActiveTextureARB");
2023 } else if (i > 0) {
2024 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2027 /* Generate an opengl texture name */
2028 glGenTextures(1, &This->dummyTextureName[i]);
2029 checkGLcall("glGenTextures");
2030 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2032 /* Generate a dummy 2d texture (not using 1d because they cause many
2033 * DRI drivers fall back to sw) */
2034 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2035 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2036 checkGLcall("glBindTexture");
2038 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2039 checkGLcall("glTexImage2D");
2041 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2042 /* Reenable because if supported it is enabled by default */
2043 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2044 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2047 LEAVE_GL();
2050 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2052 IWineD3DSwapChainImpl *swapchain = NULL;
2053 HRESULT hr;
2054 DWORD state;
2055 unsigned int i;
2057 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2058 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2059 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2061 /* TODO: Test if OpenGL is compiled in and loaded */
2063 TRACE("(%p) : Creating stateblock\n", This);
2064 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2065 hr = IWineD3DDevice_CreateStateBlock(iface,
2066 WINED3DSBT_INIT,
2067 (IWineD3DStateBlock **)&This->stateBlock,
2068 NULL);
2069 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2070 WARN("Failed to create stateblock\n");
2071 goto err_out;
2073 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2074 This->updateStateBlock = This->stateBlock;
2075 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2077 hr = allocate_shader_constants(This->updateStateBlock);
2078 if (WINED3D_OK != hr) {
2079 goto err_out;
2082 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2083 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2085 This->NumberOfPalettes = 1;
2086 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2087 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2088 ERR("Out of memory!\n");
2089 goto err_out;
2091 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2092 if(!This->palettes[0]) {
2093 ERR("Out of memory!\n");
2094 goto err_out;
2096 for (i = 0; i < 256; ++i) {
2097 This->palettes[0][i].peRed = 0xFF;
2098 This->palettes[0][i].peGreen = 0xFF;
2099 This->palettes[0][i].peBlue = 0xFF;
2100 This->palettes[0][i].peFlags = 0xFF;
2102 This->currentPalette = 0;
2104 /* Initialize the texture unit mapping to a 1:1 mapping */
2105 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2106 if (state < GL_LIMITS(fragment_samplers)) {
2107 This->texUnitMap[state] = state;
2108 This->rev_tex_unit_map[state] = state;
2109 } else {
2110 This->texUnitMap[state] = -1;
2111 This->rev_tex_unit_map[state] = -1;
2115 /* Setup the implicit swapchain */
2116 TRACE("Creating implicit swapchain\n");
2117 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2118 if (FAILED(hr) || !swapchain) {
2119 WARN("Failed to create implicit swapchain\n");
2120 goto err_out;
2123 This->NumberOfSwapChains = 1;
2124 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2125 if(!This->swapchains) {
2126 ERR("Out of memory!\n");
2127 goto err_out;
2129 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2131 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2132 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2133 This->render_targets[0] = swapchain->backBuffer[0];
2134 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2136 else {
2137 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2138 This->render_targets[0] = swapchain->frontBuffer;
2139 This->lastActiveRenderTarget = swapchain->frontBuffer;
2141 IWineD3DSurface_AddRef(This->render_targets[0]);
2142 This->activeContext = swapchain->context[0];
2143 This->lastThread = GetCurrentThreadId();
2145 /* Depth Stencil support */
2146 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2147 if (NULL != This->stencilBufferTarget) {
2148 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2151 hr = This->shader_backend->shader_alloc_private(iface);
2152 if(FAILED(hr)) {
2153 TRACE("Shader private data couldn't be allocated\n");
2154 goto err_out;
2156 hr = This->frag_pipe->alloc_private(iface);
2157 if(FAILED(hr)) {
2158 TRACE("Fragment pipeline private data couldn't be allocated\n");
2159 goto err_out;
2161 hr = This->blitter->alloc_private(iface);
2162 if(FAILED(hr)) {
2163 TRACE("Blitter private data couldn't be allocated\n");
2164 goto err_out;
2167 /* Set up some starting GL setup */
2169 /* Setup all the devices defaults */
2170 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2171 create_dummy_textures(This);
2173 ENTER_GL();
2175 #if 0
2176 IWineD3DImpl_CheckGraphicsMemory();
2177 #endif
2179 { /* Set a default viewport */
2180 WINED3DVIEWPORT vp;
2181 vp.X = 0;
2182 vp.Y = 0;
2183 vp.Width = pPresentationParameters->BackBufferWidth;
2184 vp.Height = pPresentationParameters->BackBufferHeight;
2185 vp.MinZ = 0.0f;
2186 vp.MaxZ = 1.0f;
2187 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2190 /* Initialize the current view state */
2191 This->view_ident = 1;
2192 This->contexts[0]->last_was_rhw = 0;
2193 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2194 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2196 switch(wined3d_settings.offscreen_rendering_mode) {
2197 case ORM_FBO:
2198 case ORM_PBUFFER:
2199 This->offscreenBuffer = GL_BACK;
2200 break;
2202 case ORM_BACKBUFFER:
2204 if(This->activeContext->aux_buffers > 0) {
2205 TRACE("Using auxilliary buffer for offscreen rendering\n");
2206 This->offscreenBuffer = GL_AUX0;
2207 } else {
2208 TRACE("Using back buffer for offscreen rendering\n");
2209 This->offscreenBuffer = GL_BACK;
2214 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2215 LEAVE_GL();
2217 /* Clear the screen */
2218 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2219 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2220 0x00, 1.0, 0);
2222 This->d3d_initialized = TRUE;
2224 if(wined3d_settings.logo) {
2225 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2227 This->highest_dirty_ps_const = 0;
2228 This->highest_dirty_vs_const = 0;
2229 return WINED3D_OK;
2231 err_out:
2232 HeapFree(GetProcessHeap(), 0, This->render_targets);
2233 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2234 HeapFree(GetProcessHeap(), 0, This->swapchains);
2235 This->NumberOfSwapChains = 0;
2236 if(This->palettes) {
2237 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2238 HeapFree(GetProcessHeap(), 0, This->palettes);
2240 This->NumberOfPalettes = 0;
2241 if(swapchain) {
2242 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2244 if(This->stateBlock) {
2245 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2246 This->stateBlock = NULL;
2248 if (This->blit_priv) {
2249 This->blitter->free_private(iface);
2251 if (This->fragment_priv) {
2252 This->frag_pipe->free_private(iface);
2254 if (This->shader_priv) {
2255 This->shader_backend->shader_free_private(iface);
2257 return hr;
2260 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2262 IWineD3DSwapChainImpl *swapchain = NULL;
2263 HRESULT hr;
2265 /* Setup the implicit swapchain */
2266 TRACE("Creating implicit swapchain\n");
2267 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2268 if (FAILED(hr) || !swapchain) {
2269 WARN("Failed to create implicit swapchain\n");
2270 goto err_out;
2273 This->NumberOfSwapChains = 1;
2274 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2275 if(!This->swapchains) {
2276 ERR("Out of memory!\n");
2277 goto err_out;
2279 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2280 return WINED3D_OK;
2282 err_out:
2283 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2284 return hr;
2287 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2289 int sampler;
2290 UINT i;
2291 TRACE("(%p)\n", This);
2293 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2295 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2296 * it was created. Thus make sure a context is active for the glDelete* calls
2298 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2300 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2302 TRACE("Deleting high order patches\n");
2303 for(i = 0; i < PATCHMAP_SIZE; i++) {
2304 struct list *e1, *e2;
2305 struct WineD3DRectPatch *patch;
2306 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2307 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2308 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2312 /* Delete the palette conversion shader if it is around */
2313 if(This->paletteConversionShader) {
2314 ENTER_GL();
2315 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2316 LEAVE_GL();
2317 This->paletteConversionShader = 0;
2320 /* Delete the pbuffer context if there is any */
2321 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2323 /* Delete the mouse cursor texture */
2324 if(This->cursorTexture) {
2325 ENTER_GL();
2326 glDeleteTextures(1, &This->cursorTexture);
2327 LEAVE_GL();
2328 This->cursorTexture = 0;
2331 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2332 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2334 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2335 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2338 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2339 * private data, it might contain opengl pointers
2341 if(This->depth_blt_texture) {
2342 glDeleteTextures(1, &This->depth_blt_texture);
2343 This->depth_blt_texture = 0;
2345 if (This->depth_blt_rb) {
2346 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2347 This->depth_blt_rb = 0;
2348 This->depth_blt_rb_w = 0;
2349 This->depth_blt_rb_h = 0;
2352 /* Release the update stateblock */
2353 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2354 if(This->updateStateBlock != This->stateBlock)
2355 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2357 This->updateStateBlock = NULL;
2359 { /* because were not doing proper internal refcounts releasing the primary state block
2360 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2361 to set this->stateBlock = NULL; first */
2362 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2363 This->stateBlock = NULL;
2365 /* Release the stateblock */
2366 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2367 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2371 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2372 This->blitter->free_private(iface);
2373 This->frag_pipe->free_private(iface);
2374 This->shader_backend->shader_free_private(iface);
2376 /* Release the buffers (with sanity checks)*/
2377 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2378 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2379 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2380 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2382 This->stencilBufferTarget = NULL;
2384 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2385 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2386 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2388 TRACE("Setting rendertarget to NULL\n");
2389 This->render_targets[0] = NULL;
2391 if (This->auto_depth_stencil_buffer) {
2392 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2393 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2395 This->auto_depth_stencil_buffer = NULL;
2398 for(i=0; i < This->NumberOfSwapChains; i++) {
2399 TRACE("Releasing the implicit swapchain %d\n", i);
2400 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2401 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2405 HeapFree(GetProcessHeap(), 0, This->swapchains);
2406 This->swapchains = NULL;
2407 This->NumberOfSwapChains = 0;
2409 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2410 HeapFree(GetProcessHeap(), 0, This->palettes);
2411 This->palettes = NULL;
2412 This->NumberOfPalettes = 0;
2414 HeapFree(GetProcessHeap(), 0, This->render_targets);
2415 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2416 This->render_targets = NULL;
2417 This->draw_buffers = NULL;
2419 This->d3d_initialized = FALSE;
2420 return WINED3D_OK;
2423 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2425 unsigned int i;
2427 for(i=0; i < This->NumberOfSwapChains; i++) {
2428 TRACE("Releasing the implicit swapchain %d\n", i);
2429 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2430 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2434 HeapFree(GetProcessHeap(), 0, This->swapchains);
2435 This->swapchains = NULL;
2436 This->NumberOfSwapChains = 0;
2437 return WINED3D_OK;
2440 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2441 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2442 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2444 * There is no way to deactivate thread safety once it is enabled.
2446 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2449 /*For now just store the flag(needed in case of ddraw) */
2450 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2452 return;
2455 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2456 DEVMODEW devmode;
2457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2458 LONG ret;
2459 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2460 RECT clip_rc;
2462 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2464 /* Resize the screen even without a window:
2465 * The app could have unset it with SetCooperativeLevel, but not called
2466 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2467 * but we don't have any hwnd
2470 memset(&devmode, 0, sizeof(devmode));
2471 devmode.dmSize = sizeof(devmode);
2472 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2473 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2474 devmode.dmPelsWidth = pMode->Width;
2475 devmode.dmPelsHeight = pMode->Height;
2477 devmode.dmDisplayFrequency = pMode->RefreshRate;
2478 if (pMode->RefreshRate != 0) {
2479 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2482 /* Only change the mode if necessary */
2483 if( (This->ddraw_width == pMode->Width) &&
2484 (This->ddraw_height == pMode->Height) &&
2485 (This->ddraw_format == pMode->Format) &&
2486 (pMode->RefreshRate == 0) ) {
2487 return WINED3D_OK;
2490 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2491 if (ret != DISP_CHANGE_SUCCESSFUL) {
2492 if(devmode.dmDisplayFrequency != 0) {
2493 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2494 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2495 devmode.dmDisplayFrequency = 0;
2496 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2498 if(ret != DISP_CHANGE_SUCCESSFUL) {
2499 return WINED3DERR_NOTAVAILABLE;
2503 /* Store the new values */
2504 This->ddraw_width = pMode->Width;
2505 This->ddraw_height = pMode->Height;
2506 This->ddraw_format = pMode->Format;
2508 /* And finally clip mouse to our screen */
2509 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2510 ClipCursor(&clip_rc);
2512 return WINED3D_OK;
2515 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2517 *ppD3D= This->wineD3D;
2518 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2519 IWineD3D_AddRef(*ppD3D);
2520 return WINED3D_OK;
2523 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2526 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2527 (This->adapter->TextureRam/(1024*1024)),
2528 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2529 /* return simulated texture memory left */
2530 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2535 /*****
2536 * Get / Set FVF
2537 *****/
2538 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2541 /* Update the current state block */
2542 This->updateStateBlock->changed.fvf = TRUE;
2544 if(This->updateStateBlock->fvf == fvf) {
2545 TRACE("Application is setting the old fvf over, nothing to do\n");
2546 return WINED3D_OK;
2549 This->updateStateBlock->fvf = fvf;
2550 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2551 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2552 return WINED3D_OK;
2556 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2558 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2559 *pfvf = This->stateBlock->fvf;
2560 return WINED3D_OK;
2563 /*****
2564 * Get / Set Stream Source
2565 *****/
2566 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2568 IWineD3DVertexBuffer *oldSrc;
2570 if (StreamNumber >= MAX_STREAMS) {
2571 WARN("Stream out of range %d\n", StreamNumber);
2572 return WINED3DERR_INVALIDCALL;
2573 } else if(OffsetInBytes & 0x3) {
2574 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2575 return WINED3DERR_INVALIDCALL;
2578 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2579 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2581 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2583 if(oldSrc == pStreamData &&
2584 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2585 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2586 TRACE("Application is setting the old values over, nothing to do\n");
2587 return WINED3D_OK;
2590 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2591 if (pStreamData) {
2592 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2593 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2596 /* Handle recording of state blocks */
2597 if (This->isRecordingState) {
2598 TRACE("Recording... not performing anything\n");
2599 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2600 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2601 return WINED3D_OK;
2604 /* Need to do a getParent and pass the references up */
2605 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2606 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2607 so for now, just count internally */
2608 if (pStreamData != NULL) {
2609 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2610 InterlockedIncrement(&vbImpl->bindCount);
2611 IWineD3DVertexBuffer_AddRef(pStreamData);
2613 if (oldSrc != NULL) {
2614 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2615 IWineD3DVertexBuffer_Release(oldSrc);
2618 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2620 return WINED3D_OK;
2623 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2626 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2627 This->stateBlock->streamSource[StreamNumber],
2628 This->stateBlock->streamOffset[StreamNumber],
2629 This->stateBlock->streamStride[StreamNumber]);
2631 if (StreamNumber >= MAX_STREAMS) {
2632 WARN("Stream out of range %d\n", StreamNumber);
2633 return WINED3DERR_INVALIDCALL;
2635 *pStream = This->stateBlock->streamSource[StreamNumber];
2636 *pStride = This->stateBlock->streamStride[StreamNumber];
2637 if (pOffset) {
2638 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2641 if (*pStream != NULL) {
2642 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2644 return WINED3D_OK;
2647 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2649 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2650 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2652 /* Verify input at least in d3d9 this is invalid*/
2653 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2654 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2655 return WINED3DERR_INVALIDCALL;
2657 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2658 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2659 return WINED3DERR_INVALIDCALL;
2661 if( Divider == 0 ){
2662 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2663 return WINED3DERR_INVALIDCALL;
2666 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2667 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2669 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2670 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2672 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2673 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2674 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2677 return WINED3D_OK;
2680 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2683 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2684 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2686 TRACE("(%p) : returning %d\n", This, *Divider);
2688 return WINED3D_OK;
2691 /*****
2692 * Get / Set & Multiply Transform
2693 *****/
2694 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2695 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2697 /* Most of this routine, comments included copied from ddraw tree initially: */
2698 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2700 /* Handle recording of state blocks */
2701 if (This->isRecordingState) {
2702 TRACE("Recording... not performing anything\n");
2703 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2704 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2705 return WINED3D_OK;
2709 * If the new matrix is the same as the current one,
2710 * we cut off any further processing. this seems to be a reasonable
2711 * optimization because as was noticed, some apps (warcraft3 for example)
2712 * tend towards setting the same matrix repeatedly for some reason.
2714 * From here on we assume that the new matrix is different, wherever it matters.
2716 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2717 TRACE("The app is setting the same matrix over again\n");
2718 return WINED3D_OK;
2719 } else {
2720 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2724 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2725 where ViewMat = Camera space, WorldMat = world space.
2727 In OpenGL, camera and world space is combined into GL_MODELVIEW
2728 matrix. The Projection matrix stay projection matrix.
2731 /* Capture the times we can just ignore the change for now */
2732 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2733 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2734 /* Handled by the state manager */
2737 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2738 return WINED3D_OK;
2741 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2743 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2744 *pMatrix = This->stateBlock->transforms[State];
2745 return WINED3D_OK;
2748 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2749 WINED3DMATRIX *mat = NULL;
2750 WINED3DMATRIX temp;
2752 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2753 * below means it will be recorded in a state block change, but it
2754 * works regardless where it is recorded.
2755 * If this is found to be wrong, change to StateBlock.
2757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2758 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2760 if (State < HIGHEST_TRANSFORMSTATE)
2762 mat = &This->updateStateBlock->transforms[State];
2763 } else {
2764 FIXME("Unhandled transform state!!\n");
2767 multiply_matrix(&temp, mat, pMatrix);
2769 /* Apply change via set transform - will reapply to eg. lights this way */
2770 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2773 /*****
2774 * Get / Set Light
2775 *****/
2776 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2777 you can reference any indexes you want as long as that number max are enabled at any
2778 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2779 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2780 but when recording, just build a chain pretty much of commands to be replayed. */
2782 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2783 float rho;
2784 PLIGHTINFOEL *object = NULL;
2785 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2786 struct list *e;
2788 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2789 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2791 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2792 * the gl driver.
2794 if(!pLight) {
2795 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2796 return WINED3DERR_INVALIDCALL;
2799 switch(pLight->Type) {
2800 case WINED3DLIGHT_POINT:
2801 case WINED3DLIGHT_SPOT:
2802 case WINED3DLIGHT_PARALLELPOINT:
2803 case WINED3DLIGHT_GLSPOT:
2804 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2805 * most wanted
2807 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2808 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2809 return WINED3DERR_INVALIDCALL;
2811 break;
2813 case WINED3DLIGHT_DIRECTIONAL:
2814 /* Ignores attenuation */
2815 break;
2817 default:
2818 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2819 return WINED3DERR_INVALIDCALL;
2822 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2823 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2824 if(object->OriginalIndex == Index) break;
2825 object = NULL;
2828 if(!object) {
2829 TRACE("Adding new light\n");
2830 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2831 if(!object) {
2832 ERR("Out of memory error when allocating a light\n");
2833 return E_OUTOFMEMORY;
2835 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2836 object->glIndex = -1;
2837 object->OriginalIndex = Index;
2838 object->changed = TRUE;
2841 /* Initialize the object */
2842 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,
2843 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2844 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2845 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2846 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2847 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2848 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2850 /* Save away the information */
2851 object->OriginalParms = *pLight;
2853 switch (pLight->Type) {
2854 case WINED3DLIGHT_POINT:
2855 /* Position */
2856 object->lightPosn[0] = pLight->Position.x;
2857 object->lightPosn[1] = pLight->Position.y;
2858 object->lightPosn[2] = pLight->Position.z;
2859 object->lightPosn[3] = 1.0f;
2860 object->cutoff = 180.0f;
2861 /* FIXME: Range */
2862 break;
2864 case WINED3DLIGHT_DIRECTIONAL:
2865 /* Direction */
2866 object->lightPosn[0] = -pLight->Direction.x;
2867 object->lightPosn[1] = -pLight->Direction.y;
2868 object->lightPosn[2] = -pLight->Direction.z;
2869 object->lightPosn[3] = 0.0;
2870 object->exponent = 0.0f;
2871 object->cutoff = 180.0f;
2872 break;
2874 case WINED3DLIGHT_SPOT:
2875 /* Position */
2876 object->lightPosn[0] = pLight->Position.x;
2877 object->lightPosn[1] = pLight->Position.y;
2878 object->lightPosn[2] = pLight->Position.z;
2879 object->lightPosn[3] = 1.0;
2881 /* Direction */
2882 object->lightDirn[0] = pLight->Direction.x;
2883 object->lightDirn[1] = pLight->Direction.y;
2884 object->lightDirn[2] = pLight->Direction.z;
2885 object->lightDirn[3] = 1.0;
2888 * opengl-ish and d3d-ish spot lights use too different models for the
2889 * light "intensity" as a function of the angle towards the main light direction,
2890 * so we only can approximate very roughly.
2891 * however spot lights are rather rarely used in games (if ever used at all).
2892 * furthermore if still used, probably nobody pays attention to such details.
2894 if (pLight->Falloff == 0) {
2895 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2896 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2897 * will always be 1.0 for both of them, and we don't have to care for the
2898 * rest of the rather complex calculation
2900 object->exponent = 0;
2901 } else {
2902 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2903 if (rho < 0.0001) rho = 0.0001f;
2904 object->exponent = -0.3/log(cos(rho/2));
2906 if (object->exponent > 128.0) {
2907 object->exponent = 128.0;
2909 object->cutoff = pLight->Phi*90/M_PI;
2911 /* FIXME: Range */
2912 break;
2914 default:
2915 FIXME("Unrecognized light type %d\n", pLight->Type);
2918 /* Update the live definitions if the light is currently assigned a glIndex */
2919 if (object->glIndex != -1 && !This->isRecordingState) {
2920 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2922 return WINED3D_OK;
2925 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2926 PLIGHTINFOEL *lightInfo = NULL;
2927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2928 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2929 struct list *e;
2930 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2932 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2933 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2934 if(lightInfo->OriginalIndex == Index) break;
2935 lightInfo = NULL;
2938 if (lightInfo == NULL) {
2939 TRACE("Light information requested but light not defined\n");
2940 return WINED3DERR_INVALIDCALL;
2943 *pLight = lightInfo->OriginalParms;
2944 return WINED3D_OK;
2947 /*****
2948 * Get / Set Light Enable
2949 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2950 *****/
2951 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2952 PLIGHTINFOEL *lightInfo = NULL;
2953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2954 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2955 struct list *e;
2956 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2958 /* Tests show true = 128...not clear why */
2959 Enable = Enable? 128: 0;
2961 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2962 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2963 if(lightInfo->OriginalIndex == Index) break;
2964 lightInfo = NULL;
2966 TRACE("Found light: %p\n", lightInfo);
2968 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2969 if (lightInfo == NULL) {
2971 TRACE("Light enabled requested but light not defined, so defining one!\n");
2972 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2974 /* Search for it again! Should be fairly quick as near head of list */
2975 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2976 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2977 if(lightInfo->OriginalIndex == Index) break;
2978 lightInfo = NULL;
2980 if (lightInfo == NULL) {
2981 FIXME("Adding default lights has failed dismally\n");
2982 return WINED3DERR_INVALIDCALL;
2986 lightInfo->enabledChanged = TRUE;
2987 if(!Enable) {
2988 if(lightInfo->glIndex != -1) {
2989 if(!This->isRecordingState) {
2990 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2993 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2994 lightInfo->glIndex = -1;
2995 } else {
2996 TRACE("Light already disabled, nothing to do\n");
2998 lightInfo->enabled = FALSE;
2999 } else {
3000 lightInfo->enabled = TRUE;
3001 if (lightInfo->glIndex != -1) {
3002 /* nop */
3003 TRACE("Nothing to do as light was enabled\n");
3004 } else {
3005 int i;
3006 /* Find a free gl light */
3007 for(i = 0; i < This->maxConcurrentLights; i++) {
3008 if(This->stateBlock->activeLights[i] == NULL) {
3009 This->stateBlock->activeLights[i] = lightInfo;
3010 lightInfo->glIndex = i;
3011 break;
3014 if(lightInfo->glIndex == -1) {
3015 /* Our tests show that Windows returns D3D_OK in this situation, even with
3016 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3017 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3018 * as well for those lights.
3020 * TODO: Test how this affects rendering
3022 FIXME("Too many concurrently active lights\n");
3023 return WINED3D_OK;
3026 /* i == lightInfo->glIndex */
3027 if(!This->isRecordingState) {
3028 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3033 return WINED3D_OK;
3036 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3038 PLIGHTINFOEL *lightInfo = NULL;
3039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3040 struct list *e;
3041 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3042 TRACE("(%p) : for idx(%d)\n", This, Index);
3044 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3045 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3046 if(lightInfo->OriginalIndex == Index) break;
3047 lightInfo = NULL;
3050 if (lightInfo == NULL) {
3051 TRACE("Light enabled state requested but light not defined\n");
3052 return WINED3DERR_INVALIDCALL;
3054 /* true is 128 according to SetLightEnable */
3055 *pEnable = lightInfo->enabled ? 128 : 0;
3056 return WINED3D_OK;
3059 /*****
3060 * Get / Set Clip Planes
3061 *****/
3062 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3064 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3066 /* Validate Index */
3067 if (Index >= GL_LIMITS(clipplanes)) {
3068 TRACE("Application has requested clipplane this device doesn't support\n");
3069 return WINED3DERR_INVALIDCALL;
3072 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3074 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3075 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3076 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3077 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3078 TRACE("Application is setting old values over, nothing to do\n");
3079 return WINED3D_OK;
3082 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3083 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3084 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3085 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3087 /* Handle recording of state blocks */
3088 if (This->isRecordingState) {
3089 TRACE("Recording... not performing anything\n");
3090 return WINED3D_OK;
3093 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3095 return WINED3D_OK;
3098 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3100 TRACE("(%p) : for idx %d\n", This, Index);
3102 /* Validate Index */
3103 if (Index >= GL_LIMITS(clipplanes)) {
3104 TRACE("Application has requested clipplane this device doesn't support\n");
3105 return WINED3DERR_INVALIDCALL;
3108 pPlane[0] = This->stateBlock->clipplane[Index][0];
3109 pPlane[1] = This->stateBlock->clipplane[Index][1];
3110 pPlane[2] = This->stateBlock->clipplane[Index][2];
3111 pPlane[3] = This->stateBlock->clipplane[Index][3];
3112 return WINED3D_OK;
3115 /*****
3116 * Get / Set Clip Plane Status
3117 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3118 *****/
3119 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3121 FIXME("(%p) : stub\n", This);
3122 if (NULL == pClipStatus) {
3123 return WINED3DERR_INVALIDCALL;
3125 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3126 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3127 return WINED3D_OK;
3130 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3132 FIXME("(%p) : stub\n", This);
3133 if (NULL == pClipStatus) {
3134 return WINED3DERR_INVALIDCALL;
3136 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3137 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3138 return WINED3D_OK;
3141 /*****
3142 * Get / Set Material
3143 *****/
3144 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3147 This->updateStateBlock->changed.material = TRUE;
3148 This->updateStateBlock->material = *pMaterial;
3150 /* Handle recording of state blocks */
3151 if (This->isRecordingState) {
3152 TRACE("Recording... not performing anything\n");
3153 return WINED3D_OK;
3156 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3157 return WINED3D_OK;
3160 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3162 *pMaterial = This->updateStateBlock->material;
3163 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3164 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3165 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3166 pMaterial->Ambient.b, pMaterial->Ambient.a);
3167 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3168 pMaterial->Specular.b, pMaterial->Specular.a);
3169 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3170 pMaterial->Emissive.b, pMaterial->Emissive.a);
3171 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3173 return WINED3D_OK;
3176 /*****
3177 * Get / Set Indices
3178 *****/
3179 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3181 IWineD3DIndexBuffer *oldIdxs;
3183 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3184 oldIdxs = This->updateStateBlock->pIndexData;
3186 This->updateStateBlock->changed.indices = TRUE;
3187 This->updateStateBlock->pIndexData = pIndexData;
3189 /* Handle recording of state blocks */
3190 if (This->isRecordingState) {
3191 TRACE("Recording... not performing anything\n");
3192 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3193 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3194 return WINED3D_OK;
3197 if(oldIdxs != pIndexData) {
3198 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3199 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3200 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3202 return WINED3D_OK;
3205 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3208 *ppIndexData = This->stateBlock->pIndexData;
3210 /* up ref count on ppindexdata */
3211 if (*ppIndexData) {
3212 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3213 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3214 }else{
3215 TRACE("(%p) No index data set\n", This);
3217 TRACE("Returning %p\n", *ppIndexData);
3219 return WINED3D_OK;
3222 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3223 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3225 TRACE("(%p)->(%d)\n", This, BaseIndex);
3227 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3228 TRACE("Application is setting the old value over, nothing to do\n");
3229 return WINED3D_OK;
3232 This->updateStateBlock->baseVertexIndex = BaseIndex;
3234 if (This->isRecordingState) {
3235 TRACE("Recording... not performing anything\n");
3236 return WINED3D_OK;
3238 /* The base vertex index affects the stream sources */
3239 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3240 return WINED3D_OK;
3243 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3245 TRACE("(%p) : base_index %p\n", This, base_index);
3247 *base_index = This->stateBlock->baseVertexIndex;
3249 TRACE("Returning %u\n", *base_index);
3251 return WINED3D_OK;
3254 /*****
3255 * Get / Set Viewports
3256 *****/
3257 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3260 TRACE("(%p)\n", This);
3261 This->updateStateBlock->changed.viewport = TRUE;
3262 This->updateStateBlock->viewport = *pViewport;
3264 /* Handle recording of state blocks */
3265 if (This->isRecordingState) {
3266 TRACE("Recording... not performing anything\n");
3267 return WINED3D_OK;
3270 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3271 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3273 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3274 return WINED3D_OK;
3278 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3280 TRACE("(%p)\n", This);
3281 *pViewport = This->stateBlock->viewport;
3282 return WINED3D_OK;
3285 /*****
3286 * Get / Set Render States
3287 * TODO: Verify against dx9 definitions
3288 *****/
3289 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3292 DWORD oldValue = This->stateBlock->renderState[State];
3294 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3296 This->updateStateBlock->changed.renderState[State] = TRUE;
3297 This->updateStateBlock->renderState[State] = Value;
3299 /* Handle recording of state blocks */
3300 if (This->isRecordingState) {
3301 TRACE("Recording... not performing anything\n");
3302 return WINED3D_OK;
3305 /* Compared here and not before the assignment to allow proper stateblock recording */
3306 if(Value == oldValue) {
3307 TRACE("Application is setting the old value over, nothing to do\n");
3308 } else {
3309 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3312 return WINED3D_OK;
3315 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3317 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3318 *pValue = This->stateBlock->renderState[State];
3319 return WINED3D_OK;
3322 /*****
3323 * Get / Set Sampler States
3324 * TODO: Verify against dx9 definitions
3325 *****/
3327 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3329 DWORD oldValue;
3331 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3332 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3334 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3335 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3338 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3339 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3340 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3343 * SetSampler is designed to allow for more than the standard up to 8 textures
3344 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3345 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3347 * http://developer.nvidia.com/object/General_FAQ.html#t6
3349 * There are two new settings for GForce
3350 * the sampler one:
3351 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3352 * and the texture one:
3353 * GL_MAX_TEXTURE_COORDS_ARB.
3354 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3355 ******************/
3357 oldValue = This->stateBlock->samplerState[Sampler][Type];
3358 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3359 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3361 /* Handle recording of state blocks */
3362 if (This->isRecordingState) {
3363 TRACE("Recording... not performing anything\n");
3364 return WINED3D_OK;
3367 if(oldValue == Value) {
3368 TRACE("Application is setting the old value over, nothing to do\n");
3369 return WINED3D_OK;
3372 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3374 return WINED3D_OK;
3377 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3380 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3381 This, Sampler, debug_d3dsamplerstate(Type), Type);
3383 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3384 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3387 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3388 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3389 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3391 *Value = This->stateBlock->samplerState[Sampler][Type];
3392 TRACE("(%p) : Returning %#x\n", This, *Value);
3394 return WINED3D_OK;
3397 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3400 This->updateStateBlock->changed.scissorRect = TRUE;
3401 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3402 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3403 return WINED3D_OK;
3405 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3407 if(This->isRecordingState) {
3408 TRACE("Recording... not performing anything\n");
3409 return WINED3D_OK;
3412 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3414 return WINED3D_OK;
3417 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3420 *pRect = This->updateStateBlock->scissorRect;
3421 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3422 return WINED3D_OK;
3425 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3427 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3429 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3431 This->updateStateBlock->vertexDecl = pDecl;
3432 This->updateStateBlock->changed.vertexDecl = TRUE;
3434 if (This->isRecordingState) {
3435 TRACE("Recording... not performing anything\n");
3436 return WINED3D_OK;
3437 } else if(pDecl == oldDecl) {
3438 /* Checked after the assignment to allow proper stateblock recording */
3439 TRACE("Application is setting the old declaration over, nothing to do\n");
3440 return WINED3D_OK;
3443 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3444 return WINED3D_OK;
3447 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3450 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3452 *ppDecl = This->stateBlock->vertexDecl;
3453 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3454 return WINED3D_OK;
3457 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3459 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3461 This->updateStateBlock->vertexShader = pShader;
3462 This->updateStateBlock->changed.vertexShader = TRUE;
3464 if (This->isRecordingState) {
3465 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3466 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3467 TRACE("Recording... not performing anything\n");
3468 return WINED3D_OK;
3469 } else if(oldShader == pShader) {
3470 /* Checked here to allow proper stateblock recording */
3471 TRACE("App is setting the old shader over, nothing to do\n");
3472 return WINED3D_OK;
3475 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3476 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3477 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3479 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3481 return WINED3D_OK;
3484 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3487 if (NULL == ppShader) {
3488 return WINED3DERR_INVALIDCALL;
3490 *ppShader = This->stateBlock->vertexShader;
3491 if( NULL != *ppShader)
3492 IWineD3DVertexShader_AddRef(*ppShader);
3494 TRACE("(%p) : returning %p\n", This, *ppShader);
3495 return WINED3D_OK;
3498 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3499 IWineD3DDevice *iface,
3500 UINT start,
3501 CONST BOOL *srcData,
3502 UINT count) {
3504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3505 int i, cnt = min(count, MAX_CONST_B - start);
3507 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3508 iface, srcData, start, count);
3510 if (srcData == NULL || cnt < 0)
3511 return WINED3DERR_INVALIDCALL;
3513 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3514 for (i = 0; i < cnt; i++)
3515 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3517 for (i = start; i < cnt + start; ++i) {
3518 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3521 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3523 return WINED3D_OK;
3526 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3527 IWineD3DDevice *iface,
3528 UINT start,
3529 BOOL *dstData,
3530 UINT count) {
3532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3533 int cnt = min(count, MAX_CONST_B - start);
3535 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3536 iface, dstData, start, count);
3538 if (dstData == NULL || cnt < 0)
3539 return WINED3DERR_INVALIDCALL;
3541 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3542 return WINED3D_OK;
3545 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3546 IWineD3DDevice *iface,
3547 UINT start,
3548 CONST int *srcData,
3549 UINT count) {
3551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3552 int i, cnt = min(count, MAX_CONST_I - start);
3554 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3555 iface, srcData, start, count);
3557 if (srcData == NULL || cnt < 0)
3558 return WINED3DERR_INVALIDCALL;
3560 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3561 for (i = 0; i < cnt; i++)
3562 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3563 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3565 for (i = start; i < cnt + start; ++i) {
3566 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3569 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3571 return WINED3D_OK;
3574 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3575 IWineD3DDevice *iface,
3576 UINT start,
3577 int *dstData,
3578 UINT count) {
3580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3581 int cnt = min(count, MAX_CONST_I - start);
3583 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3584 iface, dstData, start, count);
3586 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3587 return WINED3DERR_INVALIDCALL;
3589 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3590 return WINED3D_OK;
3593 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3594 IWineD3DDevice *iface,
3595 UINT start,
3596 CONST float *srcData,
3597 UINT count) {
3599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3600 int i;
3602 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3603 iface, srcData, start, count);
3605 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3606 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3607 return WINED3DERR_INVALIDCALL;
3609 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3610 if(TRACE_ON(d3d)) {
3611 for (i = 0; i < count; i++)
3612 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3613 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3616 for (i = start; i < count + start; ++i) {
3617 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3618 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3619 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3620 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3621 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3623 ptr->idx[ptr->count++] = i;
3624 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3628 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3630 return WINED3D_OK;
3633 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3634 IWineD3DDevice *iface,
3635 UINT start,
3636 CONST float *srcData,
3637 UINT count) {
3639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3640 int i;
3642 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3643 iface, srcData, start, count);
3645 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3646 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3647 return WINED3DERR_INVALIDCALL;
3649 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3650 if(TRACE_ON(d3d)) {
3651 for (i = 0; i < count; i++)
3652 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3653 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3656 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3657 * context. On a context switch the old context will be fully dirtified
3659 memset(This->activeContext->vshader_const_dirty + start, 1,
3660 sizeof(*This->activeContext->vshader_const_dirty) * count);
3661 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count+1);
3663 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3665 return WINED3D_OK;
3668 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3669 IWineD3DDevice *iface,
3670 UINT start,
3671 float *dstData,
3672 UINT count) {
3674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3675 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3677 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3678 iface, dstData, start, count);
3680 if (dstData == NULL || cnt < 0)
3681 return WINED3DERR_INVALIDCALL;
3683 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3684 return WINED3D_OK;
3687 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3688 DWORD i;
3689 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3690 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3694 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3695 int i = This->rev_tex_unit_map[unit];
3696 int j = This->texUnitMap[stage];
3698 This->texUnitMap[stage] = unit;
3699 if (i != -1 && i != stage) {
3700 This->texUnitMap[i] = -1;
3703 This->rev_tex_unit_map[unit] = stage;
3704 if (j != -1 && j != unit) {
3705 This->rev_tex_unit_map[j] = -1;
3709 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3710 int i;
3712 for (i = 0; i < MAX_TEXTURES; ++i) {
3713 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3714 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3715 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3716 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3717 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3718 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3719 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3720 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3722 if (color_op == WINED3DTOP_DISABLE) {
3723 /* Not used, and disable higher stages */
3724 while (i < MAX_TEXTURES) {
3725 This->fixed_function_usage_map[i] = FALSE;
3726 ++i;
3728 break;
3731 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3732 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3733 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3734 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3735 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3736 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3737 This->fixed_function_usage_map[i] = TRUE;
3738 } else {
3739 This->fixed_function_usage_map[i] = FALSE;
3742 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3743 This->fixed_function_usage_map[i+1] = TRUE;
3748 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3749 int i, tex;
3751 device_update_fixed_function_usage_map(This);
3753 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3754 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3755 if (!This->fixed_function_usage_map[i]) continue;
3757 if (This->texUnitMap[i] != i) {
3758 device_map_stage(This, i, i);
3759 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3760 markTextureStagesDirty(This, i);
3763 return;
3766 /* Now work out the mapping */
3767 tex = 0;
3768 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3769 if (!This->fixed_function_usage_map[i]) continue;
3771 if (This->texUnitMap[i] != tex) {
3772 device_map_stage(This, i, tex);
3773 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3774 markTextureStagesDirty(This, i);
3777 ++tex;
3781 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3782 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3783 int i;
3785 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3786 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3787 device_map_stage(This, i, i);
3788 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3789 if (i < MAX_TEXTURES) {
3790 markTextureStagesDirty(This, i);
3796 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3797 int current_mapping = This->rev_tex_unit_map[unit];
3799 if (current_mapping == -1) {
3800 /* Not currently used */
3801 return TRUE;
3804 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3805 /* Used by a fragment sampler */
3807 if (!pshader_sampler_tokens) {
3808 /* No pixel shader, check fixed function */
3809 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3812 /* Pixel shader, check the shader's sampler map */
3813 return !pshader_sampler_tokens[current_mapping];
3816 /* Used by a vertex sampler */
3817 return !vshader_sampler_tokens[current_mapping];
3820 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3821 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3822 DWORD *pshader_sampler_tokens = NULL;
3823 int start = GL_LIMITS(combined_samplers) - 1;
3824 int i;
3826 if (ps) {
3827 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3829 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3830 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3831 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3834 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3835 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3836 if (vshader_sampler_tokens[i]) {
3837 if (This->texUnitMap[vsampler_idx] != -1) {
3838 /* Already mapped somewhere */
3839 continue;
3842 while (start >= 0) {
3843 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3844 device_map_stage(This, vsampler_idx, start);
3845 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3847 --start;
3848 break;
3851 --start;
3857 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3858 BOOL vs = use_vs(This);
3859 BOOL ps = use_ps(This);
3861 * Rules are:
3862 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3863 * that would be really messy and require shader recompilation
3864 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3865 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3867 if (ps) {
3868 device_map_psamplers(This);
3869 } else {
3870 device_map_fixed_function_samplers(This);
3873 if (vs) {
3874 device_map_vsamplers(This, ps);
3878 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3880 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3881 This->updateStateBlock->pixelShader = pShader;
3882 This->updateStateBlock->changed.pixelShader = TRUE;
3884 /* Handle recording of state blocks */
3885 if (This->isRecordingState) {
3886 TRACE("Recording... not performing anything\n");
3889 if (This->isRecordingState) {
3890 TRACE("Recording... not performing anything\n");
3891 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3892 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3893 return WINED3D_OK;
3896 if(pShader == oldShader) {
3897 TRACE("App is setting the old pixel shader over, nothing to do\n");
3898 return WINED3D_OK;
3901 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3902 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3904 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3905 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3907 return WINED3D_OK;
3910 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3913 if (NULL == ppShader) {
3914 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3915 return WINED3DERR_INVALIDCALL;
3918 *ppShader = This->stateBlock->pixelShader;
3919 if (NULL != *ppShader) {
3920 IWineD3DPixelShader_AddRef(*ppShader);
3922 TRACE("(%p) : returning %p\n", This, *ppShader);
3923 return WINED3D_OK;
3926 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3927 IWineD3DDevice *iface,
3928 UINT start,
3929 CONST BOOL *srcData,
3930 UINT count) {
3932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3933 int i, cnt = min(count, MAX_CONST_B - start);
3935 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3936 iface, srcData, start, count);
3938 if (srcData == NULL || cnt < 0)
3939 return WINED3DERR_INVALIDCALL;
3941 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3942 for (i = 0; i < cnt; i++)
3943 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3945 for (i = start; i < cnt + start; ++i) {
3946 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3949 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3951 return WINED3D_OK;
3954 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3955 IWineD3DDevice *iface,
3956 UINT start,
3957 BOOL *dstData,
3958 UINT count) {
3960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3961 int cnt = min(count, MAX_CONST_B - start);
3963 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3964 iface, dstData, start, count);
3966 if (dstData == NULL || cnt < 0)
3967 return WINED3DERR_INVALIDCALL;
3969 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3970 return WINED3D_OK;
3973 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3974 IWineD3DDevice *iface,
3975 UINT start,
3976 CONST int *srcData,
3977 UINT count) {
3979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3980 int i, cnt = min(count, MAX_CONST_I - start);
3982 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3983 iface, srcData, start, count);
3985 if (srcData == NULL || cnt < 0)
3986 return WINED3DERR_INVALIDCALL;
3988 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3989 for (i = 0; i < cnt; i++)
3990 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3991 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3993 for (i = start; i < cnt + start; ++i) {
3994 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3997 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3999 return WINED3D_OK;
4002 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4003 IWineD3DDevice *iface,
4004 UINT start,
4005 int *dstData,
4006 UINT count) {
4008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4009 int cnt = min(count, MAX_CONST_I - start);
4011 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4012 iface, dstData, start, count);
4014 if (dstData == NULL || cnt < 0)
4015 return WINED3DERR_INVALIDCALL;
4017 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4018 return WINED3D_OK;
4021 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4022 IWineD3DDevice *iface,
4023 UINT start,
4024 CONST float *srcData,
4025 UINT count) {
4027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4028 int i;
4030 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4031 iface, srcData, start, count);
4033 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4034 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4035 return WINED3DERR_INVALIDCALL;
4037 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4038 if(TRACE_ON(d3d)) {
4039 for (i = 0; i < count; i++)
4040 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4041 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4044 for (i = start; i < count + start; ++i) {
4045 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
4046 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
4047 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
4048 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
4049 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
4051 ptr->idx[ptr->count++] = i;
4052 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4056 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4058 return WINED3D_OK;
4061 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4062 IWineD3DDevice *iface,
4063 UINT start,
4064 CONST float *srcData,
4065 UINT count) {
4067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4068 int i;
4070 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4071 iface, srcData, start, count);
4073 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4074 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4075 return WINED3DERR_INVALIDCALL;
4077 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4078 if(TRACE_ON(d3d)) {
4079 for (i = 0; i < count; i++)
4080 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4081 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4084 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4085 * context. On a context switch the old context will be fully dirtified
4087 memset(This->activeContext->pshader_const_dirty + start, 1,
4088 sizeof(*This->activeContext->pshader_const_dirty) * count);
4089 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count+1);
4091 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4093 return WINED3D_OK;
4096 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4097 IWineD3DDevice *iface,
4098 UINT start,
4099 float *dstData,
4100 UINT count) {
4102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4103 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4105 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4106 iface, dstData, start, count);
4108 if (dstData == NULL || cnt < 0)
4109 return WINED3DERR_INVALIDCALL;
4111 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4112 return WINED3D_OK;
4115 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4116 static HRESULT
4117 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4118 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4119 unsigned int i;
4120 DWORD DestFVF = dest->fvf;
4121 WINED3DVIEWPORT vp;
4122 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4123 BOOL doClip;
4124 int numTextures;
4126 if (lpStrideData->u.s.normal.lpData) {
4127 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4130 if (lpStrideData->u.s.position.lpData == NULL) {
4131 ERR("Source has no position mask\n");
4132 return WINED3DERR_INVALIDCALL;
4135 /* We might access VBOs from this code, so hold the lock */
4136 ENTER_GL();
4138 if (dest->resource.allocatedMemory == NULL) {
4139 /* This may happen if we do direct locking into a vbo. Unlikely,
4140 * but theoretically possible(ddraw processvertices test)
4142 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4143 if(!dest->resource.allocatedMemory) {
4144 LEAVE_GL();
4145 ERR("Out of memory\n");
4146 return E_OUTOFMEMORY;
4148 if(dest->vbo) {
4149 void *src;
4150 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4151 checkGLcall("glBindBufferARB");
4152 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4153 if(src) {
4154 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4156 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4157 checkGLcall("glUnmapBufferARB");
4161 /* Get a pointer into the destination vbo(create one if none exists) and
4162 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4164 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4165 dest->Flags |= VBFLAG_CREATEVBO;
4166 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4169 if(dest->vbo) {
4170 unsigned char extrabytes = 0;
4171 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4172 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4173 * this may write 4 extra bytes beyond the area that should be written
4175 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4176 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4177 if(!dest_conv_addr) {
4178 ERR("Out of memory\n");
4179 /* Continue without storing converted vertices */
4181 dest_conv = dest_conv_addr;
4184 /* Should I clip?
4185 * a) WINED3DRS_CLIPPING is enabled
4186 * b) WINED3DVOP_CLIP is passed
4188 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4189 static BOOL warned = FALSE;
4191 * The clipping code is not quite correct. Some things need
4192 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4193 * so disable clipping for now.
4194 * (The graphics in Half-Life are broken, and my processvertices
4195 * test crashes with IDirect3DDevice3)
4196 doClip = TRUE;
4198 doClip = FALSE;
4199 if(!warned) {
4200 warned = TRUE;
4201 FIXME("Clipping is broken and disabled for now\n");
4203 } else doClip = FALSE;
4204 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4206 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4207 WINED3DTS_VIEW,
4208 &view_mat);
4209 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4210 WINED3DTS_PROJECTION,
4211 &proj_mat);
4212 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4213 WINED3DTS_WORLDMATRIX(0),
4214 &world_mat);
4216 TRACE("View mat:\n");
4217 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);
4218 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);
4219 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);
4220 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);
4222 TRACE("Proj mat:\n");
4223 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);
4224 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);
4225 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);
4226 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);
4228 TRACE("World mat:\n");
4229 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);
4230 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);
4231 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);
4232 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);
4234 /* Get the viewport */
4235 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4236 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4237 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4239 multiply_matrix(&mat,&view_mat,&world_mat);
4240 multiply_matrix(&mat,&proj_mat,&mat);
4242 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4244 for (i = 0; i < dwCount; i+= 1) {
4245 unsigned int tex_index;
4247 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4248 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4249 /* The position first */
4250 float *p =
4251 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4252 float x, y, z, rhw;
4253 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4255 /* Multiplication with world, view and projection matrix */
4256 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);
4257 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);
4258 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);
4259 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);
4261 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4263 /* WARNING: The following things are taken from d3d7 and were not yet checked
4264 * against d3d8 or d3d9!
4267 /* Clipping conditions: From msdn
4269 * A vertex is clipped if it does not match the following requirements
4270 * -rhw < x <= rhw
4271 * -rhw < y <= rhw
4272 * 0 < z <= rhw
4273 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4275 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4276 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4280 if( !doClip ||
4281 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4282 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4283 ( rhw > eps ) ) ) {
4285 /* "Normal" viewport transformation (not clipped)
4286 * 1) The values are divided by rhw
4287 * 2) The y axis is negative, so multiply it with -1
4288 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4289 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4290 * 4) Multiply x with Width/2 and add Width/2
4291 * 5) The same for the height
4292 * 6) Add the viewpoint X and Y to the 2D coordinates and
4293 * The minimum Z value to z
4294 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4296 * Well, basically it's simply a linear transformation into viewport
4297 * coordinates
4300 x /= rhw;
4301 y /= rhw;
4302 z /= rhw;
4304 y *= -1;
4306 x *= vp.Width / 2;
4307 y *= vp.Height / 2;
4308 z *= vp.MaxZ - vp.MinZ;
4310 x += vp.Width / 2 + vp.X;
4311 y += vp.Height / 2 + vp.Y;
4312 z += vp.MinZ;
4314 rhw = 1 / rhw;
4315 } else {
4316 /* That vertex got clipped
4317 * Contrary to OpenGL it is not dropped completely, it just
4318 * undergoes a different calculation.
4320 TRACE("Vertex got clipped\n");
4321 x += rhw;
4322 y += rhw;
4324 x /= 2;
4325 y /= 2;
4327 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4328 * outside of the main vertex buffer memory. That needs some more
4329 * investigation...
4333 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4336 ( (float *) dest_ptr)[0] = x;
4337 ( (float *) dest_ptr)[1] = y;
4338 ( (float *) dest_ptr)[2] = z;
4339 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4341 dest_ptr += 3 * sizeof(float);
4343 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4344 dest_ptr += sizeof(float);
4347 if(dest_conv) {
4348 float w = 1 / rhw;
4349 ( (float *) dest_conv)[0] = x * w;
4350 ( (float *) dest_conv)[1] = y * w;
4351 ( (float *) dest_conv)[2] = z * w;
4352 ( (float *) dest_conv)[3] = w;
4354 dest_conv += 3 * sizeof(float);
4356 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4357 dest_conv += sizeof(float);
4361 if (DestFVF & WINED3DFVF_PSIZE) {
4362 dest_ptr += sizeof(DWORD);
4363 if(dest_conv) dest_conv += sizeof(DWORD);
4365 if (DestFVF & WINED3DFVF_NORMAL) {
4366 float *normal =
4367 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4368 /* AFAIK this should go into the lighting information */
4369 FIXME("Didn't expect the destination to have a normal\n");
4370 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4371 if(dest_conv) {
4372 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4376 if (DestFVF & WINED3DFVF_DIFFUSE) {
4377 DWORD *color_d =
4378 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4379 if(!color_d) {
4380 static BOOL warned = FALSE;
4382 if(!warned) {
4383 ERR("No diffuse color in source, but destination has one\n");
4384 warned = TRUE;
4387 *( (DWORD *) dest_ptr) = 0xffffffff;
4388 dest_ptr += sizeof(DWORD);
4390 if(dest_conv) {
4391 *( (DWORD *) dest_conv) = 0xffffffff;
4392 dest_conv += sizeof(DWORD);
4395 else {
4396 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4397 if(dest_conv) {
4398 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4399 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4400 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4401 dest_conv += sizeof(DWORD);
4406 if (DestFVF & WINED3DFVF_SPECULAR) {
4407 /* What's the color value in the feedback buffer? */
4408 DWORD *color_s =
4409 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4410 if(!color_s) {
4411 static BOOL warned = FALSE;
4413 if(!warned) {
4414 ERR("No specular color in source, but destination has one\n");
4415 warned = TRUE;
4418 *( (DWORD *) dest_ptr) = 0xFF000000;
4419 dest_ptr += sizeof(DWORD);
4421 if(dest_conv) {
4422 *( (DWORD *) dest_conv) = 0xFF000000;
4423 dest_conv += sizeof(DWORD);
4426 else {
4427 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4428 if(dest_conv) {
4429 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4430 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4431 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4432 dest_conv += sizeof(DWORD);
4437 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4438 float *tex_coord =
4439 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4440 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4441 if(!tex_coord) {
4442 ERR("No source texture, but destination requests one\n");
4443 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4444 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4446 else {
4447 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4448 if(dest_conv) {
4449 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4455 if(dest_conv) {
4456 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4457 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4458 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4459 dwCount * get_flexible_vertex_size(DestFVF),
4460 dest_conv_addr));
4461 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4462 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4465 LEAVE_GL();
4467 return WINED3D_OK;
4469 #undef copy_and_next
4471 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4473 WineDirect3DVertexStridedData strided;
4474 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4475 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4477 if(pVertexDecl) {
4478 ERR("Output vertex declaration not implemented yet\n");
4481 /* Need any context to write to the vbo. */
4482 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4484 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4485 * control the streamIsUP flag, thus restore it afterwards.
4487 This->stateBlock->streamIsUP = FALSE;
4488 memset(&strided, 0, sizeof(strided));
4489 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4490 This->stateBlock->streamIsUP = streamWasUP;
4492 if(vbo || SrcStartIndex) {
4493 unsigned int i;
4494 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4495 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4497 * Also get the start index in, but only loop over all elements if there's something to add at all.
4499 #define FIXSRC(type) \
4500 if(strided.u.s.type.VBO) { \
4501 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4502 strided.u.s.type.VBO = 0; \
4503 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4504 ENTER_GL(); \
4505 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4506 vb->vbo = 0; \
4507 LEAVE_GL(); \
4509 if(strided.u.s.type.lpData) { \
4510 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4512 FIXSRC(position);
4513 FIXSRC(blendWeights);
4514 FIXSRC(blendMatrixIndices);
4515 FIXSRC(normal);
4516 FIXSRC(pSize);
4517 FIXSRC(diffuse);
4518 FIXSRC(specular);
4519 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4520 FIXSRC(texCoords[i]);
4522 FIXSRC(position2);
4523 FIXSRC(normal2);
4524 FIXSRC(tangent);
4525 FIXSRC(binormal);
4526 FIXSRC(tessFactor);
4527 FIXSRC(fog);
4528 FIXSRC(depth);
4529 FIXSRC(sample);
4530 #undef FIXSRC
4533 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4536 /*****
4537 * Get / Set Texture Stage States
4538 * TODO: Verify against dx9 definitions
4539 *****/
4540 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4542 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4544 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4546 if (Stage >= MAX_TEXTURES) {
4547 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4548 return WINED3D_OK;
4551 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4552 This->updateStateBlock->textureState[Stage][Type] = Value;
4554 if (This->isRecordingState) {
4555 TRACE("Recording... not performing anything\n");
4556 return WINED3D_OK;
4559 /* Checked after the assignments to allow proper stateblock recording */
4560 if(oldValue == Value) {
4561 TRACE("App is setting the old value over, nothing to do\n");
4562 return WINED3D_OK;
4565 if(Stage > This->stateBlock->lowest_disabled_stage &&
4566 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4567 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4568 * Changes in other states are important on disabled stages too
4570 return WINED3D_OK;
4573 if(Type == WINED3DTSS_COLOROP) {
4574 int i;
4576 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4577 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4578 * they have to be disabled
4580 * The current stage is dirtified below.
4582 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4583 TRACE("Additionally dirtifying stage %d\n", i);
4584 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4586 This->stateBlock->lowest_disabled_stage = Stage;
4587 TRACE("New lowest disabled: %d\n", Stage);
4588 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4589 /* Previously disabled stage enabled. Stages above it may need enabling
4590 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4591 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4593 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4596 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4597 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4598 break;
4600 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4601 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4603 This->stateBlock->lowest_disabled_stage = i;
4604 TRACE("New lowest disabled: %d\n", i);
4606 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4607 /* TODO: Built a stage -> texture unit mapping for register combiners */
4611 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4613 return WINED3D_OK;
4616 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4618 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4619 *pValue = This->updateStateBlock->textureState[Stage][Type];
4620 return WINED3D_OK;
4623 /*****
4624 * Get / Set Texture
4625 *****/
4626 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4628 IWineD3DBaseTexture *oldTexture;
4630 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4632 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4633 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4636 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4637 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4638 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4641 oldTexture = This->updateStateBlock->textures[Stage];
4643 if(pTexture != NULL) {
4644 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4646 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4647 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4648 return WINED3DERR_INVALIDCALL;
4650 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4653 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4654 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4656 This->updateStateBlock->changed.textures[Stage] = TRUE;
4657 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4658 This->updateStateBlock->textures[Stage] = pTexture;
4660 /* Handle recording of state blocks */
4661 if (This->isRecordingState) {
4662 TRACE("Recording... not performing anything\n");
4663 return WINED3D_OK;
4666 if(oldTexture == pTexture) {
4667 TRACE("App is setting the same texture again, nothing to do\n");
4668 return WINED3D_OK;
4671 /** NOTE: MSDN says that setTexture increases the reference count,
4672 * and that the application must set the texture back to null (or have a leaky application),
4673 * This means we should pass the refcount up to the parent
4674 *******************************/
4675 if (NULL != This->updateStateBlock->textures[Stage]) {
4676 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4677 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4679 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4680 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4681 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4682 * so the COLOROP and ALPHAOP have to be dirtified.
4684 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4685 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4687 if(bindCount == 1) {
4688 new->baseTexture.sampler = Stage;
4690 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4694 if (NULL != oldTexture) {
4695 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4696 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4698 IWineD3DBaseTexture_Release(oldTexture);
4699 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4700 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4701 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4704 if(bindCount && old->baseTexture.sampler == Stage) {
4705 int i;
4706 /* Have to do a search for the other sampler(s) where the texture is bound to
4707 * Shouldn't happen as long as apps bind a texture only to one stage
4709 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4710 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4711 if(This->updateStateBlock->textures[i] == oldTexture) {
4712 old->baseTexture.sampler = i;
4713 break;
4719 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4721 return WINED3D_OK;
4724 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4727 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4729 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4730 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4733 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4734 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4735 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4738 *ppTexture=This->stateBlock->textures[Stage];
4739 if (*ppTexture)
4740 IWineD3DBaseTexture_AddRef(*ppTexture);
4742 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4744 return WINED3D_OK;
4747 /*****
4748 * Get Back Buffer
4749 *****/
4750 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4751 IWineD3DSurface **ppBackBuffer) {
4752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4753 IWineD3DSwapChain *swapChain;
4754 HRESULT hr;
4756 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4758 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4759 if (hr == WINED3D_OK) {
4760 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4761 IWineD3DSwapChain_Release(swapChain);
4762 } else {
4763 *ppBackBuffer = NULL;
4765 return hr;
4768 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4770 WARN("(%p) : stub, calling idirect3d for now\n", This);
4771 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4774 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4776 IWineD3DSwapChain *swapChain;
4777 HRESULT hr;
4779 if(iSwapChain > 0) {
4780 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4781 if (hr == WINED3D_OK) {
4782 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4783 IWineD3DSwapChain_Release(swapChain);
4784 } else {
4785 FIXME("(%p) Error getting display mode\n", This);
4787 } else {
4788 /* Don't read the real display mode,
4789 but return the stored mode instead. X11 can't change the color
4790 depth, and some apps are pretty angry if they SetDisplayMode from
4791 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4793 Also don't relay to the swapchain because with ddraw it's possible
4794 that there isn't a swapchain at all */
4795 pMode->Width = This->ddraw_width;
4796 pMode->Height = This->ddraw_height;
4797 pMode->Format = This->ddraw_format;
4798 pMode->RefreshRate = 0;
4799 hr = WINED3D_OK;
4802 return hr;
4805 /*****
4806 * Stateblock related functions
4807 *****/
4809 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4811 IWineD3DStateBlockImpl *object;
4812 HRESULT temp_result;
4813 int i;
4815 TRACE("(%p)\n", This);
4817 if (This->isRecordingState) {
4818 return WINED3DERR_INVALIDCALL;
4821 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4822 if (NULL == object ) {
4823 FIXME("(%p)Error allocating memory for stateblock\n", This);
4824 return E_OUTOFMEMORY;
4826 TRACE("(%p) created object %p\n", This, object);
4827 object->wineD3DDevice= This;
4828 /** FIXME: object->parent = parent; **/
4829 object->parent = NULL;
4830 object->blockType = WINED3DSBT_RECORDED;
4831 object->ref = 1;
4832 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4834 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4835 list_init(&object->lightMap[i]);
4838 temp_result = allocate_shader_constants(object);
4839 if (WINED3D_OK != temp_result)
4840 return temp_result;
4842 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4843 This->updateStateBlock = object;
4844 This->isRecordingState = TRUE;
4846 TRACE("(%p) recording stateblock %p\n",This , object);
4847 return WINED3D_OK;
4850 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4852 unsigned int i, j;
4853 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4855 if (!This->isRecordingState) {
4856 FIXME("(%p) not recording! returning error\n", This);
4857 *ppStateBlock = NULL;
4858 return WINED3DERR_INVALIDCALL;
4861 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4862 if(object->changed.renderState[i]) {
4863 object->contained_render_states[object->num_contained_render_states] = i;
4864 object->num_contained_render_states++;
4867 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4868 if(object->changed.transform[i]) {
4869 object->contained_transform_states[object->num_contained_transform_states] = i;
4870 object->num_contained_transform_states++;
4873 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4874 if(object->changed.vertexShaderConstantsF[i]) {
4875 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4876 object->num_contained_vs_consts_f++;
4879 for(i = 0; i < MAX_CONST_I; i++) {
4880 if(object->changed.vertexShaderConstantsI[i]) {
4881 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4882 object->num_contained_vs_consts_i++;
4885 for(i = 0; i < MAX_CONST_B; i++) {
4886 if(object->changed.vertexShaderConstantsB[i]) {
4887 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4888 object->num_contained_vs_consts_b++;
4891 for(i = 0; i < MAX_CONST_I; i++) {
4892 if(object->changed.pixelShaderConstantsI[i]) {
4893 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4894 object->num_contained_ps_consts_i++;
4897 for(i = 0; i < MAX_CONST_B; i++) {
4898 if(object->changed.pixelShaderConstantsB[i]) {
4899 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4900 object->num_contained_ps_consts_b++;
4903 for(i = 0; i < MAX_TEXTURES; i++) {
4904 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4905 if(object->changed.textureState[i][j]) {
4906 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4907 object->contained_tss_states[object->num_contained_tss_states].state = j;
4908 object->num_contained_tss_states++;
4912 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4913 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4914 if(object->changed.samplerState[i][j]) {
4915 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4916 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4917 object->num_contained_sampler_states++;
4922 *ppStateBlock = (IWineD3DStateBlock*) object;
4923 This->isRecordingState = FALSE;
4924 This->updateStateBlock = This->stateBlock;
4925 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4926 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4927 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4928 return WINED3D_OK;
4931 /*****
4932 * Scene related functions
4933 *****/
4934 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4935 /* At the moment we have no need for any functionality at the beginning
4936 of a scene */
4937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4938 TRACE("(%p)\n", This);
4940 if(This->inScene) {
4941 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4942 return WINED3DERR_INVALIDCALL;
4944 This->inScene = TRUE;
4945 return WINED3D_OK;
4948 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4950 TRACE("(%p)\n", This);
4952 if(!This->inScene) {
4953 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4954 return WINED3DERR_INVALIDCALL;
4957 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4958 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4959 glFlush();
4960 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4961 * fails
4964 This->inScene = FALSE;
4965 return WINED3D_OK;
4968 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4969 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4970 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4972 IWineD3DSwapChain *swapChain = NULL;
4973 int i;
4974 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4976 TRACE("(%p) Presenting the frame\n", This);
4978 for(i = 0 ; i < swapchains ; i ++) {
4980 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4981 TRACE("presentinng chain %d, %p\n", i, swapChain);
4982 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4983 IWineD3DSwapChain_Release(swapChain);
4986 return WINED3D_OK;
4989 /* Not called from the VTable (internal subroutine) */
4990 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4991 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4992 float Z, DWORD Stencil) {
4993 GLbitfield glMask = 0;
4994 unsigned int i;
4995 WINED3DRECT curRect;
4996 RECT vp_rect;
4997 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4998 UINT drawable_width, drawable_height;
4999 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5001 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5002 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5003 * for the cleared parts, and the untouched parts.
5005 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5006 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5007 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5008 * checking all this if the dest surface is in the drawable anyway.
5010 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5011 while(1) {
5012 if(vp->X != 0 || vp->Y != 0 ||
5013 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5014 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5015 break;
5017 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5018 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5019 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5020 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5021 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5022 break;
5024 if(Count > 0 && pRects && (
5025 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5026 pRects[0].x2 < target->currentDesc.Width ||
5027 pRects[0].y2 < target->currentDesc.Height)) {
5028 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5029 break;
5031 break;
5035 target->get_drawable_size(target, &drawable_width, &drawable_height);
5037 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5038 ENTER_GL();
5040 /* Only set the values up once, as they are not changing */
5041 if (Flags & WINED3DCLEAR_STENCIL) {
5042 glClearStencil(Stencil);
5043 checkGLcall("glClearStencil");
5044 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5045 glStencilMask(0xFFFFFFFF);
5048 if (Flags & WINED3DCLEAR_ZBUFFER) {
5049 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5050 glDepthMask(GL_TRUE);
5051 glClearDepth(Z);
5052 checkGLcall("glClearDepth");
5053 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5054 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5056 if (vp->X != 0 || vp->Y != 0 ||
5057 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5058 surface_load_ds_location(This->stencilBufferTarget, location);
5060 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5061 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5062 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5063 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5064 surface_load_ds_location(This->stencilBufferTarget, location);
5066 else if (Count > 0 && pRects && (
5067 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5068 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5069 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5070 surface_load_ds_location(This->stencilBufferTarget, location);
5074 if (Flags & WINED3DCLEAR_TARGET) {
5075 TRACE("Clearing screen with glClear to color %x\n", Color);
5076 glClearColor(D3DCOLOR_R(Color),
5077 D3DCOLOR_G(Color),
5078 D3DCOLOR_B(Color),
5079 D3DCOLOR_A(Color));
5080 checkGLcall("glClearColor");
5082 /* Clear ALL colors! */
5083 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5084 glMask = glMask | GL_COLOR_BUFFER_BIT;
5087 vp_rect.left = vp->X;
5088 vp_rect.top = vp->Y;
5089 vp_rect.right = vp->X + vp->Width;
5090 vp_rect.bottom = vp->Y + vp->Height;
5091 if (!(Count > 0 && pRects)) {
5092 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5093 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5095 if(This->render_offscreen) {
5096 glScissor(vp_rect.left, vp_rect.top,
5097 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5098 } else {
5099 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5100 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5102 checkGLcall("glScissor");
5103 glClear(glMask);
5104 checkGLcall("glClear");
5105 } else {
5106 /* Now process each rect in turn */
5107 for (i = 0; i < Count; i++) {
5108 /* Note gl uses lower left, width/height */
5109 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5110 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5111 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5113 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5114 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5115 curRect.x1, (target->currentDesc.Height - curRect.y2),
5116 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5118 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5119 * The rectangle is not cleared, no error is returned, but further rectanlges are
5120 * still cleared if they are valid
5122 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5123 TRACE("Rectangle with negative dimensions, ignoring\n");
5124 continue;
5127 if(This->render_offscreen) {
5128 glScissor(curRect.x1, curRect.y1,
5129 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5130 } else {
5131 glScissor(curRect.x1, drawable_height - curRect.y2,
5132 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5134 checkGLcall("glScissor");
5136 glClear(glMask);
5137 checkGLcall("glClear");
5141 /* Restore the old values (why..?) */
5142 if (Flags & WINED3DCLEAR_STENCIL) {
5143 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5145 if (Flags & WINED3DCLEAR_TARGET) {
5146 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5147 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5148 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5149 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5150 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5152 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5153 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5155 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5156 /* TODO: Move the fbo logic into ModifyLocation() */
5157 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5158 target->Flags |= SFLAG_INTEXTURE;
5161 if (Flags & WINED3DCLEAR_ZBUFFER) {
5162 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5163 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5164 surface_modify_ds_location(This->stencilBufferTarget, location);
5167 LEAVE_GL();
5169 return WINED3D_OK;
5172 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5173 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5175 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5177 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5178 Count, pRects, Flags, Color, Z, Stencil);
5180 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5181 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5182 /* TODO: What about depth stencil buffers without stencil bits? */
5183 return WINED3DERR_INVALIDCALL;
5186 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5189 /*****
5190 * Drawing functions
5191 *****/
5192 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5193 UINT PrimitiveCount) {
5195 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5197 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5198 debug_d3dprimitivetype(PrimitiveType),
5199 StartVertex, PrimitiveCount);
5201 if(!This->stateBlock->vertexDecl) {
5202 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5203 return WINED3DERR_INVALIDCALL;
5206 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5207 if(This->stateBlock->streamIsUP) {
5208 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5209 This->stateBlock->streamIsUP = FALSE;
5212 if(This->stateBlock->loadBaseVertexIndex != 0) {
5213 This->stateBlock->loadBaseVertexIndex = 0;
5214 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5216 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5217 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5218 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5219 return WINED3D_OK;
5222 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5223 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5224 WINED3DPRIMITIVETYPE PrimitiveType,
5225 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5228 UINT idxStride = 2;
5229 IWineD3DIndexBuffer *pIB;
5230 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5231 GLuint vbo;
5233 pIB = This->stateBlock->pIndexData;
5234 if (!pIB) {
5235 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5236 * without an index buffer set. (The first time at least...)
5237 * D3D8 simply dies, but I doubt it can do much harm to return
5238 * D3DERR_INVALIDCALL there as well. */
5239 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5240 return WINED3DERR_INVALIDCALL;
5243 if(!This->stateBlock->vertexDecl) {
5244 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5245 return WINED3DERR_INVALIDCALL;
5248 if(This->stateBlock->streamIsUP) {
5249 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5250 This->stateBlock->streamIsUP = FALSE;
5252 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5254 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5255 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5256 minIndex, NumVertices, startIndex, primCount);
5258 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5259 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5260 idxStride = 2;
5261 } else {
5262 idxStride = 4;
5265 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5266 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5267 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5270 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5271 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5273 return WINED3D_OK;
5276 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5277 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5278 UINT VertexStreamZeroStride) {
5279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5280 IWineD3DVertexBuffer *vb;
5282 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5283 debug_d3dprimitivetype(PrimitiveType),
5284 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5286 if(!This->stateBlock->vertexDecl) {
5287 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5288 return WINED3DERR_INVALIDCALL;
5291 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5292 vb = This->stateBlock->streamSource[0];
5293 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5294 if(vb) IWineD3DVertexBuffer_Release(vb);
5295 This->stateBlock->streamOffset[0] = 0;
5296 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5297 This->stateBlock->streamIsUP = TRUE;
5298 This->stateBlock->loadBaseVertexIndex = 0;
5300 /* TODO: Only mark dirty if drawing from a different UP address */
5301 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5303 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5304 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5306 /* MSDN specifies stream zero settings must be set to NULL */
5307 This->stateBlock->streamStride[0] = 0;
5308 This->stateBlock->streamSource[0] = NULL;
5310 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5311 * the new stream sources or use UP drawing again
5313 return WINED3D_OK;
5316 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5317 UINT MinVertexIndex, UINT NumVertices,
5318 UINT PrimitiveCount, CONST void* pIndexData,
5319 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5320 UINT VertexStreamZeroStride) {
5321 int idxStride;
5322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5323 IWineD3DVertexBuffer *vb;
5324 IWineD3DIndexBuffer *ib;
5326 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5327 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5328 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5329 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5331 if(!This->stateBlock->vertexDecl) {
5332 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5333 return WINED3DERR_INVALIDCALL;
5336 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5337 idxStride = 2;
5338 } else {
5339 idxStride = 4;
5342 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5343 vb = This->stateBlock->streamSource[0];
5344 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5345 if(vb) IWineD3DVertexBuffer_Release(vb);
5346 This->stateBlock->streamIsUP = TRUE;
5347 This->stateBlock->streamOffset[0] = 0;
5348 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5350 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5351 This->stateBlock->baseVertexIndex = 0;
5352 This->stateBlock->loadBaseVertexIndex = 0;
5353 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5354 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5355 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5357 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5359 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5360 This->stateBlock->streamSource[0] = NULL;
5361 This->stateBlock->streamStride[0] = 0;
5362 ib = This->stateBlock->pIndexData;
5363 if(ib) {
5364 IWineD3DIndexBuffer_Release(ib);
5365 This->stateBlock->pIndexData = NULL;
5367 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5368 * SetStreamSource to specify a vertex buffer
5371 return WINED3D_OK;
5374 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5377 /* Mark the state dirty until we have nicer tracking
5378 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5379 * that value.
5381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5382 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5383 This->stateBlock->baseVertexIndex = 0;
5384 This->up_strided = DrawPrimStrideData;
5385 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5386 This->up_strided = NULL;
5387 return WINED3D_OK;
5390 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5392 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5394 /* Mark the state dirty until we have nicer tracking
5395 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5396 * that value.
5398 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5399 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5400 This->stateBlock->streamIsUP = TRUE;
5401 This->stateBlock->baseVertexIndex = 0;
5402 This->up_strided = DrawPrimStrideData;
5403 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5404 This->up_strided = NULL;
5405 return WINED3D_OK;
5408 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5409 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5410 * not callable by the app directly no parameter validation checks are needed here.
5412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5413 WINED3DLOCKED_BOX src;
5414 WINED3DLOCKED_BOX dst;
5415 HRESULT hr;
5416 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5418 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5419 * dirtification to improve loading performance.
5421 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5422 if(FAILED(hr)) return hr;
5423 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5424 if(FAILED(hr)) {
5425 IWineD3DVolume_UnlockBox(pSourceVolume);
5426 return hr;
5429 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5431 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5432 if(FAILED(hr)) {
5433 IWineD3DVolume_UnlockBox(pSourceVolume);
5434 } else {
5435 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5437 return hr;
5440 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5441 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5443 HRESULT hr = WINED3D_OK;
5444 WINED3DRESOURCETYPE sourceType;
5445 WINED3DRESOURCETYPE destinationType;
5446 int i ,levels;
5448 /* TODO: think about moving the code into IWineD3DBaseTexture */
5450 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5452 /* verify that the source and destination textures aren't NULL */
5453 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5454 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5455 This, pSourceTexture, pDestinationTexture);
5456 hr = WINED3DERR_INVALIDCALL;
5459 if (pSourceTexture == pDestinationTexture) {
5460 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5461 This, pSourceTexture, pDestinationTexture);
5462 hr = WINED3DERR_INVALIDCALL;
5464 /* Verify that the source and destination textures are the same type */
5465 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5466 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5468 if (sourceType != destinationType) {
5469 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5470 This);
5471 hr = WINED3DERR_INVALIDCALL;
5474 /* check that both textures have the identical numbers of levels */
5475 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5476 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5477 hr = WINED3DERR_INVALIDCALL;
5480 if (WINED3D_OK == hr) {
5482 /* Make sure that the destination texture is loaded */
5483 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5485 /* Update every surface level of the texture */
5486 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5488 switch (sourceType) {
5489 case WINED3DRTYPE_TEXTURE:
5491 IWineD3DSurface *srcSurface;
5492 IWineD3DSurface *destSurface;
5494 for (i = 0 ; i < levels ; ++i) {
5495 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5496 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5497 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5498 IWineD3DSurface_Release(srcSurface);
5499 IWineD3DSurface_Release(destSurface);
5500 if (WINED3D_OK != hr) {
5501 WARN("(%p) : Call to update surface failed\n", This);
5502 return hr;
5506 break;
5507 case WINED3DRTYPE_CUBETEXTURE:
5509 IWineD3DSurface *srcSurface;
5510 IWineD3DSurface *destSurface;
5511 WINED3DCUBEMAP_FACES faceType;
5513 for (i = 0 ; i < levels ; ++i) {
5514 /* Update each cube face */
5515 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5516 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5517 if (WINED3D_OK != hr) {
5518 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5519 } else {
5520 TRACE("Got srcSurface %p\n", srcSurface);
5522 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5523 if (WINED3D_OK != hr) {
5524 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5525 } else {
5526 TRACE("Got desrSurface %p\n", destSurface);
5528 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5529 IWineD3DSurface_Release(srcSurface);
5530 IWineD3DSurface_Release(destSurface);
5531 if (WINED3D_OK != hr) {
5532 WARN("(%p) : Call to update surface failed\n", This);
5533 return hr;
5538 break;
5540 case WINED3DRTYPE_VOLUMETEXTURE:
5542 IWineD3DVolume *srcVolume = NULL;
5543 IWineD3DVolume *destVolume = NULL;
5545 for (i = 0 ; i < levels ; ++i) {
5546 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5547 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5548 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5549 IWineD3DVolume_Release(srcVolume);
5550 IWineD3DVolume_Release(destVolume);
5551 if (WINED3D_OK != hr) {
5552 WARN("(%p) : Call to update volume failed\n", This);
5553 return hr;
5557 break;
5559 default:
5560 FIXME("(%p) : Unsupported source and destination type\n", This);
5561 hr = WINED3DERR_INVALIDCALL;
5565 return hr;
5568 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5569 IWineD3DSwapChain *swapChain;
5570 HRESULT hr;
5571 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5572 if(hr == WINED3D_OK) {
5573 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5574 IWineD3DSwapChain_Release(swapChain);
5576 return hr;
5579 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5581 /* return a sensible default */
5582 *pNumPasses = 1;
5583 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5584 FIXME("(%p) : stub\n", This);
5585 return WINED3D_OK;
5588 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5590 int i;
5592 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5593 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5594 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5595 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5600 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5602 int j;
5603 UINT NewSize;
5604 PALETTEENTRY **palettes;
5606 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5608 if (PaletteNumber >= MAX_PALETTES) {
5609 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5610 return WINED3DERR_INVALIDCALL;
5613 if (PaletteNumber >= This->NumberOfPalettes) {
5614 NewSize = This->NumberOfPalettes;
5615 do {
5616 NewSize *= 2;
5617 } while(PaletteNumber >= NewSize);
5618 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5619 if (!palettes) {
5620 ERR("Out of memory!\n");
5621 return E_OUTOFMEMORY;
5623 This->palettes = palettes;
5624 This->NumberOfPalettes = NewSize;
5627 if (!This->palettes[PaletteNumber]) {
5628 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5629 if (!This->palettes[PaletteNumber]) {
5630 ERR("Out of memory!\n");
5631 return E_OUTOFMEMORY;
5635 for (j = 0; j < 256; ++j) {
5636 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5637 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5638 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5639 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5641 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5642 TRACE("(%p) : returning\n", This);
5643 return WINED3D_OK;
5646 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5647 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5648 int j;
5649 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5650 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5651 /* What happens in such situation isn't documented; Native seems to silently abort
5652 on such conditions. Return Invalid Call. */
5653 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5654 return WINED3DERR_INVALIDCALL;
5656 for (j = 0; j < 256; ++j) {
5657 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5658 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5659 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5660 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5662 TRACE("(%p) : returning\n", This);
5663 return WINED3D_OK;
5666 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5668 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5669 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5670 (tested with reference rasterizer). Return Invalid Call. */
5671 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5672 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5673 return WINED3DERR_INVALIDCALL;
5675 /*TODO: stateblocks */
5676 if (This->currentPalette != PaletteNumber) {
5677 This->currentPalette = PaletteNumber;
5678 dirtify_p8_texture_samplers(This);
5680 TRACE("(%p) : returning\n", This);
5681 return WINED3D_OK;
5684 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5686 if (PaletteNumber == NULL) {
5687 WARN("(%p) : returning Invalid Call\n", This);
5688 return WINED3DERR_INVALIDCALL;
5690 /*TODO: stateblocks */
5691 *PaletteNumber = This->currentPalette;
5692 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5693 return WINED3D_OK;
5696 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5698 static BOOL showFixmes = TRUE;
5699 if (showFixmes) {
5700 FIXME("(%p) : stub\n", This);
5701 showFixmes = FALSE;
5704 This->softwareVertexProcessing = bSoftware;
5705 return WINED3D_OK;
5709 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5711 static BOOL showFixmes = TRUE;
5712 if (showFixmes) {
5713 FIXME("(%p) : stub\n", This);
5714 showFixmes = FALSE;
5716 return This->softwareVertexProcessing;
5720 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5722 IWineD3DSwapChain *swapChain;
5723 HRESULT hr;
5725 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5727 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5728 if(hr == WINED3D_OK){
5729 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5730 IWineD3DSwapChain_Release(swapChain);
5731 }else{
5732 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5734 return hr;
5738 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5740 static BOOL showfixmes = TRUE;
5741 if(nSegments != 0.0f) {
5742 if( showfixmes) {
5743 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5744 showfixmes = FALSE;
5747 return WINED3D_OK;
5750 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5752 static BOOL showfixmes = TRUE;
5753 if( showfixmes) {
5754 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5755 showfixmes = FALSE;
5757 return 0.0f;
5760 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5762 /** TODO: remove casts to IWineD3DSurfaceImpl
5763 * NOTE: move code to surface to accomplish this
5764 ****************************************/
5765 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5766 int srcWidth, srcHeight;
5767 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5768 WINED3DFORMAT destFormat, srcFormat;
5769 UINT destSize;
5770 int srcLeft, destLeft, destTop;
5771 WINED3DPOOL srcPool, destPool;
5772 int offset = 0;
5773 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5774 glDescriptor *glDescription = NULL;
5775 GLenum dummy;
5776 int sampler;
5777 int bpp;
5778 CONVERT_TYPES convert = NO_CONVERSION;
5780 WINED3DSURFACE_DESC winedesc;
5782 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5783 memset(&winedesc, 0, sizeof(winedesc));
5784 winedesc.Width = &srcSurfaceWidth;
5785 winedesc.Height = &srcSurfaceHeight;
5786 winedesc.Pool = &srcPool;
5787 winedesc.Format = &srcFormat;
5789 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5791 winedesc.Width = &destSurfaceWidth;
5792 winedesc.Height = &destSurfaceHeight;
5793 winedesc.Pool = &destPool;
5794 winedesc.Format = &destFormat;
5795 winedesc.Size = &destSize;
5797 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5799 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5800 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5801 return WINED3DERR_INVALIDCALL;
5804 /* This call loads the opengl surface directly, instead of copying the surface to the
5805 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5806 * copy in sysmem and use regular surface loading.
5808 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5809 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5810 if(convert != NO_CONVERSION) {
5811 return IWineD3DSurface_BltFast(pDestinationSurface,
5812 pDestPoint ? pDestPoint->x : 0,
5813 pDestPoint ? pDestPoint->y : 0,
5814 pSourceSurface, (RECT *) pSourceRect, 0);
5817 if (destFormat == WINED3DFMT_UNKNOWN) {
5818 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5819 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5821 /* Get the update surface description */
5822 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5825 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5827 ENTER_GL();
5829 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5830 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5831 checkGLcall("glActiveTextureARB");
5834 /* Make sure the surface is loaded and up to date */
5835 IWineD3DSurface_PreLoad(pDestinationSurface);
5837 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5839 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5840 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5841 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5842 srcLeft = pSourceRect ? pSourceRect->left : 0;
5843 destLeft = pDestPoint ? pDestPoint->x : 0;
5844 destTop = pDestPoint ? pDestPoint->y : 0;
5847 /* This function doesn't support compressed textures
5848 the pitch is just bytesPerPixel * width */
5849 if(srcWidth != srcSurfaceWidth || srcLeft ){
5850 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5851 offset += srcLeft * pSrcSurface->bytesPerPixel;
5852 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5854 /* TODO DXT formats */
5856 if(pSourceRect != NULL && pSourceRect->top != 0){
5857 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5859 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5860 ,This
5861 ,glDescription->level
5862 ,destLeft
5863 ,destTop
5864 ,srcWidth
5865 ,srcHeight
5866 ,glDescription->glFormat
5867 ,glDescription->glType
5868 ,IWineD3DSurface_GetData(pSourceSurface)
5871 /* Sanity check */
5872 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5874 /* need to lock the surface to get the data */
5875 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5878 /* TODO: Cube and volume support */
5879 if(rowoffset != 0){
5880 /* not a whole row so we have to do it a line at a time */
5881 int j;
5883 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5884 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5886 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5888 glTexSubImage2D(glDescription->target
5889 ,glDescription->level
5890 ,destLeft
5892 ,srcWidth
5894 ,glDescription->glFormat
5895 ,glDescription->glType
5896 ,data /* could be quicker using */
5898 data += rowoffset;
5901 } else { /* Full width, so just write out the whole texture */
5903 if (WINED3DFMT_DXT1 == destFormat ||
5904 WINED3DFMT_DXT2 == destFormat ||
5905 WINED3DFMT_DXT3 == destFormat ||
5906 WINED3DFMT_DXT4 == destFormat ||
5907 WINED3DFMT_DXT5 == destFormat) {
5908 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5909 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5910 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5911 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5912 } if (destFormat != srcFormat) {
5913 FIXME("Updating mixed format compressed texture is not curretly support\n");
5914 } else {
5915 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5916 glDescription->level,
5917 glDescription->glFormatInternal,
5918 srcWidth,
5919 srcHeight,
5921 destSize,
5922 IWineD3DSurface_GetData(pSourceSurface));
5924 } else {
5925 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5929 } else {
5930 glTexSubImage2D(glDescription->target
5931 ,glDescription->level
5932 ,destLeft
5933 ,destTop
5934 ,srcWidth
5935 ,srcHeight
5936 ,glDescription->glFormat
5937 ,glDescription->glType
5938 ,IWineD3DSurface_GetData(pSourceSurface)
5942 checkGLcall("glTexSubImage2D");
5944 LEAVE_GL();
5946 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5947 sampler = This->rev_tex_unit_map[0];
5948 if (sampler != -1) {
5949 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5952 return WINED3D_OK;
5955 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5957 struct WineD3DRectPatch *patch;
5958 unsigned int i;
5959 struct list *e;
5960 BOOL found;
5961 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5963 if(!(Handle || pRectPatchInfo)) {
5964 /* TODO: Write a test for the return value, thus the FIXME */
5965 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5966 return WINED3DERR_INVALIDCALL;
5969 if(Handle) {
5970 i = PATCHMAP_HASHFUNC(Handle);
5971 found = FALSE;
5972 LIST_FOR_EACH(e, &This->patches[i]) {
5973 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5974 if(patch->Handle == Handle) {
5975 found = TRUE;
5976 break;
5980 if(!found) {
5981 TRACE("Patch does not exist. Creating a new one\n");
5982 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5983 patch->Handle = Handle;
5984 list_add_head(&This->patches[i], &patch->entry);
5985 } else {
5986 TRACE("Found existing patch %p\n", patch);
5988 } else {
5989 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5990 * attributes we have to tesselate, read back, and draw. This needs a patch
5991 * management structure instance. Create one.
5993 * A possible improvement is to check if a vertex shader is used, and if not directly
5994 * draw the patch.
5996 FIXME("Drawing an uncached patch. This is slow\n");
5997 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6000 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6001 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6002 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6003 HRESULT hr;
6004 TRACE("Tesselation density or patch info changed, retesselating\n");
6006 if(pRectPatchInfo) {
6007 patch->RectPatchInfo = *pRectPatchInfo;
6009 patch->numSegs[0] = pNumSegs[0];
6010 patch->numSegs[1] = pNumSegs[1];
6011 patch->numSegs[2] = pNumSegs[2];
6012 patch->numSegs[3] = pNumSegs[3];
6014 hr = tesselate_rectpatch(This, patch);
6015 if(FAILED(hr)) {
6016 WARN("Patch tesselation failed\n");
6018 /* Do not release the handle to store the params of the patch */
6019 if(!Handle) {
6020 HeapFree(GetProcessHeap(), 0, patch);
6022 return hr;
6026 This->currentPatch = patch;
6027 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6028 This->currentPatch = NULL;
6030 /* Destroy uncached patches */
6031 if(!Handle) {
6032 HeapFree(GetProcessHeap(), 0, patch->mem);
6033 HeapFree(GetProcessHeap(), 0, patch);
6035 return WINED3D_OK;
6038 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6040 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6041 FIXME("(%p) : Stub\n", This);
6042 return WINED3D_OK;
6045 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6046 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6047 int i;
6048 struct WineD3DRectPatch *patch;
6049 struct list *e;
6050 TRACE("(%p) Handle(%d)\n", This, Handle);
6052 i = PATCHMAP_HASHFUNC(Handle);
6053 LIST_FOR_EACH(e, &This->patches[i]) {
6054 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6055 if(patch->Handle == Handle) {
6056 TRACE("Deleting patch %p\n", patch);
6057 list_remove(&patch->entry);
6058 HeapFree(GetProcessHeap(), 0, patch->mem);
6059 HeapFree(GetProcessHeap(), 0, patch);
6060 return WINED3D_OK;
6064 /* TODO: Write a test for the return value */
6065 FIXME("Attempt to destroy nonexistent patch\n");
6066 return WINED3DERR_INVALIDCALL;
6069 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6070 HRESULT hr;
6071 IWineD3DSwapChain *swapchain;
6073 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6074 if (SUCCEEDED(hr)) {
6075 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6076 return swapchain;
6079 return NULL;
6082 void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
6083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6085 if (!*fbo) {
6086 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
6087 checkGLcall("glGenFramebuffersEXT()");
6089 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
6090 checkGLcall("glBindFramebuffer()");
6093 /* TODO: Handle stencil attachments */
6094 void attach_depth_stencil_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, IWineD3DSurface *depth_stencil, BOOL use_render_buffer) {
6095 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6097 if (use_render_buffer && depth_stencil_impl->current_renderbuffer) {
6098 GL_EXTCALL(glFramebufferRenderbufferEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6099 checkGLcall("glFramebufferRenderbufferEXT()");
6100 } else {
6101 IWineD3DBaseTextureImpl *texture_impl;
6102 GLenum texttarget, target;
6103 GLint old_binding = 0;
6105 texttarget = depth_stencil_impl->glDescription.target;
6106 if(texttarget == GL_TEXTURE_2D) {
6107 target = GL_TEXTURE_2D;
6108 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6109 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6110 target = GL_TEXTURE_RECTANGLE_ARB;
6111 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6112 } else {
6113 target = GL_TEXTURE_CUBE_MAP_ARB;
6114 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6117 IWineD3DSurface_PreLoad(depth_stencil);
6119 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6120 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6121 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6122 glBindTexture(target, old_binding);
6124 /* Update base texture states array */
6125 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6126 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6127 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6128 if (texture_impl->baseTexture.bindCount) {
6129 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6132 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6135 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6136 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6137 checkGLcall("glFramebufferTexture2DEXT()");
6141 void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
6142 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
6143 IWineD3DBaseTextureImpl *texture_impl;
6144 GLenum texttarget, target;
6145 GLint old_binding;
6147 texttarget = surface_impl->glDescription.target;
6148 if(texttarget == GL_TEXTURE_2D) {
6149 target = GL_TEXTURE_2D;
6150 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6151 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6152 target = GL_TEXTURE_RECTANGLE_ARB;
6153 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6154 } else {
6155 target = GL_TEXTURE_CUBE_MAP_ARB;
6156 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6159 IWineD3DSurface_PreLoad(surface);
6161 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6162 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6163 glBindTexture(target, old_binding);
6165 /* Update base texture states array */
6166 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6167 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6168 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6169 if (texture_impl->baseTexture.bindCount) {
6170 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6173 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6176 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6177 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6179 checkGLcall("attach_surface_fbo");
6182 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6184 IWineD3DSwapChain *swapchain;
6186 swapchain = get_swapchain(surface);
6187 if (swapchain) {
6188 GLenum buffer;
6190 TRACE("Surface %p is onscreen\n", surface);
6192 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6193 ENTER_GL();
6194 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6195 buffer = surface_get_gl_buffer(surface, swapchain);
6196 glDrawBuffer(buffer);
6197 checkGLcall("glDrawBuffer()");
6198 } else {
6199 TRACE("Surface %p is offscreen\n", surface);
6201 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6202 ENTER_GL();
6203 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6204 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6205 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6206 checkGLcall("glFramebufferRenderbufferEXT");
6209 if (rect) {
6210 glEnable(GL_SCISSOR_TEST);
6211 if(!swapchain) {
6212 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6213 } else {
6214 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6215 rect->x2 - rect->x1, rect->y2 - rect->y1);
6217 checkGLcall("glScissor");
6218 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6219 } else {
6220 glDisable(GL_SCISSOR_TEST);
6222 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6224 glDisable(GL_BLEND);
6225 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6227 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6228 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6230 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6231 glClear(GL_COLOR_BUFFER_BIT);
6232 checkGLcall("glClear");
6234 if (This->render_offscreen) {
6235 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->fbo);
6236 } else {
6237 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6238 checkGLcall("glBindFramebuffer()");
6241 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6242 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6243 glDrawBuffer(GL_BACK);
6244 checkGLcall("glDrawBuffer()");
6247 LEAVE_GL();
6250 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6251 unsigned int r, g, b, a;
6252 DWORD ret;
6254 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6255 destfmt == WINED3DFMT_R8G8B8)
6256 return color;
6258 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6260 a = (color & 0xff000000) >> 24;
6261 r = (color & 0x00ff0000) >> 16;
6262 g = (color & 0x0000ff00) >> 8;
6263 b = (color & 0x000000ff) >> 0;
6265 switch(destfmt)
6267 case WINED3DFMT_R5G6B5:
6268 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6269 r = (r * 32) / 256;
6270 g = (g * 64) / 256;
6271 b = (b * 32) / 256;
6272 ret = r << 11;
6273 ret |= g << 5;
6274 ret |= b;
6275 TRACE("Returning %08x\n", ret);
6276 return ret;
6278 case WINED3DFMT_X1R5G5B5:
6279 case WINED3DFMT_A1R5G5B5:
6280 a = (a * 2) / 256;
6281 r = (r * 32) / 256;
6282 g = (g * 32) / 256;
6283 b = (b * 32) / 256;
6284 ret = a << 15;
6285 ret |= r << 10;
6286 ret |= g << 5;
6287 ret |= b << 0;
6288 TRACE("Returning %08x\n", ret);
6289 return ret;
6291 case WINED3DFMT_A8:
6292 TRACE("Returning %08x\n", a);
6293 return a;
6295 case WINED3DFMT_X4R4G4B4:
6296 case WINED3DFMT_A4R4G4B4:
6297 a = (a * 16) / 256;
6298 r = (r * 16) / 256;
6299 g = (g * 16) / 256;
6300 b = (b * 16) / 256;
6301 ret = a << 12;
6302 ret |= r << 8;
6303 ret |= g << 4;
6304 ret |= b << 0;
6305 TRACE("Returning %08x\n", ret);
6306 return ret;
6308 case WINED3DFMT_R3G3B2:
6309 r = (r * 8) / 256;
6310 g = (g * 8) / 256;
6311 b = (b * 4) / 256;
6312 ret = r << 5;
6313 ret |= g << 2;
6314 ret |= b << 0;
6315 TRACE("Returning %08x\n", ret);
6316 return ret;
6318 case WINED3DFMT_X8B8G8R8:
6319 case WINED3DFMT_A8B8G8R8:
6320 ret = a << 24;
6321 ret |= b << 16;
6322 ret |= g << 8;
6323 ret |= r << 0;
6324 TRACE("Returning %08x\n", ret);
6325 return ret;
6327 case WINED3DFMT_A2R10G10B10:
6328 a = (a * 4) / 256;
6329 r = (r * 1024) / 256;
6330 g = (g * 1024) / 256;
6331 b = (b * 1024) / 256;
6332 ret = a << 30;
6333 ret |= r << 20;
6334 ret |= g << 10;
6335 ret |= b << 0;
6336 TRACE("Returning %08x\n", ret);
6337 return ret;
6339 case WINED3DFMT_A2B10G10R10:
6340 a = (a * 4) / 256;
6341 r = (r * 1024) / 256;
6342 g = (g * 1024) / 256;
6343 b = (b * 1024) / 256;
6344 ret = a << 30;
6345 ret |= b << 20;
6346 ret |= g << 10;
6347 ret |= r << 0;
6348 TRACE("Returning %08x\n", ret);
6349 return ret;
6351 default:
6352 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6353 return 0;
6357 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6359 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6360 WINEDDBLTFX BltFx;
6361 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6363 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6364 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6365 return WINED3DERR_INVALIDCALL;
6368 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6369 color_fill_fbo(iface, pSurface, pRect, color);
6370 return WINED3D_OK;
6371 } else {
6372 /* Just forward this to the DirectDraw blitting engine */
6373 memset(&BltFx, 0, sizeof(BltFx));
6374 BltFx.dwSize = sizeof(BltFx);
6375 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6376 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6380 /* rendertarget and depth stencil functions */
6381 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6384 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6385 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6386 return WINED3DERR_INVALIDCALL;
6389 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6390 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6391 /* Note inc ref on returned surface */
6392 if(*ppRenderTarget != NULL)
6393 IWineD3DSurface_AddRef(*ppRenderTarget);
6394 return WINED3D_OK;
6397 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6399 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6400 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6401 IWineD3DSwapChainImpl *Swapchain;
6402 HRESULT hr;
6404 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6406 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6407 if(hr != WINED3D_OK) {
6408 ERR("Can't get the swapchain\n");
6409 return hr;
6412 /* Make sure to release the swapchain */
6413 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6415 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6416 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6417 return WINED3DERR_INVALIDCALL;
6419 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6420 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6421 return WINED3DERR_INVALIDCALL;
6424 if(Swapchain->frontBuffer != Front) {
6425 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6427 if(Swapchain->frontBuffer)
6428 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6429 Swapchain->frontBuffer = Front;
6431 if(Swapchain->frontBuffer) {
6432 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6436 if(Back && !Swapchain->backBuffer) {
6437 /* We need memory for the back buffer array - only one back buffer this way */
6438 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6439 if(!Swapchain->backBuffer) {
6440 ERR("Out of memory\n");
6441 return E_OUTOFMEMORY;
6445 if(Swapchain->backBuffer[0] != Back) {
6446 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6448 /* What to do about the context here in the case of multithreading? Not sure.
6449 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6451 ENTER_GL();
6452 if(!Swapchain->backBuffer[0]) {
6453 /* GL was told to draw to the front buffer at creation,
6454 * undo that
6456 glDrawBuffer(GL_BACK);
6457 checkGLcall("glDrawBuffer(GL_BACK)");
6458 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6459 Swapchain->presentParms.BackBufferCount = 1;
6460 } else if (!Back) {
6461 /* That makes problems - disable for now */
6462 /* glDrawBuffer(GL_FRONT); */
6463 checkGLcall("glDrawBuffer(GL_FRONT)");
6464 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6465 Swapchain->presentParms.BackBufferCount = 0;
6467 LEAVE_GL();
6469 if(Swapchain->backBuffer[0])
6470 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6471 Swapchain->backBuffer[0] = Back;
6473 if(Swapchain->backBuffer[0]) {
6474 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6475 } else {
6476 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6477 Swapchain->backBuffer = NULL;
6482 return WINED3D_OK;
6485 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6487 *ppZStencilSurface = This->stencilBufferTarget;
6488 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6490 if(*ppZStencilSurface != NULL) {
6491 /* Note inc ref on returned surface */
6492 IWineD3DSurface_AddRef(*ppZStencilSurface);
6493 return WINED3D_OK;
6494 } else {
6495 return WINED3DERR_NOTFOUND;
6499 /* TODO: Handle stencil attachments */
6500 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6503 TRACE("Set depth stencil to %p\n", depth_stencil);
6505 if (depth_stencil) {
6506 attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, depth_stencil, TRUE);
6507 } else {
6508 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6509 checkGLcall("glFramebufferTexture2DEXT()");
6513 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6516 TRACE("Set render target %u to %p\n", idx, render_target);
6518 if (render_target) {
6519 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6520 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6521 } else {
6522 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6523 checkGLcall("glFramebufferTexture2DEXT()");
6525 This->draw_buffers[idx] = GL_NONE;
6529 static void check_fbo_status(IWineD3DDevice *iface) {
6530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6531 GLenum status;
6533 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6534 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6535 TRACE("FBO complete\n");
6536 } else {
6537 IWineD3DSurfaceImpl *attachment;
6538 int i;
6539 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6541 /* Dump the FBO attachments */
6542 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6543 attachment = (IWineD3DSurfaceImpl *)This->activeContext->fbo_color_attachments[i];
6544 if (attachment) {
6545 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6546 attachment->pow2Width, attachment->pow2Height);
6549 attachment = (IWineD3DSurfaceImpl *)This->activeContext->fbo_depth_attachment;
6550 if (attachment) {
6551 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6552 attachment->pow2Width, attachment->pow2Height);
6557 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6559 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6560 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6562 if (!ds_impl) return FALSE;
6564 if (ds_impl->current_renderbuffer) {
6565 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6566 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6569 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6570 rt_impl->pow2Height != ds_impl->pow2Height);
6573 void apply_fbo_state(IWineD3DDevice *iface) {
6574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6575 WineD3DContext *context = This->activeContext;
6576 unsigned int i;
6578 if (This->render_offscreen) {
6579 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &context->fbo);
6581 /* Apply render targets */
6582 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6583 IWineD3DSurface *render_target = This->render_targets[i];
6584 if (context->fbo_color_attachments[i] != render_target) {
6585 set_render_target_fbo(iface, i, render_target);
6586 context->fbo_color_attachments[i] = render_target;
6590 /* Apply depth targets */
6591 if (context->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6592 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6593 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6595 if (This->stencilBufferTarget) {
6596 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6598 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6599 context->fbo_depth_attachment = This->stencilBufferTarget;
6601 } else {
6602 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6605 check_fbo_status(iface);
6608 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6609 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6611 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6612 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6613 GLenum gl_filter;
6614 POINT offset = {0, 0};
6616 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6617 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6618 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6619 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6621 switch (filter) {
6622 case WINED3DTEXF_LINEAR:
6623 gl_filter = GL_LINEAR;
6624 break;
6626 default:
6627 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6628 case WINED3DTEXF_NONE:
6629 case WINED3DTEXF_POINT:
6630 gl_filter = GL_NEAREST;
6631 break;
6634 /* Attach src surface to src fbo */
6635 src_swapchain = get_swapchain(src_surface);
6636 if (src_swapchain) {
6637 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6639 TRACE("Source surface %p is onscreen\n", src_surface);
6640 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6641 /* Make sure the drawable is up to date. In the offscreen case
6642 * attach_surface_fbo() implicitly takes care of this. */
6643 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6645 if(buffer == GL_FRONT) {
6646 RECT windowsize;
6647 UINT h;
6648 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6649 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6650 h = windowsize.bottom - windowsize.top;
6651 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6652 src_rect->y1 = offset.y + h - src_rect->y1;
6653 src_rect->y2 = offset.y + h - src_rect->y2;
6654 } else {
6655 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6656 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6659 ENTER_GL();
6660 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6661 glReadBuffer(buffer);
6662 checkGLcall("glReadBuffer()");
6663 } else {
6664 TRACE("Source surface %p is offscreen\n", src_surface);
6665 ENTER_GL();
6666 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6667 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6668 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6669 checkGLcall("glReadBuffer()");
6670 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6671 checkGLcall("glFramebufferRenderbufferEXT");
6673 LEAVE_GL();
6675 /* Attach dst surface to dst fbo */
6676 dst_swapchain = get_swapchain(dst_surface);
6677 if (dst_swapchain) {
6678 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6680 TRACE("Destination surface %p is onscreen\n", dst_surface);
6681 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6682 /* Make sure the drawable is up to date. In the offscreen case
6683 * attach_surface_fbo() implicitly takes care of this. */
6684 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6686 if(buffer == GL_FRONT) {
6687 RECT windowsize;
6688 UINT h;
6689 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6690 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6691 h = windowsize.bottom - windowsize.top;
6692 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6693 dst_rect->y1 = offset.y + h - dst_rect->y1;
6694 dst_rect->y2 = offset.y + h - dst_rect->y2;
6695 } else {
6696 /* Screen coords = window coords, surface height = window height */
6697 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6698 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6701 ENTER_GL();
6702 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6703 glDrawBuffer(buffer);
6704 checkGLcall("glDrawBuffer()");
6705 } else {
6706 TRACE("Destination surface %p is offscreen\n", dst_surface);
6708 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6709 if(!src_swapchain) {
6710 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6713 ENTER_GL();
6714 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6715 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6716 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6717 checkGLcall("glDrawBuffer()");
6718 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6719 checkGLcall("glFramebufferRenderbufferEXT");
6721 glDisable(GL_SCISSOR_TEST);
6722 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6724 if (flip) {
6725 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6726 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6727 checkGLcall("glBlitFramebuffer()");
6728 } else {
6729 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6730 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6731 checkGLcall("glBlitFramebuffer()");
6734 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6736 if (This->render_offscreen) {
6737 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->fbo);
6738 } else {
6739 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6740 checkGLcall("glBindFramebuffer()");
6743 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6744 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6745 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6746 glDrawBuffer(GL_BACK);
6747 checkGLcall("glDrawBuffer()");
6749 LEAVE_GL();
6752 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6754 WINED3DVIEWPORT viewport;
6756 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6758 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6759 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6760 This, RenderTargetIndex, GL_LIMITS(buffers));
6761 return WINED3DERR_INVALIDCALL;
6764 /* MSDN says that null disables the render target
6765 but a device must always be associated with a render target
6766 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6768 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6769 FIXME("Trying to set render target 0 to NULL\n");
6770 return WINED3DERR_INVALIDCALL;
6772 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6773 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);
6774 return WINED3DERR_INVALIDCALL;
6777 /* If we are trying to set what we already have, don't bother */
6778 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6779 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6780 return WINED3D_OK;
6782 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6783 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6784 This->render_targets[RenderTargetIndex] = pRenderTarget;
6786 /* Render target 0 is special */
6787 if(RenderTargetIndex == 0) {
6788 /* Finally, reset the viewport as the MSDN states. */
6789 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6790 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6791 viewport.X = 0;
6792 viewport.Y = 0;
6793 viewport.MaxZ = 1.0f;
6794 viewport.MinZ = 0.0f;
6795 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6796 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6797 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6799 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6801 return WINED3D_OK;
6804 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6806 HRESULT hr = WINED3D_OK;
6807 IWineD3DSurface *tmp;
6809 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6811 if (pNewZStencil == This->stencilBufferTarget) {
6812 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6813 } else {
6814 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6815 * depending on the renter target implementation being used.
6816 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6817 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6818 * stencil buffer and incur an extra memory overhead
6819 ******************************************************/
6821 if (This->stencilBufferTarget) {
6822 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6823 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6824 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6827 tmp = This->stencilBufferTarget;
6828 This->stencilBufferTarget = pNewZStencil;
6829 /* should we be calling the parent or the wined3d surface? */
6830 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6831 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6832 hr = WINED3D_OK;
6834 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6835 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6836 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6837 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6838 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6842 return hr;
6845 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6846 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6848 /* TODO: the use of Impl is deprecated. */
6849 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6850 WINED3DLOCKED_RECT lockedRect;
6852 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6854 /* some basic validation checks */
6855 if(This->cursorTexture) {
6856 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6857 ENTER_GL();
6858 glDeleteTextures(1, &This->cursorTexture);
6859 LEAVE_GL();
6860 This->cursorTexture = 0;
6863 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6864 This->haveHardwareCursor = TRUE;
6865 else
6866 This->haveHardwareCursor = FALSE;
6868 if(pCursorBitmap) {
6869 WINED3DLOCKED_RECT rect;
6871 /* MSDN: Cursor must be A8R8G8B8 */
6872 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6873 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6874 return WINED3DERR_INVALIDCALL;
6877 /* MSDN: Cursor must be smaller than the display mode */
6878 if(pSur->currentDesc.Width > This->ddraw_width ||
6879 pSur->currentDesc.Height > This->ddraw_height) {
6880 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);
6881 return WINED3DERR_INVALIDCALL;
6884 if (!This->haveHardwareCursor) {
6885 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6887 /* Do not store the surface's pointer because the application may
6888 * release it after setting the cursor image. Windows doesn't
6889 * addref the set surface, so we can't do this either without
6890 * creating circular refcount dependencies. Copy out the gl texture
6891 * instead.
6893 This->cursorWidth = pSur->currentDesc.Width;
6894 This->cursorHeight = pSur->currentDesc.Height;
6895 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6897 const GlPixelFormatDesc *glDesc;
6898 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6899 char *mem, *bits = (char *)rect.pBits;
6900 GLint intfmt = glDesc->glInternal;
6901 GLint format = glDesc->glFormat;
6902 GLint type = glDesc->glType;
6903 INT height = This->cursorHeight;
6904 INT width = This->cursorWidth;
6905 INT bpp = tableEntry->bpp;
6906 INT i, sampler;
6908 /* Reformat the texture memory (pitch and width can be
6909 * different) */
6910 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6911 for(i = 0; i < height; i++)
6912 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6913 IWineD3DSurface_UnlockRect(pCursorBitmap);
6914 ENTER_GL();
6916 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6917 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6918 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6921 /* Make sure that a proper texture unit is selected */
6922 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6923 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6924 checkGLcall("glActiveTextureARB");
6926 sampler = This->rev_tex_unit_map[0];
6927 if (sampler != -1) {
6928 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6930 /* Create a new cursor texture */
6931 glGenTextures(1, &This->cursorTexture);
6932 checkGLcall("glGenTextures");
6933 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6934 checkGLcall("glBindTexture");
6935 /* Copy the bitmap memory into the cursor texture */
6936 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6937 HeapFree(GetProcessHeap(), 0, mem);
6938 checkGLcall("glTexImage2D");
6940 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6941 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6942 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6945 LEAVE_GL();
6947 else
6949 FIXME("A cursor texture was not returned.\n");
6950 This->cursorTexture = 0;
6953 else
6955 /* Draw a hardware cursor */
6956 ICONINFO cursorInfo;
6957 HCURSOR cursor;
6958 /* Create and clear maskBits because it is not needed for
6959 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6960 * chunks. */
6961 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6962 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6963 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6964 WINED3DLOCK_NO_DIRTY_UPDATE |
6965 WINED3DLOCK_READONLY
6967 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6968 pSur->currentDesc.Height);
6970 cursorInfo.fIcon = FALSE;
6971 cursorInfo.xHotspot = XHotSpot;
6972 cursorInfo.yHotspot = YHotSpot;
6973 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6974 pSur->currentDesc.Height, 1,
6975 1, &maskBits);
6976 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6977 pSur->currentDesc.Height, 1,
6978 32, lockedRect.pBits);
6979 IWineD3DSurface_UnlockRect(pCursorBitmap);
6980 /* Create our cursor and clean up. */
6981 cursor = CreateIconIndirect(&cursorInfo);
6982 SetCursor(cursor);
6983 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6984 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6985 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6986 This->hardwareCursor = cursor;
6987 HeapFree(GetProcessHeap(), 0, maskBits);
6991 This->xHotSpot = XHotSpot;
6992 This->yHotSpot = YHotSpot;
6993 return WINED3D_OK;
6996 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6998 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7000 This->xScreenSpace = XScreenSpace;
7001 This->yScreenSpace = YScreenSpace;
7003 return;
7007 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7009 BOOL oldVisible = This->bCursorVisible;
7010 POINT pt;
7012 TRACE("(%p) : visible(%d)\n", This, bShow);
7015 * When ShowCursor is first called it should make the cursor appear at the OS's last
7016 * known cursor position. Because of this, some applications just repetitively call
7017 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7019 GetCursorPos(&pt);
7020 This->xScreenSpace = pt.x;
7021 This->yScreenSpace = pt.y;
7023 if (This->haveHardwareCursor) {
7024 This->bCursorVisible = bShow;
7025 if (bShow)
7026 SetCursor(This->hardwareCursor);
7027 else
7028 SetCursor(NULL);
7030 else
7032 if (This->cursorTexture)
7033 This->bCursorVisible = bShow;
7036 return oldVisible;
7039 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7041 IWineD3DResourceImpl *resource;
7042 TRACE("(%p) : state (%u)\n", This, This->state);
7044 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7045 switch (This->state) {
7046 case WINED3D_OK:
7047 return WINED3D_OK;
7048 case WINED3DERR_DEVICELOST:
7050 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7051 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7052 return WINED3DERR_DEVICENOTRESET;
7054 return WINED3DERR_DEVICELOST;
7056 case WINED3DERR_DRIVERINTERNALERROR:
7057 return WINED3DERR_DRIVERINTERNALERROR;
7060 /* Unknown state */
7061 return WINED3DERR_DRIVERINTERNALERROR;
7065 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7067 /** FIXME: Resource tracking needs to be done,
7068 * The closes we can do to this is set the priorities of all managed textures low
7069 * and then reset them.
7070 ***********************************************************/
7071 FIXME("(%p) : stub\n", This);
7072 return WINED3D_OK;
7075 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7076 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7078 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7079 if(surface->Flags & SFLAG_DIBSECTION) {
7080 /* Release the DC */
7081 SelectObject(surface->hDC, surface->dib.holdbitmap);
7082 DeleteDC(surface->hDC);
7083 /* Release the DIB section */
7084 DeleteObject(surface->dib.DIBsection);
7085 surface->dib.bitmap_data = NULL;
7086 surface->resource.allocatedMemory = NULL;
7087 surface->Flags &= ~SFLAG_DIBSECTION;
7089 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7090 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7091 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7092 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7093 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7094 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7095 } else {
7096 surface->pow2Width = surface->pow2Height = 1;
7097 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7098 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7100 surface->glRect.left = 0;
7101 surface->glRect.top = 0;
7102 surface->glRect.right = surface->pow2Width;
7103 surface->glRect.bottom = surface->pow2Height;
7105 if(surface->glDescription.textureName) {
7106 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7107 ENTER_GL();
7108 glDeleteTextures(1, &surface->glDescription.textureName);
7109 LEAVE_GL();
7110 surface->glDescription.textureName = 0;
7111 surface->Flags &= ~SFLAG_CLIENT;
7113 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7114 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7115 surface->Flags |= SFLAG_NONPOW2;
7116 } else {
7117 surface->Flags &= ~SFLAG_NONPOW2;
7119 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7120 surface->resource.allocatedMemory = NULL;
7121 surface->resource.heapMemory = NULL;
7122 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7123 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7124 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7125 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7126 } else {
7127 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7131 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7132 TRACE("Unloading resource %p\n", resource);
7133 IWineD3DResource_UnLoad(resource);
7134 IWineD3DResource_Release(resource);
7135 return S_OK;
7138 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7139 UINT i, count;
7140 WINED3DDISPLAYMODE m;
7141 HRESULT hr;
7143 /* All Windowed modes are supported, as is leaving the current mode */
7144 if(pp->Windowed) return TRUE;
7145 if(!pp->BackBufferWidth) return TRUE;
7146 if(!pp->BackBufferHeight) return TRUE;
7148 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7149 for(i = 0; i < count; i++) {
7150 memset(&m, 0, sizeof(m));
7151 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7152 if(FAILED(hr)) {
7153 ERR("EnumAdapterModes failed\n");
7155 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7156 /* Mode found, it is supported */
7157 return TRUE;
7160 /* Mode not found -> not supported */
7161 return FALSE;
7164 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7166 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7167 UINT i;
7168 IWineD3DBaseShaderImpl *shader;
7170 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7171 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7172 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7175 ENTER_GL();
7176 if(This->depth_blt_texture) {
7177 glDeleteTextures(1, &This->depth_blt_texture);
7178 This->depth_blt_texture = 0;
7180 if (This->depth_blt_rb) {
7181 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7182 This->depth_blt_rb = 0;
7183 This->depth_blt_rb_w = 0;
7184 This->depth_blt_rb_h = 0;
7186 This->blitter->free_private(iface);
7187 This->frag_pipe->free_private(iface);
7188 This->shader_backend->shader_free_private(iface);
7190 for (i = 0; i < GL_LIMITS(textures); i++) {
7191 /* Textures are recreated below */
7192 glDeleteTextures(1, &This->dummyTextureName[i]);
7193 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7194 This->dummyTextureName[i] = 0;
7196 LEAVE_GL();
7198 while(This->numContexts) {
7199 DestroyContext(This, This->contexts[0]);
7201 This->activeContext = NULL;
7202 HeapFree(GetProcessHeap(), 0, swapchain->context);
7203 swapchain->context = NULL;
7204 swapchain->num_contexts = 0;
7207 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7209 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7210 HRESULT hr;
7211 IWineD3DSurfaceImpl *target;
7213 /* Recreate the primary swapchain's context */
7214 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7215 if(swapchain->backBuffer) {
7216 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7217 } else {
7218 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7220 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7221 &swapchain->presentParms);
7222 swapchain->num_contexts = 1;
7223 This->activeContext = swapchain->context[0];
7225 create_dummy_textures(This);
7227 hr = This->shader_backend->shader_alloc_private(iface);
7228 if(FAILED(hr)) {
7229 ERR("Failed to recreate shader private data\n");
7230 goto err_out;
7232 hr = This->frag_pipe->alloc_private(iface);
7233 if(FAILED(hr)) {
7234 TRACE("Fragment pipeline private data couldn't be allocated\n");
7235 goto err_out;
7237 hr = This->blitter->alloc_private(iface);
7238 if(FAILED(hr)) {
7239 TRACE("Blitter private data couldn't be allocated\n");
7240 goto err_out;
7243 return WINED3D_OK;
7245 err_out:
7246 This->blitter->free_private(iface);
7247 This->frag_pipe->free_private(iface);
7248 This->shader_backend->shader_free_private(iface);
7249 return hr;
7252 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7253 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7254 IWineD3DSwapChainImpl *swapchain;
7255 HRESULT hr;
7256 BOOL DisplayModeChanged = FALSE;
7257 WINED3DDISPLAYMODE mode;
7258 TRACE("(%p)\n", This);
7260 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7261 if(FAILED(hr)) {
7262 ERR("Failed to get the first implicit swapchain\n");
7263 return hr;
7266 if(!is_display_mode_supported(This, pPresentationParameters)) {
7267 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7268 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7269 pPresentationParameters->BackBufferHeight);
7270 return WINED3DERR_INVALIDCALL;
7273 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7274 * on an existing gl context, so there's no real need for recreation.
7276 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7278 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7280 TRACE("New params:\n");
7281 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7282 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7283 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7284 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7285 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7286 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7287 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7288 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7289 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7290 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7291 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7292 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7293 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7295 /* No special treatment of these parameters. Just store them */
7296 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7297 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7298 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7299 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7301 /* What to do about these? */
7302 if(pPresentationParameters->BackBufferCount != 0 &&
7303 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7304 ERR("Cannot change the back buffer count yet\n");
7306 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7307 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7308 ERR("Cannot change the back buffer format yet\n");
7310 if(pPresentationParameters->hDeviceWindow != NULL &&
7311 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7312 ERR("Cannot change the device window yet\n");
7314 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7315 ERR("What do do about a changed auto depth stencil parameter?\n");
7318 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7320 if(pPresentationParameters->Windowed) {
7321 mode.Width = swapchain->orig_width;
7322 mode.Height = swapchain->orig_height;
7323 mode.RefreshRate = 0;
7324 mode.Format = swapchain->presentParms.BackBufferFormat;
7325 } else {
7326 mode.Width = pPresentationParameters->BackBufferWidth;
7327 mode.Height = pPresentationParameters->BackBufferHeight;
7328 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7329 mode.Format = swapchain->presentParms.BackBufferFormat;
7332 /* Should Width == 800 && Height == 0 set 800x600? */
7333 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7334 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7335 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7337 WINED3DVIEWPORT vp;
7338 int i;
7340 vp.X = 0;
7341 vp.Y = 0;
7342 vp.Width = pPresentationParameters->BackBufferWidth;
7343 vp.Height = pPresentationParameters->BackBufferHeight;
7344 vp.MinZ = 0;
7345 vp.MaxZ = 1;
7347 if(!pPresentationParameters->Windowed) {
7348 DisplayModeChanged = TRUE;
7350 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7351 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7353 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7354 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7355 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7357 if(This->auto_depth_stencil_buffer) {
7358 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7362 /* Now set the new viewport */
7363 IWineD3DDevice_SetViewport(iface, &vp);
7366 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7367 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7368 DisplayModeChanged) {
7370 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7372 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7373 if(swapchain->presentParms.Windowed) {
7374 /* switch from windowed to fs */
7375 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7376 pPresentationParameters->BackBufferWidth,
7377 pPresentationParameters->BackBufferHeight);
7378 } else {
7379 /* Fullscreen -> fullscreen mode change */
7380 MoveWindow(swapchain->win_handle, 0, 0,
7381 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7382 TRUE);
7384 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7385 /* Fullscreen -> windowed switch */
7386 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7388 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7389 } else if(!pPresentationParameters->Windowed) {
7390 DWORD style = This->style, exStyle = This->exStyle;
7391 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7392 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7393 * Reset to clear up their mess. Guild Wars also loses the device during that.
7395 This->style = 0;
7396 This->exStyle = 0;
7397 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7398 pPresentationParameters->BackBufferWidth,
7399 pPresentationParameters->BackBufferHeight);
7400 This->style = style;
7401 This->exStyle = exStyle;
7404 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7405 if(FAILED(hr)) {
7406 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7409 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7410 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7412 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7413 * first use
7415 return hr;
7418 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7420 /** FIXME: always true at the moment **/
7421 if(!bEnableDialogs) {
7422 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7424 return WINED3D_OK;
7428 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7430 TRACE("(%p) : pParameters %p\n", This, pParameters);
7432 *pParameters = This->createParms;
7433 return WINED3D_OK;
7436 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7437 IWineD3DSwapChain *swapchain;
7439 TRACE("Relaying to swapchain\n");
7441 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7442 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7443 IWineD3DSwapChain_Release(swapchain);
7445 return;
7448 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7449 IWineD3DSwapChain *swapchain;
7451 TRACE("Relaying to swapchain\n");
7453 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7454 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7455 IWineD3DSwapChain_Release(swapchain);
7457 return;
7461 /** ********************************************************
7462 * Notification functions
7463 ** ********************************************************/
7464 /** This function must be called in the release of a resource when ref == 0,
7465 * the contents of resource must still be correct,
7466 * any handles to other resource held by the caller must be closed
7467 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7468 *****************************************************/
7469 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7470 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7472 TRACE("(%p) : Adding Resource %p\n", This, resource);
7473 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7476 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7479 TRACE("(%p) : Removing resource %p\n", This, resource);
7481 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7485 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7487 int counter;
7489 TRACE("(%p) : resource %p\n", This, resource);
7490 switch(IWineD3DResource_GetType(resource)){
7491 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7492 case WINED3DRTYPE_SURFACE: {
7493 unsigned int i;
7495 /* Cleanup any FBO attachments if d3d is enabled */
7496 if(This->d3d_initialized) {
7497 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7498 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7500 TRACE("Last active render target destroyed\n");
7501 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7502 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7503 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7504 * and the lastActiveRenderTarget member shouldn't matter
7506 if(swapchain) {
7507 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7508 TRACE("Activating primary back buffer\n");
7509 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7510 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7511 /* Single buffering environment */
7512 TRACE("Activating primary front buffer\n");
7513 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7514 } else {
7515 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7516 /* Implicit render target destroyed, that means the device is being destroyed
7517 * whatever we set here, it shouldn't matter
7519 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7521 } else {
7522 /* May happen during ddraw uninitialization */
7523 TRACE("Render target set, but swapchain does not exist!\n");
7524 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7528 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7529 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7530 This->render_targets[i] = NULL;
7533 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7534 This->stencilBufferTarget = NULL;
7537 for (i = 0; i < This->numContexts; ++i) {
7538 int j;
7539 for (j = 0; j < GL_LIMITS(buffers); ++j) {
7540 if (This->contexts[i]->fbo_color_attachments[j] == (IWineD3DSurface *)resource) {
7541 This->contexts[i]->fbo_color_attachments[j] = NULL;
7544 if (This->contexts[i]->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7545 This->contexts[i]->fbo_depth_attachment = NULL;
7550 break;
7552 case WINED3DRTYPE_TEXTURE:
7553 case WINED3DRTYPE_CUBETEXTURE:
7554 case WINED3DRTYPE_VOLUMETEXTURE:
7555 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7556 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7557 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7558 This->stateBlock->textures[counter] = NULL;
7560 if (This->updateStateBlock != This->stateBlock ){
7561 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7562 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7563 This->updateStateBlock->textures[counter] = NULL;
7567 break;
7568 case WINED3DRTYPE_VOLUME:
7569 /* TODO: nothing really? */
7570 break;
7571 case WINED3DRTYPE_VERTEXBUFFER:
7572 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7574 int streamNumber;
7575 TRACE("Cleaning up stream pointers\n");
7577 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7578 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7579 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7581 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7582 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7583 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7584 This->updateStateBlock->streamSource[streamNumber] = 0;
7585 /* Set changed flag? */
7588 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) */
7589 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7590 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7591 This->stateBlock->streamSource[streamNumber] = 0;
7594 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7595 else { /* This shouldn't happen */
7596 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7598 #endif
7602 break;
7603 case WINED3DRTYPE_INDEXBUFFER:
7604 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7605 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7606 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7607 This->updateStateBlock->pIndexData = NULL;
7610 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7611 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7612 This->stateBlock->pIndexData = NULL;
7616 break;
7617 default:
7618 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7619 break;
7623 /* Remove the resource from the resourceStore */
7624 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7626 TRACE("Resource released\n");
7630 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7632 IWineD3DResourceImpl *resource, *cursor;
7633 HRESULT ret;
7634 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7636 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7637 TRACE("enumerating resource %p\n", resource);
7638 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7639 ret = pCallback((IWineD3DResource *) resource, pData);
7640 if(ret == S_FALSE) {
7641 TRACE("Canceling enumeration\n");
7642 break;
7645 return WINED3D_OK;
7648 /**********************************************************
7649 * IWineD3DDevice VTbl follows
7650 **********************************************************/
7652 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7654 /*** IUnknown methods ***/
7655 IWineD3DDeviceImpl_QueryInterface,
7656 IWineD3DDeviceImpl_AddRef,
7657 IWineD3DDeviceImpl_Release,
7658 /*** IWineD3DDevice methods ***/
7659 IWineD3DDeviceImpl_GetParent,
7660 /*** Creation methods**/
7661 IWineD3DDeviceImpl_CreateVertexBuffer,
7662 IWineD3DDeviceImpl_CreateIndexBuffer,
7663 IWineD3DDeviceImpl_CreateStateBlock,
7664 IWineD3DDeviceImpl_CreateSurface,
7665 IWineD3DDeviceImpl_CreateTexture,
7666 IWineD3DDeviceImpl_CreateVolumeTexture,
7667 IWineD3DDeviceImpl_CreateVolume,
7668 IWineD3DDeviceImpl_CreateCubeTexture,
7669 IWineD3DDeviceImpl_CreateQuery,
7670 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7671 IWineD3DDeviceImpl_CreateVertexDeclaration,
7672 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7673 IWineD3DDeviceImpl_CreateVertexShader,
7674 IWineD3DDeviceImpl_CreatePixelShader,
7675 IWineD3DDeviceImpl_CreatePalette,
7676 /*** Odd functions **/
7677 IWineD3DDeviceImpl_Init3D,
7678 IWineD3DDeviceImpl_InitGDI,
7679 IWineD3DDeviceImpl_Uninit3D,
7680 IWineD3DDeviceImpl_UninitGDI,
7681 IWineD3DDeviceImpl_SetMultithreaded,
7682 IWineD3DDeviceImpl_EvictManagedResources,
7683 IWineD3DDeviceImpl_GetAvailableTextureMem,
7684 IWineD3DDeviceImpl_GetBackBuffer,
7685 IWineD3DDeviceImpl_GetCreationParameters,
7686 IWineD3DDeviceImpl_GetDeviceCaps,
7687 IWineD3DDeviceImpl_GetDirect3D,
7688 IWineD3DDeviceImpl_GetDisplayMode,
7689 IWineD3DDeviceImpl_SetDisplayMode,
7690 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7691 IWineD3DDeviceImpl_GetRasterStatus,
7692 IWineD3DDeviceImpl_GetSwapChain,
7693 IWineD3DDeviceImpl_Reset,
7694 IWineD3DDeviceImpl_SetDialogBoxMode,
7695 IWineD3DDeviceImpl_SetCursorProperties,
7696 IWineD3DDeviceImpl_SetCursorPosition,
7697 IWineD3DDeviceImpl_ShowCursor,
7698 IWineD3DDeviceImpl_TestCooperativeLevel,
7699 /*** Getters and setters **/
7700 IWineD3DDeviceImpl_SetClipPlane,
7701 IWineD3DDeviceImpl_GetClipPlane,
7702 IWineD3DDeviceImpl_SetClipStatus,
7703 IWineD3DDeviceImpl_GetClipStatus,
7704 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7705 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7706 IWineD3DDeviceImpl_SetDepthStencilSurface,
7707 IWineD3DDeviceImpl_GetDepthStencilSurface,
7708 IWineD3DDeviceImpl_SetFVF,
7709 IWineD3DDeviceImpl_GetFVF,
7710 IWineD3DDeviceImpl_SetGammaRamp,
7711 IWineD3DDeviceImpl_GetGammaRamp,
7712 IWineD3DDeviceImpl_SetIndices,
7713 IWineD3DDeviceImpl_GetIndices,
7714 IWineD3DDeviceImpl_SetBaseVertexIndex,
7715 IWineD3DDeviceImpl_GetBaseVertexIndex,
7716 IWineD3DDeviceImpl_SetLight,
7717 IWineD3DDeviceImpl_GetLight,
7718 IWineD3DDeviceImpl_SetLightEnable,
7719 IWineD3DDeviceImpl_GetLightEnable,
7720 IWineD3DDeviceImpl_SetMaterial,
7721 IWineD3DDeviceImpl_GetMaterial,
7722 IWineD3DDeviceImpl_SetNPatchMode,
7723 IWineD3DDeviceImpl_GetNPatchMode,
7724 IWineD3DDeviceImpl_SetPaletteEntries,
7725 IWineD3DDeviceImpl_GetPaletteEntries,
7726 IWineD3DDeviceImpl_SetPixelShader,
7727 IWineD3DDeviceImpl_GetPixelShader,
7728 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7729 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7730 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7731 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7732 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7733 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7734 IWineD3DDeviceImpl_SetRenderState,
7735 IWineD3DDeviceImpl_GetRenderState,
7736 IWineD3DDeviceImpl_SetRenderTarget,
7737 IWineD3DDeviceImpl_GetRenderTarget,
7738 IWineD3DDeviceImpl_SetFrontBackBuffers,
7739 IWineD3DDeviceImpl_SetSamplerState,
7740 IWineD3DDeviceImpl_GetSamplerState,
7741 IWineD3DDeviceImpl_SetScissorRect,
7742 IWineD3DDeviceImpl_GetScissorRect,
7743 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7744 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7745 IWineD3DDeviceImpl_SetStreamSource,
7746 IWineD3DDeviceImpl_GetStreamSource,
7747 IWineD3DDeviceImpl_SetStreamSourceFreq,
7748 IWineD3DDeviceImpl_GetStreamSourceFreq,
7749 IWineD3DDeviceImpl_SetTexture,
7750 IWineD3DDeviceImpl_GetTexture,
7751 IWineD3DDeviceImpl_SetTextureStageState,
7752 IWineD3DDeviceImpl_GetTextureStageState,
7753 IWineD3DDeviceImpl_SetTransform,
7754 IWineD3DDeviceImpl_GetTransform,
7755 IWineD3DDeviceImpl_SetVertexDeclaration,
7756 IWineD3DDeviceImpl_GetVertexDeclaration,
7757 IWineD3DDeviceImpl_SetVertexShader,
7758 IWineD3DDeviceImpl_GetVertexShader,
7759 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7760 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7761 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7762 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7763 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7764 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7765 IWineD3DDeviceImpl_SetViewport,
7766 IWineD3DDeviceImpl_GetViewport,
7767 IWineD3DDeviceImpl_MultiplyTransform,
7768 IWineD3DDeviceImpl_ValidateDevice,
7769 IWineD3DDeviceImpl_ProcessVertices,
7770 /*** State block ***/
7771 IWineD3DDeviceImpl_BeginStateBlock,
7772 IWineD3DDeviceImpl_EndStateBlock,
7773 /*** Scene management ***/
7774 IWineD3DDeviceImpl_BeginScene,
7775 IWineD3DDeviceImpl_EndScene,
7776 IWineD3DDeviceImpl_Present,
7777 IWineD3DDeviceImpl_Clear,
7778 /*** Drawing ***/
7779 IWineD3DDeviceImpl_DrawPrimitive,
7780 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7781 IWineD3DDeviceImpl_DrawPrimitiveUP,
7782 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7783 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7784 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7785 IWineD3DDeviceImpl_DrawRectPatch,
7786 IWineD3DDeviceImpl_DrawTriPatch,
7787 IWineD3DDeviceImpl_DeletePatch,
7788 IWineD3DDeviceImpl_ColorFill,
7789 IWineD3DDeviceImpl_UpdateTexture,
7790 IWineD3DDeviceImpl_UpdateSurface,
7791 IWineD3DDeviceImpl_GetFrontBufferData,
7792 /*** object tracking ***/
7793 IWineD3DDeviceImpl_ResourceReleased,
7794 IWineD3DDeviceImpl_EnumResources
7797 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7799 /*** IUnknown methods ***/
7800 IWineD3DDeviceImpl_QueryInterface,
7801 IWineD3DDeviceImpl_AddRef,
7802 IWineD3DDeviceImpl_Release,
7803 /*** IWineD3DDevice methods ***/
7804 IWineD3DDeviceImpl_GetParent,
7805 /*** Creation methods**/
7806 IWineD3DDeviceImpl_CreateVertexBuffer,
7807 IWineD3DDeviceImpl_CreateIndexBuffer,
7808 IWineD3DDeviceImpl_CreateStateBlock,
7809 IWineD3DDeviceImpl_CreateSurface,
7810 IWineD3DDeviceImpl_CreateTexture,
7811 IWineD3DDeviceImpl_CreateVolumeTexture,
7812 IWineD3DDeviceImpl_CreateVolume,
7813 IWineD3DDeviceImpl_CreateCubeTexture,
7814 IWineD3DDeviceImpl_CreateQuery,
7815 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7816 IWineD3DDeviceImpl_CreateVertexDeclaration,
7817 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7818 IWineD3DDeviceImpl_CreateVertexShader,
7819 IWineD3DDeviceImpl_CreatePixelShader,
7820 IWineD3DDeviceImpl_CreatePalette,
7821 /*** Odd functions **/
7822 IWineD3DDeviceImpl_Init3D,
7823 IWineD3DDeviceImpl_InitGDI,
7824 IWineD3DDeviceImpl_Uninit3D,
7825 IWineD3DDeviceImpl_UninitGDI,
7826 IWineD3DDeviceImpl_SetMultithreaded,
7827 IWineD3DDeviceImpl_EvictManagedResources,
7828 IWineD3DDeviceImpl_GetAvailableTextureMem,
7829 IWineD3DDeviceImpl_GetBackBuffer,
7830 IWineD3DDeviceImpl_GetCreationParameters,
7831 IWineD3DDeviceImpl_GetDeviceCaps,
7832 IWineD3DDeviceImpl_GetDirect3D,
7833 IWineD3DDeviceImpl_GetDisplayMode,
7834 IWineD3DDeviceImpl_SetDisplayMode,
7835 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7836 IWineD3DDeviceImpl_GetRasterStatus,
7837 IWineD3DDeviceImpl_GetSwapChain,
7838 IWineD3DDeviceImpl_Reset,
7839 IWineD3DDeviceImpl_SetDialogBoxMode,
7840 IWineD3DDeviceImpl_SetCursorProperties,
7841 IWineD3DDeviceImpl_SetCursorPosition,
7842 IWineD3DDeviceImpl_ShowCursor,
7843 IWineD3DDeviceImpl_TestCooperativeLevel,
7844 /*** Getters and setters **/
7845 IWineD3DDeviceImpl_SetClipPlane,
7846 IWineD3DDeviceImpl_GetClipPlane,
7847 IWineD3DDeviceImpl_SetClipStatus,
7848 IWineD3DDeviceImpl_GetClipStatus,
7849 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7850 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7851 IWineD3DDeviceImpl_SetDepthStencilSurface,
7852 IWineD3DDeviceImpl_GetDepthStencilSurface,
7853 IWineD3DDeviceImpl_SetFVF,
7854 IWineD3DDeviceImpl_GetFVF,
7855 IWineD3DDeviceImpl_SetGammaRamp,
7856 IWineD3DDeviceImpl_GetGammaRamp,
7857 IWineD3DDeviceImpl_SetIndices,
7858 IWineD3DDeviceImpl_GetIndices,
7859 IWineD3DDeviceImpl_SetBaseVertexIndex,
7860 IWineD3DDeviceImpl_GetBaseVertexIndex,
7861 IWineD3DDeviceImpl_SetLight,
7862 IWineD3DDeviceImpl_GetLight,
7863 IWineD3DDeviceImpl_SetLightEnable,
7864 IWineD3DDeviceImpl_GetLightEnable,
7865 IWineD3DDeviceImpl_SetMaterial,
7866 IWineD3DDeviceImpl_GetMaterial,
7867 IWineD3DDeviceImpl_SetNPatchMode,
7868 IWineD3DDeviceImpl_GetNPatchMode,
7869 IWineD3DDeviceImpl_SetPaletteEntries,
7870 IWineD3DDeviceImpl_GetPaletteEntries,
7871 IWineD3DDeviceImpl_SetPixelShader,
7872 IWineD3DDeviceImpl_GetPixelShader,
7873 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7874 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7875 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7876 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7877 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7878 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7879 IWineD3DDeviceImpl_SetRenderState,
7880 IWineD3DDeviceImpl_GetRenderState,
7881 IWineD3DDeviceImpl_SetRenderTarget,
7882 IWineD3DDeviceImpl_GetRenderTarget,
7883 IWineD3DDeviceImpl_SetFrontBackBuffers,
7884 IWineD3DDeviceImpl_SetSamplerState,
7885 IWineD3DDeviceImpl_GetSamplerState,
7886 IWineD3DDeviceImpl_SetScissorRect,
7887 IWineD3DDeviceImpl_GetScissorRect,
7888 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7889 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7890 IWineD3DDeviceImpl_SetStreamSource,
7891 IWineD3DDeviceImpl_GetStreamSource,
7892 IWineD3DDeviceImpl_SetStreamSourceFreq,
7893 IWineD3DDeviceImpl_GetStreamSourceFreq,
7894 IWineD3DDeviceImpl_SetTexture,
7895 IWineD3DDeviceImpl_GetTexture,
7896 IWineD3DDeviceImpl_SetTextureStageState,
7897 IWineD3DDeviceImpl_GetTextureStageState,
7898 IWineD3DDeviceImpl_SetTransform,
7899 IWineD3DDeviceImpl_GetTransform,
7900 IWineD3DDeviceImpl_SetVertexDeclaration,
7901 IWineD3DDeviceImpl_GetVertexDeclaration,
7902 IWineD3DDeviceImpl_SetVertexShader,
7903 IWineD3DDeviceImpl_GetVertexShader,
7904 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7905 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7906 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7907 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7908 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7909 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7910 IWineD3DDeviceImpl_SetViewport,
7911 IWineD3DDeviceImpl_GetViewport,
7912 IWineD3DDeviceImpl_MultiplyTransform,
7913 IWineD3DDeviceImpl_ValidateDevice,
7914 IWineD3DDeviceImpl_ProcessVertices,
7915 /*** State block ***/
7916 IWineD3DDeviceImpl_BeginStateBlock,
7917 IWineD3DDeviceImpl_EndStateBlock,
7918 /*** Scene management ***/
7919 IWineD3DDeviceImpl_BeginScene,
7920 IWineD3DDeviceImpl_EndScene,
7921 IWineD3DDeviceImpl_Present,
7922 IWineD3DDeviceImpl_Clear,
7923 /*** Drawing ***/
7924 IWineD3DDeviceImpl_DrawPrimitive,
7925 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7926 IWineD3DDeviceImpl_DrawPrimitiveUP,
7927 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7928 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7929 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7930 IWineD3DDeviceImpl_DrawRectPatch,
7931 IWineD3DDeviceImpl_DrawTriPatch,
7932 IWineD3DDeviceImpl_DeletePatch,
7933 IWineD3DDeviceImpl_ColorFill,
7934 IWineD3DDeviceImpl_UpdateTexture,
7935 IWineD3DDeviceImpl_UpdateSurface,
7936 IWineD3DDeviceImpl_GetFrontBufferData,
7937 /*** object tracking ***/
7938 IWineD3DDeviceImpl_ResourceReleased,
7939 IWineD3DDeviceImpl_EnumResources
7942 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7943 WINED3DRS_ALPHABLENDENABLE ,
7944 WINED3DRS_ALPHAFUNC ,
7945 WINED3DRS_ALPHAREF ,
7946 WINED3DRS_ALPHATESTENABLE ,
7947 WINED3DRS_BLENDOP ,
7948 WINED3DRS_COLORWRITEENABLE ,
7949 WINED3DRS_DESTBLEND ,
7950 WINED3DRS_DITHERENABLE ,
7951 WINED3DRS_FILLMODE ,
7952 WINED3DRS_FOGDENSITY ,
7953 WINED3DRS_FOGEND ,
7954 WINED3DRS_FOGSTART ,
7955 WINED3DRS_LASTPIXEL ,
7956 WINED3DRS_SHADEMODE ,
7957 WINED3DRS_SRCBLEND ,
7958 WINED3DRS_STENCILENABLE ,
7959 WINED3DRS_STENCILFAIL ,
7960 WINED3DRS_STENCILFUNC ,
7961 WINED3DRS_STENCILMASK ,
7962 WINED3DRS_STENCILPASS ,
7963 WINED3DRS_STENCILREF ,
7964 WINED3DRS_STENCILWRITEMASK ,
7965 WINED3DRS_STENCILZFAIL ,
7966 WINED3DRS_TEXTUREFACTOR ,
7967 WINED3DRS_WRAP0 ,
7968 WINED3DRS_WRAP1 ,
7969 WINED3DRS_WRAP2 ,
7970 WINED3DRS_WRAP3 ,
7971 WINED3DRS_WRAP4 ,
7972 WINED3DRS_WRAP5 ,
7973 WINED3DRS_WRAP6 ,
7974 WINED3DRS_WRAP7 ,
7975 WINED3DRS_ZENABLE ,
7976 WINED3DRS_ZFUNC ,
7977 WINED3DRS_ZWRITEENABLE
7980 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7981 WINED3DTSS_ADDRESSW ,
7982 WINED3DTSS_ALPHAARG0 ,
7983 WINED3DTSS_ALPHAARG1 ,
7984 WINED3DTSS_ALPHAARG2 ,
7985 WINED3DTSS_ALPHAOP ,
7986 WINED3DTSS_BUMPENVLOFFSET ,
7987 WINED3DTSS_BUMPENVLSCALE ,
7988 WINED3DTSS_BUMPENVMAT00 ,
7989 WINED3DTSS_BUMPENVMAT01 ,
7990 WINED3DTSS_BUMPENVMAT10 ,
7991 WINED3DTSS_BUMPENVMAT11 ,
7992 WINED3DTSS_COLORARG0 ,
7993 WINED3DTSS_COLORARG1 ,
7994 WINED3DTSS_COLORARG2 ,
7995 WINED3DTSS_COLOROP ,
7996 WINED3DTSS_RESULTARG ,
7997 WINED3DTSS_TEXCOORDINDEX ,
7998 WINED3DTSS_TEXTURETRANSFORMFLAGS
8001 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8002 WINED3DSAMP_ADDRESSU ,
8003 WINED3DSAMP_ADDRESSV ,
8004 WINED3DSAMP_ADDRESSW ,
8005 WINED3DSAMP_BORDERCOLOR ,
8006 WINED3DSAMP_MAGFILTER ,
8007 WINED3DSAMP_MINFILTER ,
8008 WINED3DSAMP_MIPFILTER ,
8009 WINED3DSAMP_MIPMAPLODBIAS ,
8010 WINED3DSAMP_MAXMIPLEVEL ,
8011 WINED3DSAMP_MAXANISOTROPY ,
8012 WINED3DSAMP_SRGBTEXTURE ,
8013 WINED3DSAMP_ELEMENTINDEX
8016 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8017 WINED3DRS_AMBIENT ,
8018 WINED3DRS_AMBIENTMATERIALSOURCE ,
8019 WINED3DRS_CLIPPING ,
8020 WINED3DRS_CLIPPLANEENABLE ,
8021 WINED3DRS_COLORVERTEX ,
8022 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8023 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8024 WINED3DRS_FOGDENSITY ,
8025 WINED3DRS_FOGEND ,
8026 WINED3DRS_FOGSTART ,
8027 WINED3DRS_FOGTABLEMODE ,
8028 WINED3DRS_FOGVERTEXMODE ,
8029 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8030 WINED3DRS_LIGHTING ,
8031 WINED3DRS_LOCALVIEWER ,
8032 WINED3DRS_MULTISAMPLEANTIALIAS ,
8033 WINED3DRS_MULTISAMPLEMASK ,
8034 WINED3DRS_NORMALIZENORMALS ,
8035 WINED3DRS_PATCHEDGESTYLE ,
8036 WINED3DRS_POINTSCALE_A ,
8037 WINED3DRS_POINTSCALE_B ,
8038 WINED3DRS_POINTSCALE_C ,
8039 WINED3DRS_POINTSCALEENABLE ,
8040 WINED3DRS_POINTSIZE ,
8041 WINED3DRS_POINTSIZE_MAX ,
8042 WINED3DRS_POINTSIZE_MIN ,
8043 WINED3DRS_POINTSPRITEENABLE ,
8044 WINED3DRS_RANGEFOGENABLE ,
8045 WINED3DRS_SPECULARMATERIALSOURCE ,
8046 WINED3DRS_TWEENFACTOR ,
8047 WINED3DRS_VERTEXBLEND ,
8048 WINED3DRS_CULLMODE ,
8049 WINED3DRS_FOGCOLOR
8052 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8053 WINED3DTSS_TEXCOORDINDEX ,
8054 WINED3DTSS_TEXTURETRANSFORMFLAGS
8057 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8058 WINED3DSAMP_DMAPOFFSET
8061 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8062 DWORD rep = This->StateTable[state].representative;
8063 DWORD idx;
8064 BYTE shift;
8065 UINT i;
8066 WineD3DContext *context;
8068 if(!rep) return;
8069 for(i = 0; i < This->numContexts; i++) {
8070 context = This->contexts[i];
8071 if(isStateDirty(context, rep)) continue;
8073 context->dirtyArray[context->numDirtyEntries++] = rep;
8074 idx = rep >> 5;
8075 shift = rep & 0x1f;
8076 context->isStateDirty[idx] |= (1 << shift);
8080 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8081 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8082 /* The drawable size of a pbuffer render target is the current pbuffer size
8084 *width = dev->pbufferWidth;
8085 *height = dev->pbufferHeight;
8088 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8089 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8091 *width = This->pow2Width;
8092 *height = This->pow2Height;
8095 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8096 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8097 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8098 * current context's drawable, which is the size of the back buffer of the swapchain
8099 * the active context belongs to. The back buffer of the swapchain is stored as the
8100 * surface the context belongs to.
8102 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8103 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;