winedos: Increase extended memory from 7MB to 15MB.
[wine.git] / dlls / wined3d / device.c
blob1aa3c56a30abf54455476be86645bfc093a3d7a7
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /* helper macros */
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
66 object->ref = 1; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 object->resource.priority = 0; \
94 list_init(&object->resource.privateData); \
95 /* Check that we have enough video ram left */ \
96 if (Pool == WINED3DPOOL_DEFAULT) { \
97 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
98 WARN("Out of 'bogus' video memory\n"); \
99 HeapFree(GetProcessHeap(), 0, object); \
100 *pp##type = NULL; \
101 return WINED3DERR_OUTOFVIDEOMEMORY; \
103 WineD3DAdapterChangeGLRam(This, _size); \
105 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
106 if (object->resource.heapMemory == NULL && _size != 0) { \
107 FIXME("Out of memory!\n"); \
108 HeapFree(GetProcessHeap(), 0, object); \
109 *pp##type = NULL; \
110 return WINED3DERR_OUTOFVIDEOMEMORY; \
112 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
113 *pp##type = (IWineD3D##type *) object; \
114 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
115 TRACE("(%p) : Created resource %p\n", This, object); \
118 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
119 _basetexture.levels = Levels; \
120 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
121 _basetexture.LOD = 0; \
122 _basetexture.dirty = TRUE; \
123 _basetexture.is_srgb = FALSE; \
124 _basetexture.srgb_mode_change_count = 0; \
127 /**********************************************************
128 * Global variable / Constants follow
129 **********************************************************/
130 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
132 /**********************************************************
133 * IUnknown parts follows
134 **********************************************************/
136 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
140 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
141 if (IsEqualGUID(riid, &IID_IUnknown)
142 || IsEqualGUID(riid, &IID_IWineD3DBase)
143 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
144 IUnknown_AddRef(iface);
145 *ppobj = This;
146 return S_OK;
148 *ppobj = NULL;
149 return E_NOINTERFACE;
152 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
154 ULONG refCount = InterlockedIncrement(&This->ref);
156 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
157 return refCount;
160 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
162 ULONG refCount = InterlockedDecrement(&This->ref);
164 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
166 if (!refCount) {
167 /* TODO: Clean up all the surfaces and textures! */
168 /* NOTE: You must release the parent if the object was created via a callback
169 ** ***************************/
171 if (!list_empty(&This->resources)) {
172 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
173 dumpResources(&This->resources);
176 if(This->contexts) ERR("Context array not freed!\n");
177 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
178 This->haveHardwareCursor = FALSE;
180 IWineD3D_Release(This->wineD3D);
181 This->wineD3D = NULL;
182 HeapFree(GetProcessHeap(), 0, This);
183 TRACE("Freed device %p\n", This);
184 This = NULL;
186 return refCount;
189 /**********************************************************
190 * IWineD3DDevice implementation follows
191 **********************************************************/
192 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
194 *pParent = This->parent;
195 IUnknown_AddRef(This->parent);
196 return WINED3D_OK;
199 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
200 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
201 IUnknown *parent) {
202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
203 IWineD3DVertexBufferImpl *object;
204 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
205 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
206 BOOL conv;
208 if(Size == 0) {
209 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
210 *ppVertexBuffer = NULL;
211 return WINED3DERR_INVALIDCALL;
212 } else if(Pool == WINED3DPOOL_SCRATCH) {
213 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
214 * anyway, SCRATCH vertex buffers aren't usable anywhere
216 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
217 *ppVertexBuffer = NULL;
218 return WINED3DERR_INVALIDCALL;
221 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
223 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
224 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
226 object->fvf = FVF;
228 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
229 * drawStridedFast (half-life 2).
231 * Basically converting the vertices in the buffer is quite expensive, and observations
232 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
233 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
235 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
236 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
237 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
238 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
239 * dx7 apps.
240 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
241 * more. In this call we can convert dx7 buffers too.
243 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
244 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
245 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
246 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
247 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
248 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
249 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
250 } else if(dxVersion <= 7 && conv) {
251 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
252 } else {
253 object->Flags |= VBFLAG_CREATEVBO;
255 return WINED3D_OK;
258 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
259 GLenum error, glUsage;
260 TRACE("Creating VBO for Index Buffer %p\n", object);
262 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
263 * restored on the next draw
265 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
267 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
268 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
269 ENTER_GL();
271 while(glGetError());
273 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
274 error = glGetError();
275 if(error != GL_NO_ERROR || object->vbo == 0) {
276 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
277 goto out;
280 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
281 error = glGetError();
282 if(error != GL_NO_ERROR) {
283 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
284 goto out;
287 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
288 * copy no readback will be needed
290 glUsage = GL_STATIC_DRAW_ARB;
291 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
292 error = glGetError();
293 if(error != GL_NO_ERROR) {
294 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
295 goto out;
297 LEAVE_GL();
298 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
299 return;
301 out:
302 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
303 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
304 LEAVE_GL();
305 object->vbo = 0;
308 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
309 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
310 HANDLE *sharedHandle, IUnknown *parent) {
311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
312 IWineD3DIndexBufferImpl *object;
313 TRACE("(%p) Creating index buffer\n", This);
315 /* Allocate the storage for the device */
316 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
318 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
319 CreateIndexBufferVBO(This, object);
322 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
323 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
324 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
326 return WINED3D_OK;
329 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
332 IWineD3DStateBlockImpl *object;
333 int i, j;
334 HRESULT temp_result;
336 D3DCREATEOBJECTINSTANCE(object, StateBlock)
337 object->blockType = Type;
339 for(i = 0; i < LIGHTMAP_SIZE; i++) {
340 list_init(&object->lightMap[i]);
343 temp_result = allocate_shader_constants(object);
344 if (FAILED(temp_result))
346 HeapFree(GetProcessHeap(), 0, object);
347 return temp_result;
350 /* Special case - Used during initialization to produce a placeholder stateblock
351 so other functions called can update a state block */
352 if (Type == WINED3DSBT_INIT) {
353 /* Don't bother increasing the reference count otherwise a device will never
354 be freed due to circular dependencies */
355 return WINED3D_OK;
358 /* Otherwise, might as well set the whole state block to the appropriate values */
359 if (This->stateBlock != NULL)
360 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
361 else
362 memset(object->streamFreq, 1, sizeof(object->streamFreq));
364 /* Reset the ref and type after kludging it */
365 object->wineD3DDevice = This;
366 object->ref = 1;
367 object->blockType = Type;
369 TRACE("Updating changed flags appropriate for type %d\n", Type);
371 if (Type == WINED3DSBT_ALL) {
373 TRACE("ALL => Pretend everything has changed\n");
374 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
376 /* Lights are not part of the changed / set structure */
377 for(j = 0; j < LIGHTMAP_SIZE; j++) {
378 struct list *e;
379 LIST_FOR_EACH(e, &object->lightMap[j]) {
380 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
381 light->changed = TRUE;
382 light->enabledChanged = TRUE;
385 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
386 object->contained_render_states[j - 1] = j;
388 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
389 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
390 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
391 object->contained_transform_states[j - 1] = j;
393 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
394 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
395 object->contained_vs_consts_f[j] = j;
397 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
398 for(j = 0; j < MAX_CONST_I; j++) {
399 object->contained_vs_consts_i[j] = j;
401 object->num_contained_vs_consts_i = MAX_CONST_I;
402 for(j = 0; j < MAX_CONST_B; j++) {
403 object->contained_vs_consts_b[j] = j;
405 object->num_contained_vs_consts_b = MAX_CONST_B;
406 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
407 object->contained_ps_consts_f[j] = j;
409 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
410 for(j = 0; j < MAX_CONST_I; j++) {
411 object->contained_ps_consts_i[j] = j;
413 object->num_contained_ps_consts_i = MAX_CONST_I;
414 for(j = 0; j < MAX_CONST_B; j++) {
415 object->contained_ps_consts_b[j] = j;
417 object->num_contained_ps_consts_b = MAX_CONST_B;
418 for(i = 0; i < MAX_TEXTURES; i++) {
419 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
420 object->contained_tss_states[object->num_contained_tss_states].stage = i;
421 object->contained_tss_states[object->num_contained_tss_states].state = j;
422 object->num_contained_tss_states++;
425 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
426 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
427 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
428 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
429 object->num_contained_sampler_states++;
433 for(i = 0; i < MAX_STREAMS; i++) {
434 if(object->streamSource[i]) {
435 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
438 if(object->pIndexData) {
439 IWineD3DIndexBuffer_AddRef(object->pIndexData);
441 if(object->vertexShader) {
442 IWineD3DVertexShader_AddRef(object->vertexShader);
444 if(object->pixelShader) {
445 IWineD3DPixelShader_AddRef(object->pixelShader);
448 } else if (Type == WINED3DSBT_PIXELSTATE) {
450 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
451 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
453 object->changed.pixelShader = TRUE;
455 /* Pixel Shader Constants */
456 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
457 object->contained_ps_consts_f[i] = i;
458 object->changed.pixelShaderConstantsF[i] = TRUE;
460 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
461 for (i = 0; i < MAX_CONST_B; ++i) {
462 object->contained_ps_consts_b[i] = i;
463 object->changed.pixelShaderConstantsB |= (1 << i);
465 object->num_contained_ps_consts_b = MAX_CONST_B;
466 for (i = 0; i < MAX_CONST_I; ++i) {
467 object->contained_ps_consts_i[i] = i;
468 object->changed.pixelShaderConstantsI |= (1 << i);
470 object->num_contained_ps_consts_i = MAX_CONST_I;
472 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
473 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
474 object->contained_render_states[i] = SavedPixelStates_R[i];
476 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
477 for (j = 0; j < MAX_TEXTURES; j++) {
478 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
479 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
480 object->contained_tss_states[object->num_contained_tss_states].stage = j;
481 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
482 object->num_contained_tss_states++;
485 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
486 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
487 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
488 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
489 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
490 object->num_contained_sampler_states++;
493 if(object->pixelShader) {
494 IWineD3DPixelShader_AddRef(object->pixelShader);
497 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
498 * on them. This makes releasing the buffer easier
500 for(i = 0; i < MAX_STREAMS; i++) {
501 object->streamSource[i] = NULL;
503 object->pIndexData = NULL;
504 object->vertexShader = NULL;
506 } else if (Type == WINED3DSBT_VERTEXSTATE) {
508 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
509 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
511 object->changed.vertexShader = TRUE;
513 /* Vertex Shader Constants */
514 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
515 object->changed.vertexShaderConstantsF[i] = TRUE;
516 object->contained_vs_consts_f[i] = i;
518 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
519 for (i = 0; i < MAX_CONST_B; ++i) {
520 object->contained_vs_consts_b[i] = i;
521 object->changed.vertexShaderConstantsB |= (1 << i);
523 object->num_contained_vs_consts_b = MAX_CONST_B;
524 for (i = 0; i < MAX_CONST_I; ++i) {
525 object->contained_vs_consts_i[i] = i;
526 object->changed.vertexShaderConstantsI |= (1 << i);
528 object->num_contained_vs_consts_i = MAX_CONST_I;
529 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
530 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
531 object->contained_render_states[i] = SavedVertexStates_R[i];
533 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
534 for (j = 0; j < MAX_TEXTURES; j++) {
535 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
536 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
537 object->contained_tss_states[object->num_contained_tss_states].stage = j;
538 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
539 object->num_contained_tss_states++;
542 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
543 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
544 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
545 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
546 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
547 object->num_contained_sampler_states++;
551 for(j = 0; j < LIGHTMAP_SIZE; j++) {
552 struct list *e;
553 LIST_FOR_EACH(e, &object->lightMap[j]) {
554 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
555 light->changed = TRUE;
556 light->enabledChanged = TRUE;
560 for(i = 0; i < MAX_STREAMS; i++) {
561 if(object->streamSource[i]) {
562 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
565 if(object->vertexShader) {
566 IWineD3DVertexShader_AddRef(object->vertexShader);
568 object->pIndexData = NULL;
569 object->pixelShader = NULL;
570 } else {
571 FIXME("Unrecognized state block type %d\n", Type);
574 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
575 return WINED3D_OK;
578 /* ************************************
579 MSDN:
580 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
582 Discard
583 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
585 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.
587 ******************************** */
589 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) {
590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
591 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
592 unsigned int Size = 1;
593 const struct GlPixelFormatDesc *glDesc;
594 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
595 UINT mul_4w, mul_4h;
596 TRACE("(%p) Create surface\n",This);
598 /** FIXME: Check ranges on the inputs are valid
599 * MSDN
600 * MultisampleQuality
601 * [in] Quality level. The valid range is between zero and one less than the level
602 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
603 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
604 * values of paired render targets, depth stencil surfaces, and the MultiSample type
605 * must all match.
606 *******************************/
610 * TODO: Discard MSDN
611 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
613 * If this flag is set, the contents of the depth stencil buffer will be
614 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
615 * with a different depth surface.
617 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
618 ***************************/
620 if(MultisampleQuality > 0) {
621 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
622 MultisampleQuality=0;
625 /** FIXME: Check that the format is supported
626 * by the device.
627 *******************************/
629 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
630 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
631 * space!
632 *********************************/
633 mul_4w = (Width + 3) & ~3;
634 mul_4h = (Height + 3) & ~3;
635 if (WINED3DFMT_UNKNOWN == Format) {
636 Size = 0;
637 } else if (Format == WINED3DFMT_DXT1) {
638 /* DXT1 is half byte per pixel */
639 Size = (mul_4w * tableEntry->bpp * mul_4h) >> 1;
641 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
642 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
643 Format == WINED3DFMT_ATI2N) {
644 Size = (mul_4w * tableEntry->bpp * mul_4h);
645 } else {
646 /* The pitch is a multiple of 4 bytes */
647 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
648 Size *= Height;
651 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
653 /** Create and initialise the surface resource **/
654 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
655 /* "Standalone" surface */
656 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
658 object->currentDesc.Width = Width;
659 object->currentDesc.Height = Height;
660 object->currentDesc.MultiSampleType = MultiSample;
661 object->currentDesc.MultiSampleQuality = MultisampleQuality;
662 object->glDescription.level = Level;
663 object->heightscale = glDesc->heightscale != 0.0 ? glDesc->heightscale : 1.0;
664 list_init(&object->overlays);
666 /* Flags */
667 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
668 object->Flags |= Discard ? SFLAG_DISCARD : 0;
669 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
670 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
673 if (WINED3DFMT_UNKNOWN != Format) {
674 object->bytesPerPixel = tableEntry->bpp;
675 } else {
676 object->bytesPerPixel = 0;
679 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
681 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
683 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
684 * this function is too deep to need to care about things like this.
685 * Levels need to be checked too, and possibly Type since they all affect what can be done.
686 * ****************************************/
687 switch(Pool) {
688 case WINED3DPOOL_SCRATCH:
689 if(!Lockable)
690 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
691 "which are mutually exclusive, setting lockable to TRUE\n");
692 Lockable = TRUE;
693 break;
694 case WINED3DPOOL_SYSTEMMEM:
695 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
696 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
697 case WINED3DPOOL_MANAGED:
698 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
699 "Usage of DYNAMIC which are mutually exclusive, not doing "
700 "anything just telling you.\n");
701 break;
702 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
703 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
704 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
705 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
706 break;
707 default:
708 FIXME("(%p) Unknown pool %d\n", This, Pool);
709 break;
712 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
713 FIXME("Trying to create a render target that isn't in the default pool\n");
716 /* mark the texture as dirty so that it gets loaded first time around*/
717 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
718 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
719 This, Width, Height, Format, debug_d3dformat(Format),
720 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
722 /* Look at the implementation and set the correct Vtable */
723 switch(Impl) {
724 case SURFACE_OPENGL:
725 /* Check if a 3D adapter is available when creating gl surfaces */
726 if(!This->adapter) {
727 ERR("OpenGL surfaces are not available without opengl\n");
728 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
729 HeapFree(GetProcessHeap(), 0, object);
730 return WINED3DERR_NOTAVAILABLE;
732 break;
734 case SURFACE_GDI:
735 object->lpVtbl = &IWineGDISurface_Vtbl;
736 break;
738 default:
739 /* To be sure to catch this */
740 ERR("Unknown requested surface implementation %d!\n", Impl);
741 IWineD3DSurface_Release((IWineD3DSurface *) object);
742 return WINED3DERR_INVALIDCALL;
745 list_init(&object->renderbuffers);
747 /* Call the private setup routine */
748 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
752 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
753 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
754 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
755 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
758 IWineD3DTextureImpl *object;
759 unsigned int i;
760 UINT tmpW;
761 UINT tmpH;
762 HRESULT hr;
763 unsigned int pow2Width;
764 unsigned int pow2Height;
765 const struct GlPixelFormatDesc *glDesc;
766 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
768 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
769 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
770 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
772 /* TODO: It should only be possible to create textures for formats
773 that are reported as supported */
774 if (WINED3DFMT_UNKNOWN >= Format) {
775 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
776 return WINED3DERR_INVALIDCALL;
779 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
780 D3DINITIALIZEBASETEXTURE(object->baseTexture);
781 object->width = Width;
782 object->height = Height;
784 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
785 object->baseTexture.minMipLookup = minMipLookup;
786 object->baseTexture.magLookup = magLookup;
787 } else {
788 object->baseTexture.minMipLookup = minMipLookup_noFilter;
789 object->baseTexture.magLookup = magLookup_noFilter;
792 /** Non-power2 support **/
793 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
794 pow2Width = Width;
795 pow2Height = Height;
796 } else {
797 /* Find the nearest pow2 match */
798 pow2Width = pow2Height = 1;
799 while (pow2Width < Width) pow2Width <<= 1;
800 while (pow2Height < Height) pow2Height <<= 1;
802 if(pow2Width != Width || pow2Height != Height) {
803 if(Levels > 1) {
804 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
805 HeapFree(GetProcessHeap(), 0, object);
806 *ppTexture = NULL;
807 return WINED3DERR_INVALIDCALL;
808 } else {
809 Levels = 1;
814 /** FIXME: add support for real non-power-two if it's provided by the video card **/
815 /* Precalculated scaling for 'faked' non power of two texture coords.
816 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
817 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
818 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
820 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
821 object->baseTexture.pow2Matrix[0] = 1.0;
822 object->baseTexture.pow2Matrix[5] = 1.0;
823 object->baseTexture.pow2Matrix[10] = 1.0;
824 object->baseTexture.pow2Matrix[15] = 1.0;
825 object->target = GL_TEXTURE_2D;
826 object->cond_np2 = TRUE;
827 object->baseTexture.minMipLookup = minMipLookup_noFilter;
828 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
829 (Width != pow2Width || Height != pow2Height) &&
830 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
832 object->baseTexture.pow2Matrix[0] = (float)Width;
833 object->baseTexture.pow2Matrix[5] = (float)Height;
834 object->baseTexture.pow2Matrix[10] = 1.0;
835 object->baseTexture.pow2Matrix[15] = 1.0;
836 object->target = GL_TEXTURE_RECTANGLE_ARB;
837 object->cond_np2 = TRUE;
838 object->baseTexture.minMipLookup = minMipLookup_noFilter;
839 } else {
840 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
841 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
842 object->baseTexture.pow2Matrix[10] = 1.0;
843 object->baseTexture.pow2Matrix[15] = 1.0;
844 object->target = GL_TEXTURE_2D;
845 object->cond_np2 = FALSE;
847 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
849 /* Calculate levels for mip mapping */
850 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
851 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
852 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
853 return WINED3DERR_INVALIDCALL;
855 if(Levels > 1) {
856 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
857 return WINED3DERR_INVALIDCALL;
859 object->baseTexture.levels = 1;
860 } else if (Levels == 0) {
861 object->baseTexture.levels = wined3d_log2i(max(Width, Height)) + 1;
862 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
865 /* Generate all the surfaces */
866 tmpW = Width;
867 tmpH = Height;
868 for (i = 0; i < object->baseTexture.levels; i++)
870 /* use the callback to create the texture surface */
871 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
872 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
873 FIXME("Failed to create surface %p\n", object);
874 /* clean up */
875 object->surfaces[i] = NULL;
876 IWineD3DTexture_Release((IWineD3DTexture *)object);
878 *ppTexture = NULL;
879 return hr;
882 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
883 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
884 surface_set_texture_target(object->surfaces[i], object->target);
885 /* calculate the next mipmap level */
886 tmpW = max(1, tmpW >> 1);
887 tmpH = max(1, tmpH >> 1);
889 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
891 TRACE("(%p) : Created texture %p\n", This, object);
892 return WINED3D_OK;
895 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
896 UINT Width, UINT Height, UINT Depth,
897 UINT Levels, DWORD Usage,
898 WINED3DFORMAT Format, WINED3DPOOL Pool,
899 IWineD3DVolumeTexture **ppVolumeTexture,
900 HANDLE *pSharedHandle, IUnknown *parent,
901 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
904 IWineD3DVolumeTextureImpl *object;
905 unsigned int i;
906 UINT tmpW;
907 UINT tmpH;
908 UINT tmpD;
909 const struct GlPixelFormatDesc *glDesc;
911 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
913 /* TODO: It should only be possible to create textures for formats
914 that are reported as supported */
915 if (WINED3DFMT_UNKNOWN >= Format) {
916 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
917 return WINED3DERR_INVALIDCALL;
919 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
920 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
921 return WINED3DERR_INVALIDCALL;
924 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
925 D3DINITIALIZEBASETEXTURE(object->baseTexture);
927 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
928 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
930 /* Is NP2 support for volumes needed? */
931 object->baseTexture.pow2Matrix[ 0] = 1.0;
932 object->baseTexture.pow2Matrix[ 5] = 1.0;
933 object->baseTexture.pow2Matrix[10] = 1.0;
934 object->baseTexture.pow2Matrix[15] = 1.0;
936 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
937 object->baseTexture.minMipLookup = minMipLookup;
938 object->baseTexture.magLookup = magLookup;
939 } else {
940 object->baseTexture.minMipLookup = minMipLookup_noFilter;
941 object->baseTexture.magLookup = magLookup_noFilter;
944 /* Calculate levels for mip mapping */
945 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
946 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
947 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
948 return WINED3DERR_INVALIDCALL;
950 if(Levels > 1) {
951 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
952 return WINED3DERR_INVALIDCALL;
954 object->baseTexture.levels = 1;
955 } else if (Levels == 0) {
956 object->baseTexture.levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
957 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
960 /* Generate all the surfaces */
961 tmpW = Width;
962 tmpH = Height;
963 tmpD = Depth;
965 for (i = 0; i < object->baseTexture.levels; i++)
967 HRESULT hr;
968 /* Create the volume */
969 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
970 &object->volumes[i], pSharedHandle);
972 if(FAILED(hr)) {
973 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
974 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
975 *ppVolumeTexture = NULL;
976 return hr;
979 /* Set its container to this object */
980 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
982 /* calculate the next mipmap level */
983 tmpW = max(1, tmpW >> 1);
984 tmpH = max(1, tmpH >> 1);
985 tmpD = max(1, tmpD >> 1);
987 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
989 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
990 TRACE("(%p) : Created volume texture %p\n", This, object);
991 return WINED3D_OK;
994 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
995 UINT Width, UINT Height, UINT Depth,
996 DWORD Usage,
997 WINED3DFORMAT Format, WINED3DPOOL Pool,
998 IWineD3DVolume** ppVolume,
999 HANDLE* pSharedHandle, IUnknown *parent) {
1001 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1002 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1003 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1005 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1006 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1007 return WINED3DERR_INVALIDCALL;
1010 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1012 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1013 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1015 object->currentDesc.Width = Width;
1016 object->currentDesc.Height = Height;
1017 object->currentDesc.Depth = Depth;
1018 object->bytesPerPixel = formatDesc->bpp;
1020 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1021 object->lockable = TRUE;
1022 object->locked = FALSE;
1023 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1024 object->dirty = TRUE;
1026 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1029 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1030 UINT Levels, DWORD Usage,
1031 WINED3DFORMAT Format, WINED3DPOOL Pool,
1032 IWineD3DCubeTexture **ppCubeTexture,
1033 HANDLE *pSharedHandle, IUnknown *parent,
1034 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1037 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1038 unsigned int i, j;
1039 UINT tmpW;
1040 HRESULT hr;
1041 unsigned int pow2EdgeLength;
1042 const struct GlPixelFormatDesc *glDesc;
1043 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1045 /* TODO: It should only be possible to create textures for formats
1046 that are reported as supported */
1047 if (WINED3DFMT_UNKNOWN >= Format) {
1048 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1049 return WINED3DERR_INVALIDCALL;
1052 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1053 WARN("(%p) : Tried to create not supported cube texture\n", This);
1054 return WINED3DERR_INVALIDCALL;
1057 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1058 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1060 TRACE("(%p) Create Cube Texture\n", This);
1062 /* Find the nearest pow2 match */
1063 pow2EdgeLength = 1;
1064 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1066 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
1067 /* Precalculated scaling for 'faked' non power of two texture coords */
1068 object->baseTexture.pow2Matrix[ 0] = 1.0;
1069 object->baseTexture.pow2Matrix[ 5] = 1.0;
1070 object->baseTexture.pow2Matrix[10] = 1.0;
1071 object->baseTexture.pow2Matrix[15] = 1.0;
1072 } else {
1073 /* Precalculated scaling for 'faked' non power of two texture coords */
1074 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1075 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1076 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1077 object->baseTexture.pow2Matrix[15] = 1.0;
1080 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1081 object->baseTexture.minMipLookup = minMipLookup;
1082 object->baseTexture.magLookup = magLookup;
1083 } else {
1084 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1085 object->baseTexture.magLookup = magLookup_noFilter;
1088 /* Calculate levels for mip mapping */
1089 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1090 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1091 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1092 HeapFree(GetProcessHeap(), 0, object);
1093 *ppCubeTexture = NULL;
1095 return WINED3DERR_INVALIDCALL;
1097 if(Levels > 1) {
1098 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1099 HeapFree(GetProcessHeap(), 0, object);
1100 *ppCubeTexture = NULL;
1102 return WINED3DERR_INVALIDCALL;
1104 object->baseTexture.levels = 1;
1105 } else if (Levels == 0) {
1106 object->baseTexture.levels = wined3d_log2i(EdgeLength) + 1;
1107 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1110 /* Generate all the surfaces */
1111 tmpW = EdgeLength;
1112 for (i = 0; i < object->baseTexture.levels; i++) {
1114 /* Create the 6 faces */
1115 for (j = 0; j < 6; j++) {
1116 static const GLenum cube_targets[6] = {
1117 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1118 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1119 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1120 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1121 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1122 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1125 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1126 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1128 if(hr!= WINED3D_OK) {
1129 /* clean up */
1130 unsigned int k;
1131 unsigned int l;
1132 for (l = 0; l < j; l++) {
1133 IWineD3DSurface_Release(object->surfaces[l][i]);
1135 for (k = 0; k < i; k++) {
1136 for (l = 0; l < 6; l++) {
1137 IWineD3DSurface_Release(object->surfaces[l][k]);
1141 FIXME("(%p) Failed to create surface\n",object);
1142 HeapFree(GetProcessHeap(),0,object);
1143 *ppCubeTexture = NULL;
1144 return hr;
1146 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1147 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1148 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1150 tmpW = max(1, tmpW >> 1);
1152 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
1154 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1155 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1156 return WINED3D_OK;
1159 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1161 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1162 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1163 const IWineD3DQueryVtbl *vtable;
1165 /* Just a check to see if we support this type of query */
1166 switch(Type) {
1167 case WINED3DQUERYTYPE_OCCLUSION:
1168 TRACE("(%p) occlusion query\n", This);
1169 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1170 hr = WINED3D_OK;
1171 else
1172 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1174 vtable = &IWineD3DOcclusionQuery_Vtbl;
1175 break;
1177 case WINED3DQUERYTYPE_EVENT:
1178 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1179 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1180 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1182 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1184 vtable = &IWineD3DEventQuery_Vtbl;
1185 hr = WINED3D_OK;
1186 break;
1188 case WINED3DQUERYTYPE_VCACHE:
1189 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1190 case WINED3DQUERYTYPE_VERTEXSTATS:
1191 case WINED3DQUERYTYPE_TIMESTAMP:
1192 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1193 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1194 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1195 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1196 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1197 case WINED3DQUERYTYPE_PIXELTIMINGS:
1198 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1199 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1200 default:
1201 /* Use the base Query vtable until we have a special one for each query */
1202 vtable = &IWineD3DQuery_Vtbl;
1203 FIXME("(%p) Unhandled query type %d\n", This, Type);
1205 if(NULL == ppQuery || hr != WINED3D_OK) {
1206 return hr;
1209 D3DCREATEOBJECTINSTANCE(object, Query)
1210 object->lpVtbl = vtable;
1211 object->type = Type;
1212 object->state = QUERY_CREATED;
1213 /* allocated the 'extended' data based on the type of query requested */
1214 switch(Type){
1215 case WINED3DQUERYTYPE_OCCLUSION:
1216 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1217 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1219 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1220 TRACE("(%p) Allocating data for an occlusion query\n", This);
1222 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1223 ENTER_GL();
1224 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1225 LEAVE_GL();
1226 break;
1228 case WINED3DQUERYTYPE_EVENT:
1229 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1230 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1232 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1233 ENTER_GL();
1234 if(GL_SUPPORT(APPLE_FENCE)) {
1235 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1236 checkGLcall("glGenFencesAPPLE");
1237 } else if(GL_SUPPORT(NV_FENCE)) {
1238 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1239 checkGLcall("glGenFencesNV");
1241 LEAVE_GL();
1242 break;
1244 case WINED3DQUERYTYPE_VCACHE:
1245 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1246 case WINED3DQUERYTYPE_VERTEXSTATS:
1247 case WINED3DQUERYTYPE_TIMESTAMP:
1248 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1249 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1250 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1251 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1252 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1253 case WINED3DQUERYTYPE_PIXELTIMINGS:
1254 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1255 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1256 default:
1257 object->extendedData = 0;
1258 FIXME("(%p) Unhandled query type %d\n",This , Type);
1260 TRACE("(%p) : Created Query %p\n", This, object);
1261 return WINED3D_OK;
1264 /*****************************************************************************
1265 * IWineD3DDeviceImpl_SetupFullscreenWindow
1267 * Helper function that modifies a HWND's Style and ExStyle for proper
1268 * fullscreen use.
1270 * Params:
1271 * iface: Pointer to the IWineD3DDevice interface
1272 * window: Window to setup
1274 *****************************************************************************/
1275 static LONG fullscreen_style(LONG orig_style) {
1276 LONG style = orig_style;
1277 style &= ~WS_CAPTION;
1278 style &= ~WS_THICKFRAME;
1280 /* Make sure the window is managed, otherwise we won't get keyboard input */
1281 style |= WS_POPUP | WS_SYSMENU;
1283 return style;
1286 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1287 LONG exStyle = orig_exStyle;
1289 /* Filter out window decorations */
1290 exStyle &= ~WS_EX_WINDOWEDGE;
1291 exStyle &= ~WS_EX_CLIENTEDGE;
1293 return exStyle;
1296 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1299 LONG style, exStyle;
1300 /* Don't do anything if an original style is stored.
1301 * That shouldn't happen
1303 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1304 if (This->style || This->exStyle) {
1305 ERR("(%p): Want to change the window parameters of HWND %p, but "
1306 "another style is stored for restoration afterwards\n", This, window);
1309 /* Get the parameters and save them */
1310 style = GetWindowLongW(window, GWL_STYLE);
1311 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1312 This->style = style;
1313 This->exStyle = exStyle;
1315 style = fullscreen_style(style);
1316 exStyle = fullscreen_exStyle(exStyle);
1318 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1319 This->style, This->exStyle, style, exStyle);
1321 SetWindowLongW(window, GWL_STYLE, style);
1322 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1324 /* Inform the window about the update. */
1325 SetWindowPos(window, HWND_TOP, 0, 0,
1326 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1329 /*****************************************************************************
1330 * IWineD3DDeviceImpl_RestoreWindow
1332 * Helper function that restores a windows' properties when taking it out
1333 * of fullscreen mode
1335 * Params:
1336 * iface: Pointer to the IWineD3DDevice interface
1337 * window: Window to setup
1339 *****************************************************************************/
1340 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1341 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1342 LONG style, exStyle;
1344 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1345 * switch, do nothing
1347 if (!This->style && !This->exStyle) return;
1349 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1350 This, window, This->style, This->exStyle);
1352 style = GetWindowLongW(window, GWL_STYLE);
1353 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1355 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1356 * Some applications change it before calling Reset() when switching between windowed and
1357 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1359 if(style == fullscreen_style(This->style) &&
1360 exStyle == fullscreen_style(This->exStyle)) {
1361 SetWindowLongW(window, GWL_STYLE, This->style);
1362 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1365 /* Delete the old values */
1366 This->style = 0;
1367 This->exStyle = 0;
1369 /* Inform the window about the update */
1370 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1371 0, 0, 0, 0, /* Pos, Size, ignored */
1372 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1375 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1376 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice* iface,
1377 WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1378 IUnknown* parent, D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1379 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil, WINED3DSURFTYPE surface_type)
1381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1383 HDC hDc;
1384 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1385 HRESULT hr;
1386 IUnknown *bufferParent;
1387 BOOL displaymode_set = FALSE;
1388 WINED3DDISPLAYMODE Mode;
1389 const StaticPixelFormatDesc *formatDesc;
1391 TRACE("(%p) : Created Additional Swap Chain\n", This);
1393 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1394 * does a device hold a reference to a swap chain giving them a lifetime of the device
1395 * or does the swap chain notify the device of its destruction.
1396 *******************************/
1398 /* Check the params */
1399 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1400 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1401 return WINED3DERR_INVALIDCALL;
1402 } else if (pPresentationParameters->BackBufferCount > 1) {
1403 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");
1406 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1407 switch(surface_type) {
1408 case SURFACE_GDI:
1409 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1410 break;
1411 case SURFACE_OPENGL:
1412 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1413 break;
1414 case SURFACE_UNKNOWN:
1415 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1416 return WINED3DERR_INVALIDCALL;
1419 /*********************
1420 * Lookup the window Handle and the relating X window handle
1421 ********************/
1423 /* Setup hwnd we are using, plus which display this equates to */
1424 object->win_handle = pPresentationParameters->hDeviceWindow;
1425 if (!object->win_handle) {
1426 object->win_handle = This->createParms.hFocusWindow;
1428 if(!pPresentationParameters->Windowed && object->win_handle) {
1429 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1430 pPresentationParameters->BackBufferWidth,
1431 pPresentationParameters->BackBufferHeight);
1434 hDc = GetDC(object->win_handle);
1435 TRACE("Using hDc %p\n", hDc);
1437 if (NULL == hDc) {
1438 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1439 return WINED3DERR_NOTAVAILABLE;
1442 /* Get info on the current display setup */
1443 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1444 object->orig_width = Mode.Width;
1445 object->orig_height = Mode.Height;
1446 object->orig_fmt = Mode.Format;
1447 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1449 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1450 * then the corresponding dimension of the client area of the hDeviceWindow
1451 * (or the focus window, if hDeviceWindow is NULL) is taken.
1452 **********************/
1454 if (pPresentationParameters->Windowed &&
1455 ((pPresentationParameters->BackBufferWidth == 0) ||
1456 (pPresentationParameters->BackBufferHeight == 0) ||
1457 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1459 RECT Rect;
1460 GetClientRect(object->win_handle, &Rect);
1462 if (pPresentationParameters->BackBufferWidth == 0) {
1463 pPresentationParameters->BackBufferWidth = Rect.right;
1464 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1466 if (pPresentationParameters->BackBufferHeight == 0) {
1467 pPresentationParameters->BackBufferHeight = Rect.bottom;
1468 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1470 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1471 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1472 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1476 /* Put the correct figures in the presentation parameters */
1477 TRACE("Copying across presentation parameters\n");
1478 object->presentParms = *pPresentationParameters;
1480 TRACE("calling rendertarget CB\n");
1481 hr = D3DCB_CreateRenderTarget(This->parent,
1482 parent,
1483 object->presentParms.BackBufferWidth,
1484 object->presentParms.BackBufferHeight,
1485 object->presentParms.BackBufferFormat,
1486 object->presentParms.MultiSampleType,
1487 object->presentParms.MultiSampleQuality,
1488 TRUE /* Lockable */,
1489 &object->frontBuffer,
1490 NULL /* pShared (always null)*/);
1491 if (SUCCEEDED(hr)) {
1492 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1493 if(surface_type == SURFACE_OPENGL) {
1494 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1496 } else {
1497 ERR("Failed to create the front buffer\n");
1498 goto error;
1501 /*********************
1502 * Windowed / Fullscreen
1503 *******************/
1506 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1507 * so we should really check to see if there is a fullscreen swapchain already
1508 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1509 **************************************/
1511 if (!pPresentationParameters->Windowed) {
1512 WINED3DDISPLAYMODE mode;
1515 /* Change the display settings */
1516 mode.Width = pPresentationParameters->BackBufferWidth;
1517 mode.Height = pPresentationParameters->BackBufferHeight;
1518 mode.Format = pPresentationParameters->BackBufferFormat;
1519 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1521 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1522 displaymode_set = TRUE;
1526 * Create an opengl context for the display visual
1527 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1528 * use different properties after that point in time. FIXME: How to handle when requested format
1529 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1530 * it chooses is identical to the one already being used!
1531 **********************************/
1532 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1534 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1535 if(!object->context) {
1536 ERR("Failed to create the context array\n");
1537 hr = E_OUTOFMEMORY;
1538 goto error;
1540 object->num_contexts = 1;
1542 if(surface_type == SURFACE_OPENGL) {
1543 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1544 if (!object->context[0]) {
1545 ERR("Failed to create a new context\n");
1546 hr = WINED3DERR_NOTAVAILABLE;
1547 goto error;
1548 } else {
1549 TRACE("Context created (HWND=%p, glContext=%p)\n",
1550 object->win_handle, object->context[0]->glCtx);
1554 /*********************
1555 * Create the back, front and stencil buffers
1556 *******************/
1557 if(object->presentParms.BackBufferCount > 0) {
1558 UINT i;
1560 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1561 if(!object->backBuffer) {
1562 ERR("Out of memory\n");
1563 hr = E_OUTOFMEMORY;
1564 goto error;
1567 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1568 TRACE("calling rendertarget CB\n");
1569 hr = D3DCB_CreateRenderTarget(This->parent,
1570 parent,
1571 object->presentParms.BackBufferWidth,
1572 object->presentParms.BackBufferHeight,
1573 object->presentParms.BackBufferFormat,
1574 object->presentParms.MultiSampleType,
1575 object->presentParms.MultiSampleQuality,
1576 TRUE /* Lockable */,
1577 &object->backBuffer[i],
1578 NULL /* pShared (always null)*/);
1579 if(SUCCEEDED(hr)) {
1580 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1581 } else {
1582 ERR("Cannot create new back buffer\n");
1583 goto error;
1585 if(surface_type == SURFACE_OPENGL) {
1586 ENTER_GL();
1587 glDrawBuffer(GL_BACK);
1588 checkGLcall("glDrawBuffer(GL_BACK)");
1589 LEAVE_GL();
1592 } else {
1593 object->backBuffer = NULL;
1595 /* Single buffering - draw to front buffer */
1596 if(surface_type == SURFACE_OPENGL) {
1597 ENTER_GL();
1598 glDrawBuffer(GL_FRONT);
1599 checkGLcall("glDrawBuffer(GL_FRONT)");
1600 LEAVE_GL();
1604 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1605 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1606 TRACE("Creating depth stencil buffer\n");
1607 if (This->auto_depth_stencil_buffer == NULL ) {
1608 hr = D3DCB_CreateDepthStencil(This->parent,
1609 parent,
1610 object->presentParms.BackBufferWidth,
1611 object->presentParms.BackBufferHeight,
1612 object->presentParms.AutoDepthStencilFormat,
1613 object->presentParms.MultiSampleType,
1614 object->presentParms.MultiSampleQuality,
1615 FALSE /* FIXME: Discard */,
1616 &This->auto_depth_stencil_buffer,
1617 NULL /* pShared (always null)*/ );
1618 if (SUCCEEDED(hr)) {
1619 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1620 } else {
1621 ERR("Failed to create the auto depth stencil\n");
1622 goto error;
1627 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1629 TRACE("Created swapchain %p\n", object);
1630 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1631 return WINED3D_OK;
1633 error:
1634 if (displaymode_set) {
1635 DEVMODEW devmode;
1636 RECT clip_rc;
1638 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1639 ClipCursor(NULL);
1641 /* Change the display settings */
1642 memset(&devmode, 0, sizeof(devmode));
1643 devmode.dmSize = sizeof(devmode);
1644 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1645 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1646 devmode.dmPelsWidth = object->orig_width;
1647 devmode.dmPelsHeight = object->orig_height;
1648 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1651 if (object->backBuffer) {
1652 UINT i;
1653 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1654 if(object->backBuffer[i]) {
1655 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1656 IUnknown_Release(bufferParent); /* once for the get parent */
1657 if (IUnknown_Release(bufferParent) > 0) {
1658 FIXME("(%p) Something's still holding the back buffer\n",This);
1662 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1663 object->backBuffer = NULL;
1665 if(object->context && object->context[0])
1666 DestroyContext(This, object->context[0]);
1667 if(object->frontBuffer) {
1668 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1669 IUnknown_Release(bufferParent); /* once for the get parent */
1670 if (IUnknown_Release(bufferParent) > 0) {
1671 FIXME("(%p) Something's still holding the front buffer\n",This);
1674 HeapFree(GetProcessHeap(), 0, object);
1675 return hr;
1678 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1679 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1681 TRACE("(%p)\n", This);
1683 return This->NumberOfSwapChains;
1686 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1688 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1690 if(iSwapChain < This->NumberOfSwapChains) {
1691 *pSwapChain = This->swapchains[iSwapChain];
1692 IWineD3DSwapChain_AddRef(*pSwapChain);
1693 TRACE("(%p) returning %p\n", This, *pSwapChain);
1694 return WINED3D_OK;
1695 } else {
1696 TRACE("Swapchain out of range\n");
1697 *pSwapChain = NULL;
1698 return WINED3DERR_INVALIDCALL;
1702 /*****
1703 * Vertex Declaration
1704 *****/
1705 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1706 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1708 IWineD3DVertexDeclarationImpl *object = NULL;
1709 HRESULT hr = WINED3D_OK;
1711 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1712 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1714 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1716 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1717 if(FAILED(hr)) {
1718 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1719 *ppVertexDeclaration = NULL;
1722 return hr;
1725 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1726 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1728 unsigned int idx, idx2;
1729 unsigned int offset;
1730 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1731 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1732 BOOL has_blend_idx = has_blend &&
1733 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1734 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1735 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1736 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1737 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1738 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1739 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1741 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1742 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1744 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1745 WINED3DVERTEXELEMENT *elements = NULL;
1747 unsigned int size;
1748 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1749 if (has_blend_idx) num_blends--;
1751 /* Compute declaration size */
1752 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1753 has_psize + has_diffuse + has_specular + num_textures + 1;
1755 /* convert the declaration */
1756 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1757 if (!elements)
1758 return 0;
1760 elements[size-1] = end_element;
1761 idx = 0;
1762 if (has_pos) {
1763 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1764 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1765 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1767 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1768 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1769 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1771 else {
1772 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1773 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1775 elements[idx].UsageIndex = 0;
1776 idx++;
1778 if (has_blend && (num_blends > 0)) {
1779 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1780 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1781 else {
1782 switch(num_blends) {
1783 case 1: elements[idx].Type = WINED3DDECLTYPE_FLOAT1; break;
1784 case 2: elements[idx].Type = WINED3DDECLTYPE_FLOAT2; break;
1785 case 3: elements[idx].Type = WINED3DDECLTYPE_FLOAT3; break;
1786 case 4: elements[idx].Type = WINED3DDECLTYPE_FLOAT4; break;
1787 default:
1788 ERR("Unexpected amount of blend values: %u\n", num_blends);
1791 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1792 elements[idx].UsageIndex = 0;
1793 idx++;
1795 if (has_blend_idx) {
1796 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1797 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1798 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1799 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1800 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1801 else
1802 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1803 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1804 elements[idx].UsageIndex = 0;
1805 idx++;
1807 if (has_normal) {
1808 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1809 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1810 elements[idx].UsageIndex = 0;
1811 idx++;
1813 if (has_psize) {
1814 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1815 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1816 elements[idx].UsageIndex = 0;
1817 idx++;
1819 if (has_diffuse) {
1820 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1821 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1822 elements[idx].UsageIndex = 0;
1823 idx++;
1825 if (has_specular) {
1826 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1827 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1828 elements[idx].UsageIndex = 1;
1829 idx++;
1831 for (idx2 = 0; idx2 < num_textures; idx2++) {
1832 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1833 switch (numcoords) {
1834 case WINED3DFVF_TEXTUREFORMAT1:
1835 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1836 break;
1837 case WINED3DFVF_TEXTUREFORMAT2:
1838 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1839 break;
1840 case WINED3DFVF_TEXTUREFORMAT3:
1841 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1842 break;
1843 case WINED3DFVF_TEXTUREFORMAT4:
1844 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1845 break;
1847 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1848 elements[idx].UsageIndex = idx2;
1849 idx++;
1852 /* Now compute offsets, and initialize the rest of the fields */
1853 for (idx = 0, offset = 0; idx < size-1; idx++) {
1854 elements[idx].Stream = 0;
1855 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1856 elements[idx].Offset = offset;
1857 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1860 *ppVertexElements = elements;
1861 return size;
1864 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1865 WINED3DVERTEXELEMENT* elements = NULL;
1866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1867 unsigned int size;
1868 DWORD hr;
1870 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1871 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1873 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1874 HeapFree(GetProcessHeap(), 0, elements);
1875 if (hr != S_OK) return hr;
1877 return WINED3D_OK;
1880 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1882 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1883 HRESULT hr = WINED3D_OK;
1885 if (!pFunction) return WINED3DERR_INVALIDCALL;
1887 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1888 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1890 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1892 if (vertex_declaration) {
1893 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1896 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1898 if (WINED3D_OK != hr) {
1899 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1900 IWineD3DVertexShader_Release(*ppVertexShader);
1901 return WINED3DERR_INVALIDCALL;
1903 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1905 return WINED3D_OK;
1908 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1910 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1911 HRESULT hr = WINED3D_OK;
1913 if (!pFunction) return WINED3DERR_INVALIDCALL;
1915 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1916 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1917 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1918 if (WINED3D_OK == hr) {
1919 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1920 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1921 } else {
1922 WARN("(%p) : Failed to create pixel shader\n", This);
1925 return hr;
1928 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1929 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1932 IWineD3DPaletteImpl *object;
1933 HRESULT hr;
1934 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1936 /* Create the new object */
1937 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1938 if(!object) {
1939 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1940 return E_OUTOFMEMORY;
1943 object->lpVtbl = &IWineD3DPalette_Vtbl;
1944 object->ref = 1;
1945 object->Flags = Flags;
1946 object->parent = Parent;
1947 object->wineD3DDevice = This;
1948 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1950 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1952 if(!object->hpal) {
1953 HeapFree( GetProcessHeap(), 0, object);
1954 return E_OUTOFMEMORY;
1957 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1958 if(FAILED(hr)) {
1959 IWineD3DPalette_Release((IWineD3DPalette *) object);
1960 return hr;
1963 *Palette = (IWineD3DPalette *) object;
1965 return WINED3D_OK;
1968 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1969 HBITMAP hbm;
1970 BITMAP bm;
1971 HRESULT hr;
1972 HDC dcb = NULL, dcs = NULL;
1973 WINEDDCOLORKEY colorkey;
1975 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1976 if(hbm)
1978 GetObjectA(hbm, sizeof(BITMAP), &bm);
1979 dcb = CreateCompatibleDC(NULL);
1980 if(!dcb) goto out;
1981 SelectObject(dcb, hbm);
1983 else
1985 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1986 * couldn't be loaded
1988 memset(&bm, 0, sizeof(bm));
1989 bm.bmWidth = 32;
1990 bm.bmHeight = 32;
1993 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1994 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1995 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1996 if(FAILED(hr)) {
1997 ERR("Wine logo requested, but failed to create surface\n");
1998 goto out;
2001 if(dcb) {
2002 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2003 if(FAILED(hr)) goto out;
2004 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2005 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2007 colorkey.dwColorSpaceLowValue = 0;
2008 colorkey.dwColorSpaceHighValue = 0;
2009 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2010 } else {
2011 /* Fill the surface with a white color to show that wined3d is there */
2012 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2015 out:
2016 if(dcb) {
2017 DeleteDC(dcb);
2019 if(hbm) {
2020 DeleteObject(hbm);
2022 return;
2025 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2026 unsigned int i;
2027 /* Under DirectX you can have texture stage operations even if no texture is
2028 bound, whereas opengl will only do texture operations when a valid texture is
2029 bound. We emulate this by creating dummy textures and binding them to each
2030 texture stage, but disable all stages by default. Hence if a stage is enabled
2031 then the default texture will kick in until replaced by a SetTexture call */
2032 ENTER_GL();
2034 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2035 /* The dummy texture does not have client storage backing */
2036 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2037 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2039 for (i = 0; i < GL_LIMITS(textures); i++) {
2040 GLubyte white = 255;
2042 /* Make appropriate texture active */
2043 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2044 checkGLcall("glActiveTextureARB");
2046 /* Generate an opengl texture name */
2047 glGenTextures(1, &This->dummyTextureName[i]);
2048 checkGLcall("glGenTextures");
2049 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2051 /* Generate a dummy 2d texture (not using 1d because they cause many
2052 * DRI drivers fall back to sw) */
2053 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2054 checkGLcall("glBindTexture");
2056 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2057 checkGLcall("glTexImage2D");
2059 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2060 /* Reenable because if supported it is enabled by default */
2061 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2062 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2065 LEAVE_GL();
2068 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2070 IWineD3DSwapChainImpl *swapchain = NULL;
2071 HRESULT hr;
2072 DWORD state;
2073 unsigned int i;
2075 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateSwapChain);
2076 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2077 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2079 /* TODO: Test if OpenGL is compiled in and loaded */
2081 TRACE("(%p) : Creating stateblock\n", This);
2082 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2083 hr = IWineD3DDevice_CreateStateBlock(iface,
2084 WINED3DSBT_INIT,
2085 (IWineD3DStateBlock **)&This->stateBlock,
2086 NULL);
2087 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2088 WARN("Failed to create stateblock\n");
2089 goto err_out;
2091 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2092 This->updateStateBlock = This->stateBlock;
2093 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2095 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2096 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2098 This->NumberOfPalettes = 1;
2099 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2100 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2101 ERR("Out of memory!\n");
2102 goto err_out;
2104 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2105 if(!This->palettes[0]) {
2106 ERR("Out of memory!\n");
2107 goto err_out;
2109 for (i = 0; i < 256; ++i) {
2110 This->palettes[0][i].peRed = 0xFF;
2111 This->palettes[0][i].peGreen = 0xFF;
2112 This->palettes[0][i].peBlue = 0xFF;
2113 This->palettes[0][i].peFlags = 0xFF;
2115 This->currentPalette = 0;
2117 /* Initialize the texture unit mapping to a 1:1 mapping */
2118 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2119 if (state < GL_LIMITS(fragment_samplers)) {
2120 This->texUnitMap[state] = state;
2121 This->rev_tex_unit_map[state] = state;
2122 } else {
2123 This->texUnitMap[state] = -1;
2124 This->rev_tex_unit_map[state] = -1;
2128 /* Setup the implicit swapchain */
2129 TRACE("Creating implicit swapchain\n");
2130 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2131 if (FAILED(hr) || !swapchain) {
2132 WARN("Failed to create implicit swapchain\n");
2133 goto err_out;
2136 This->NumberOfSwapChains = 1;
2137 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2138 if(!This->swapchains) {
2139 ERR("Out of memory!\n");
2140 goto err_out;
2142 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2144 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2145 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2146 This->render_targets[0] = swapchain->backBuffer[0];
2147 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2149 else {
2150 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2151 This->render_targets[0] = swapchain->frontBuffer;
2152 This->lastActiveRenderTarget = swapchain->frontBuffer;
2154 IWineD3DSurface_AddRef(This->render_targets[0]);
2155 This->activeContext = swapchain->context[0];
2156 This->lastThread = GetCurrentThreadId();
2158 /* Depth Stencil support */
2159 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2160 if (NULL != This->stencilBufferTarget) {
2161 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2164 hr = This->shader_backend->shader_alloc_private(iface);
2165 if(FAILED(hr)) {
2166 TRACE("Shader private data couldn't be allocated\n");
2167 goto err_out;
2169 hr = This->frag_pipe->alloc_private(iface);
2170 if(FAILED(hr)) {
2171 TRACE("Fragment pipeline private data couldn't be allocated\n");
2172 goto err_out;
2174 hr = This->blitter->alloc_private(iface);
2175 if(FAILED(hr)) {
2176 TRACE("Blitter private data couldn't be allocated\n");
2177 goto err_out;
2180 /* Set up some starting GL setup */
2182 /* Setup all the devices defaults */
2183 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2184 create_dummy_textures(This);
2186 ENTER_GL();
2188 /* Initialize the current view state */
2189 This->view_ident = 1;
2190 This->contexts[0]->last_was_rhw = 0;
2191 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2192 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2194 switch(wined3d_settings.offscreen_rendering_mode) {
2195 case ORM_FBO:
2196 case ORM_PBUFFER:
2197 This->offscreenBuffer = GL_BACK;
2198 break;
2200 case ORM_BACKBUFFER:
2202 if(This->activeContext->aux_buffers > 0) {
2203 TRACE("Using auxilliary buffer for offscreen rendering\n");
2204 This->offscreenBuffer = GL_AUX0;
2205 } else {
2206 TRACE("Using back buffer for offscreen rendering\n");
2207 This->offscreenBuffer = GL_BACK;
2212 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2213 LEAVE_GL();
2215 /* Clear the screen */
2216 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2217 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2218 0x00, 1.0, 0);
2220 This->d3d_initialized = TRUE;
2222 if(wined3d_settings.logo) {
2223 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2225 This->highest_dirty_ps_const = 0;
2226 This->highest_dirty_vs_const = 0;
2227 return WINED3D_OK;
2229 err_out:
2230 HeapFree(GetProcessHeap(), 0, This->render_targets);
2231 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2232 HeapFree(GetProcessHeap(), 0, This->swapchains);
2233 This->NumberOfSwapChains = 0;
2234 if(This->palettes) {
2235 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2236 HeapFree(GetProcessHeap(), 0, This->palettes);
2238 This->NumberOfPalettes = 0;
2239 if(swapchain) {
2240 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2242 if(This->stateBlock) {
2243 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2244 This->stateBlock = NULL;
2246 if (This->blit_priv) {
2247 This->blitter->free_private(iface);
2249 if (This->fragment_priv) {
2250 This->frag_pipe->free_private(iface);
2252 if (This->shader_priv) {
2253 This->shader_backend->shader_free_private(iface);
2255 return hr;
2258 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2260 IWineD3DSwapChainImpl *swapchain = NULL;
2261 HRESULT hr;
2263 /* Setup the implicit swapchain */
2264 TRACE("Creating implicit swapchain\n");
2265 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2266 if (FAILED(hr) || !swapchain) {
2267 WARN("Failed to create implicit swapchain\n");
2268 goto err_out;
2271 This->NumberOfSwapChains = 1;
2272 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2273 if(!This->swapchains) {
2274 ERR("Out of memory!\n");
2275 goto err_out;
2277 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2278 return WINED3D_OK;
2280 err_out:
2281 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2282 return hr;
2285 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2287 int sampler;
2288 UINT i;
2289 TRACE("(%p)\n", This);
2291 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2293 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2294 * it was created. Thus make sure a context is active for the glDelete* calls
2296 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2298 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2300 TRACE("Deleting high order patches\n");
2301 for(i = 0; i < PATCHMAP_SIZE; i++) {
2302 struct list *e1, *e2;
2303 struct WineD3DRectPatch *patch;
2304 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2305 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2306 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2310 /* Delete the palette conversion shader if it is around */
2311 if(This->paletteConversionShader) {
2312 ENTER_GL();
2313 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2314 LEAVE_GL();
2315 This->paletteConversionShader = 0;
2318 /* Delete the pbuffer context if there is any */
2319 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2321 /* Delete the mouse cursor texture */
2322 if(This->cursorTexture) {
2323 ENTER_GL();
2324 glDeleteTextures(1, &This->cursorTexture);
2325 LEAVE_GL();
2326 This->cursorTexture = 0;
2329 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2330 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2332 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2333 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2336 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2337 * private data, it might contain opengl pointers
2339 if(This->depth_blt_texture) {
2340 glDeleteTextures(1, &This->depth_blt_texture);
2341 This->depth_blt_texture = 0;
2343 if (This->depth_blt_rb) {
2344 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2345 This->depth_blt_rb = 0;
2346 This->depth_blt_rb_w = 0;
2347 This->depth_blt_rb_h = 0;
2350 /* Release the update stateblock */
2351 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2352 if(This->updateStateBlock != This->stateBlock)
2353 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2355 This->updateStateBlock = NULL;
2357 { /* because were not doing proper internal refcounts releasing the primary state block
2358 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2359 to set this->stateBlock = NULL; first */
2360 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2361 This->stateBlock = NULL;
2363 /* Release the stateblock */
2364 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2365 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2369 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2370 This->blitter->free_private(iface);
2371 This->frag_pipe->free_private(iface);
2372 This->shader_backend->shader_free_private(iface);
2374 /* Release the buffers (with sanity checks)*/
2375 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2376 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2377 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2378 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2380 This->stencilBufferTarget = NULL;
2382 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2383 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2384 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2386 TRACE("Setting rendertarget to NULL\n");
2387 This->render_targets[0] = NULL;
2389 if (This->auto_depth_stencil_buffer) {
2390 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2391 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2393 This->auto_depth_stencil_buffer = NULL;
2396 for(i=0; i < This->NumberOfSwapChains; i++) {
2397 TRACE("Releasing the implicit swapchain %d\n", i);
2398 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2399 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2403 HeapFree(GetProcessHeap(), 0, This->swapchains);
2404 This->swapchains = NULL;
2405 This->NumberOfSwapChains = 0;
2407 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2408 HeapFree(GetProcessHeap(), 0, This->palettes);
2409 This->palettes = NULL;
2410 This->NumberOfPalettes = 0;
2412 HeapFree(GetProcessHeap(), 0, This->render_targets);
2413 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2414 This->render_targets = NULL;
2415 This->draw_buffers = NULL;
2417 This->d3d_initialized = FALSE;
2418 return WINED3D_OK;
2421 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2423 unsigned int i;
2425 for(i=0; i < This->NumberOfSwapChains; i++) {
2426 TRACE("Releasing the implicit swapchain %d\n", i);
2427 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2428 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2432 HeapFree(GetProcessHeap(), 0, This->swapchains);
2433 This->swapchains = NULL;
2434 This->NumberOfSwapChains = 0;
2435 return WINED3D_OK;
2438 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2439 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2440 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2442 * There is no way to deactivate thread safety once it is enabled.
2444 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2447 /*For now just store the flag(needed in case of ddraw) */
2448 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2450 return;
2453 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2454 const WINED3DDISPLAYMODE* pMode) {
2455 DEVMODEW devmode;
2456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2457 LONG ret;
2458 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2459 RECT clip_rc;
2461 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2463 /* Resize the screen even without a window:
2464 * The app could have unset it with SetCooperativeLevel, but not called
2465 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2466 * but we don't have any hwnd
2469 memset(&devmode, 0, sizeof(devmode));
2470 devmode.dmSize = sizeof(devmode);
2471 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2472 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2473 devmode.dmPelsWidth = pMode->Width;
2474 devmode.dmPelsHeight = pMode->Height;
2476 devmode.dmDisplayFrequency = pMode->RefreshRate;
2477 if (pMode->RefreshRate != 0) {
2478 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2481 /* Only change the mode if necessary */
2482 if( (This->ddraw_width == pMode->Width) &&
2483 (This->ddraw_height == pMode->Height) &&
2484 (This->ddraw_format == pMode->Format) &&
2485 (pMode->RefreshRate == 0) ) {
2486 return WINED3D_OK;
2489 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2490 if (ret != DISP_CHANGE_SUCCESSFUL) {
2491 if(devmode.dmDisplayFrequency != 0) {
2492 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2493 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2494 devmode.dmDisplayFrequency = 0;
2495 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2497 if(ret != DISP_CHANGE_SUCCESSFUL) {
2498 return WINED3DERR_NOTAVAILABLE;
2502 /* Store the new values */
2503 This->ddraw_width = pMode->Width;
2504 This->ddraw_height = pMode->Height;
2505 This->ddraw_format = pMode->Format;
2507 /* And finally clip mouse to our screen */
2508 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2509 ClipCursor(&clip_rc);
2511 return WINED3D_OK;
2514 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2516 *ppD3D= This->wineD3D;
2517 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2518 IWineD3D_AddRef(*ppD3D);
2519 return WINED3D_OK;
2522 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2525 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2526 (This->adapter->TextureRam/(1024*1024)),
2527 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2528 /* return simulated texture memory left */
2529 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2532 /*****
2533 * Get / Set Stream Source
2534 *****/
2535 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2537 IWineD3DVertexBuffer *oldSrc;
2539 if (StreamNumber >= MAX_STREAMS) {
2540 WARN("Stream out of range %d\n", StreamNumber);
2541 return WINED3DERR_INVALIDCALL;
2542 } else if(OffsetInBytes & 0x3) {
2543 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2544 return WINED3DERR_INVALIDCALL;
2547 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2548 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2550 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2552 if(oldSrc == pStreamData &&
2553 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2554 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2555 TRACE("Application is setting the old values over, nothing to do\n");
2556 return WINED3D_OK;
2559 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2560 if (pStreamData) {
2561 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2562 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2565 /* Handle recording of state blocks */
2566 if (This->isRecordingState) {
2567 TRACE("Recording... not performing anything\n");
2568 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2569 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2570 return WINED3D_OK;
2573 /* Need to do a getParent and pass the references up */
2574 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2575 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2576 so for now, just count internally */
2577 if (pStreamData != NULL) {
2578 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2579 InterlockedIncrement(&vbImpl->bindCount);
2580 IWineD3DVertexBuffer_AddRef(pStreamData);
2582 if (oldSrc != NULL) {
2583 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2584 IWineD3DVertexBuffer_Release(oldSrc);
2587 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2589 return WINED3D_OK;
2592 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2595 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2596 This->stateBlock->streamSource[StreamNumber],
2597 This->stateBlock->streamOffset[StreamNumber],
2598 This->stateBlock->streamStride[StreamNumber]);
2600 if (StreamNumber >= MAX_STREAMS) {
2601 WARN("Stream out of range %d\n", StreamNumber);
2602 return WINED3DERR_INVALIDCALL;
2604 *pStream = This->stateBlock->streamSource[StreamNumber];
2605 *pStride = This->stateBlock->streamStride[StreamNumber];
2606 if (pOffset) {
2607 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2610 if (*pStream != NULL) {
2611 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2613 return WINED3D_OK;
2616 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2618 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2619 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2621 /* Verify input at least in d3d9 this is invalid*/
2622 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2623 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2624 return WINED3DERR_INVALIDCALL;
2626 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2627 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2628 return WINED3DERR_INVALIDCALL;
2630 if( Divider == 0 ){
2631 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2632 return WINED3DERR_INVALIDCALL;
2635 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2636 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2638 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2639 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2641 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2642 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2643 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2646 return WINED3D_OK;
2649 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2652 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2653 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2655 TRACE("(%p) : returning %d\n", This, *Divider);
2657 return WINED3D_OK;
2660 /*****
2661 * Get / Set & Multiply Transform
2662 *****/
2663 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2666 /* Most of this routine, comments included copied from ddraw tree initially: */
2667 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2669 /* Handle recording of state blocks */
2670 if (This->isRecordingState) {
2671 TRACE("Recording... not performing anything\n");
2672 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2673 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2674 return WINED3D_OK;
2678 * If the new matrix is the same as the current one,
2679 * we cut off any further processing. this seems to be a reasonable
2680 * optimization because as was noticed, some apps (warcraft3 for example)
2681 * tend towards setting the same matrix repeatedly for some reason.
2683 * From here on we assume that the new matrix is different, wherever it matters.
2685 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2686 TRACE("The app is setting the same matrix over again\n");
2687 return WINED3D_OK;
2688 } else {
2689 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2693 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2694 where ViewMat = Camera space, WorldMat = world space.
2696 In OpenGL, camera and world space is combined into GL_MODELVIEW
2697 matrix. The Projection matrix stay projection matrix.
2700 /* Capture the times we can just ignore the change for now */
2701 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2702 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2703 /* Handled by the state manager */
2706 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2707 return WINED3D_OK;
2710 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2712 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2713 *pMatrix = This->stateBlock->transforms[State];
2714 return WINED3D_OK;
2717 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2718 const WINED3DMATRIX *mat = NULL;
2719 WINED3DMATRIX temp;
2721 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2722 * below means it will be recorded in a state block change, but it
2723 * works regardless where it is recorded.
2724 * If this is found to be wrong, change to StateBlock.
2726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2727 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2729 if (State < HIGHEST_TRANSFORMSTATE)
2731 mat = &This->updateStateBlock->transforms[State];
2732 } else {
2733 FIXME("Unhandled transform state!!\n");
2736 multiply_matrix(&temp, mat, pMatrix);
2738 /* Apply change via set transform - will reapply to eg. lights this way */
2739 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2742 /*****
2743 * Get / Set Light
2744 *****/
2745 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2746 you can reference any indexes you want as long as that number max are enabled at any
2747 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2748 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2749 but when recording, just build a chain pretty much of commands to be replayed. */
2751 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2752 float rho;
2753 PLIGHTINFOEL *object = NULL;
2754 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2755 struct list *e;
2757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2758 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2760 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2761 * the gl driver.
2763 if(!pLight) {
2764 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2765 return WINED3DERR_INVALIDCALL;
2768 switch(pLight->Type) {
2769 case WINED3DLIGHT_POINT:
2770 case WINED3DLIGHT_SPOT:
2771 case WINED3DLIGHT_PARALLELPOINT:
2772 case WINED3DLIGHT_GLSPOT:
2773 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2774 * most wanted
2776 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2777 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2778 return WINED3DERR_INVALIDCALL;
2780 break;
2782 case WINED3DLIGHT_DIRECTIONAL:
2783 /* Ignores attenuation */
2784 break;
2786 default:
2787 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2788 return WINED3DERR_INVALIDCALL;
2791 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2792 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2793 if(object->OriginalIndex == Index) break;
2794 object = NULL;
2797 if(!object) {
2798 TRACE("Adding new light\n");
2799 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2800 if(!object) {
2801 ERR("Out of memory error when allocating a light\n");
2802 return E_OUTOFMEMORY;
2804 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2805 object->glIndex = -1;
2806 object->OriginalIndex = Index;
2807 object->changed = TRUE;
2810 /* Initialize the object */
2811 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,
2812 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2813 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2814 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2815 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2816 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2817 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2819 /* Save away the information */
2820 object->OriginalParms = *pLight;
2822 switch (pLight->Type) {
2823 case WINED3DLIGHT_POINT:
2824 /* Position */
2825 object->lightPosn[0] = pLight->Position.x;
2826 object->lightPosn[1] = pLight->Position.y;
2827 object->lightPosn[2] = pLight->Position.z;
2828 object->lightPosn[3] = 1.0f;
2829 object->cutoff = 180.0f;
2830 /* FIXME: Range */
2831 break;
2833 case WINED3DLIGHT_DIRECTIONAL:
2834 /* Direction */
2835 object->lightPosn[0] = -pLight->Direction.x;
2836 object->lightPosn[1] = -pLight->Direction.y;
2837 object->lightPosn[2] = -pLight->Direction.z;
2838 object->lightPosn[3] = 0.0;
2839 object->exponent = 0.0f;
2840 object->cutoff = 180.0f;
2841 break;
2843 case WINED3DLIGHT_SPOT:
2844 /* Position */
2845 object->lightPosn[0] = pLight->Position.x;
2846 object->lightPosn[1] = pLight->Position.y;
2847 object->lightPosn[2] = pLight->Position.z;
2848 object->lightPosn[3] = 1.0;
2850 /* Direction */
2851 object->lightDirn[0] = pLight->Direction.x;
2852 object->lightDirn[1] = pLight->Direction.y;
2853 object->lightDirn[2] = pLight->Direction.z;
2854 object->lightDirn[3] = 1.0;
2857 * opengl-ish and d3d-ish spot lights use too different models for the
2858 * light "intensity" as a function of the angle towards the main light direction,
2859 * so we only can approximate very roughly.
2860 * however spot lights are rather rarely used in games (if ever used at all).
2861 * furthermore if still used, probably nobody pays attention to such details.
2863 if (pLight->Falloff == 0) {
2864 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2865 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2866 * will always be 1.0 for both of them, and we don't have to care for the
2867 * rest of the rather complex calculation
2869 object->exponent = 0;
2870 } else {
2871 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2872 if (rho < 0.0001) rho = 0.0001f;
2873 object->exponent = -0.3/log(cos(rho/2));
2875 if (object->exponent > 128.0) {
2876 object->exponent = 128.0;
2878 object->cutoff = pLight->Phi*90/M_PI;
2880 /* FIXME: Range */
2881 break;
2883 default:
2884 FIXME("Unrecognized light type %d\n", pLight->Type);
2887 /* Update the live definitions if the light is currently assigned a glIndex */
2888 if (object->glIndex != -1 && !This->isRecordingState) {
2889 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2891 return WINED3D_OK;
2894 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2895 PLIGHTINFOEL *lightInfo = NULL;
2896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2897 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2898 struct list *e;
2899 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2901 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2902 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2903 if(lightInfo->OriginalIndex == Index) break;
2904 lightInfo = NULL;
2907 if (lightInfo == NULL) {
2908 TRACE("Light information requested but light not defined\n");
2909 return WINED3DERR_INVALIDCALL;
2912 *pLight = lightInfo->OriginalParms;
2913 return WINED3D_OK;
2916 /*****
2917 * Get / Set Light Enable
2918 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2919 *****/
2920 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2921 PLIGHTINFOEL *lightInfo = NULL;
2922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2923 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2924 struct list *e;
2925 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2927 /* Tests show true = 128...not clear why */
2928 Enable = Enable? 128: 0;
2930 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2931 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2932 if(lightInfo->OriginalIndex == Index) break;
2933 lightInfo = NULL;
2935 TRACE("Found light: %p\n", lightInfo);
2937 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2938 if (lightInfo == NULL) {
2940 TRACE("Light enabled requested but light not defined, so defining one!\n");
2941 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2943 /* Search for it again! Should be fairly quick as near head of list */
2944 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2945 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2946 if(lightInfo->OriginalIndex == Index) break;
2947 lightInfo = NULL;
2949 if (lightInfo == NULL) {
2950 FIXME("Adding default lights has failed dismally\n");
2951 return WINED3DERR_INVALIDCALL;
2955 lightInfo->enabledChanged = TRUE;
2956 if(!Enable) {
2957 if(lightInfo->glIndex != -1) {
2958 if(!This->isRecordingState) {
2959 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2962 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2963 lightInfo->glIndex = -1;
2964 } else {
2965 TRACE("Light already disabled, nothing to do\n");
2967 lightInfo->enabled = FALSE;
2968 } else {
2969 lightInfo->enabled = TRUE;
2970 if (lightInfo->glIndex != -1) {
2971 /* nop */
2972 TRACE("Nothing to do as light was enabled\n");
2973 } else {
2974 int i;
2975 /* Find a free gl light */
2976 for(i = 0; i < This->maxConcurrentLights; i++) {
2977 if(This->updateStateBlock->activeLights[i] == NULL) {
2978 This->updateStateBlock->activeLights[i] = lightInfo;
2979 lightInfo->glIndex = i;
2980 break;
2983 if(lightInfo->glIndex == -1) {
2984 /* Our tests show that Windows returns D3D_OK in this situation, even with
2985 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2986 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2987 * as well for those lights.
2989 * TODO: Test how this affects rendering
2991 WARN("Too many concurrently active lights\n");
2992 return WINED3D_OK;
2995 /* i == lightInfo->glIndex */
2996 if(!This->isRecordingState) {
2997 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3002 return WINED3D_OK;
3005 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3007 PLIGHTINFOEL *lightInfo = NULL;
3008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3009 struct list *e;
3010 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3011 TRACE("(%p) : for idx(%d)\n", This, Index);
3013 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3014 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3015 if(lightInfo->OriginalIndex == Index) break;
3016 lightInfo = NULL;
3019 if (lightInfo == NULL) {
3020 TRACE("Light enabled state requested but light not defined\n");
3021 return WINED3DERR_INVALIDCALL;
3023 /* true is 128 according to SetLightEnable */
3024 *pEnable = lightInfo->enabled ? 128 : 0;
3025 return WINED3D_OK;
3028 /*****
3029 * Get / Set Clip Planes
3030 *****/
3031 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3033 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3035 /* Validate Index */
3036 if (Index >= GL_LIMITS(clipplanes)) {
3037 TRACE("Application has requested clipplane this device doesn't support\n");
3038 return WINED3DERR_INVALIDCALL;
3041 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3043 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3044 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3045 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3046 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3047 TRACE("Application is setting old values over, nothing to do\n");
3048 return WINED3D_OK;
3051 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3052 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3053 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3054 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3056 /* Handle recording of state blocks */
3057 if (This->isRecordingState) {
3058 TRACE("Recording... not performing anything\n");
3059 return WINED3D_OK;
3062 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3064 return WINED3D_OK;
3067 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3069 TRACE("(%p) : for idx %d\n", This, Index);
3071 /* Validate Index */
3072 if (Index >= GL_LIMITS(clipplanes)) {
3073 TRACE("Application has requested clipplane this device doesn't support\n");
3074 return WINED3DERR_INVALIDCALL;
3077 pPlane[0] = This->stateBlock->clipplane[Index][0];
3078 pPlane[1] = This->stateBlock->clipplane[Index][1];
3079 pPlane[2] = This->stateBlock->clipplane[Index][2];
3080 pPlane[3] = This->stateBlock->clipplane[Index][3];
3081 return WINED3D_OK;
3084 /*****
3085 * Get / Set Clip Plane Status
3086 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3087 *****/
3088 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3090 FIXME("(%p) : stub\n", This);
3091 if (NULL == pClipStatus) {
3092 return WINED3DERR_INVALIDCALL;
3094 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3095 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3096 return WINED3D_OK;
3099 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3101 FIXME("(%p) : stub\n", This);
3102 if (NULL == pClipStatus) {
3103 return WINED3DERR_INVALIDCALL;
3105 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3106 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3107 return WINED3D_OK;
3110 /*****
3111 * Get / Set Material
3112 *****/
3113 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3114 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3116 This->updateStateBlock->changed.material = TRUE;
3117 This->updateStateBlock->material = *pMaterial;
3119 /* Handle recording of state blocks */
3120 if (This->isRecordingState) {
3121 TRACE("Recording... not performing anything\n");
3122 return WINED3D_OK;
3125 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3126 return WINED3D_OK;
3129 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3131 *pMaterial = This->updateStateBlock->material;
3132 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3133 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3134 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3135 pMaterial->Ambient.b, pMaterial->Ambient.a);
3136 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3137 pMaterial->Specular.b, pMaterial->Specular.a);
3138 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3139 pMaterial->Emissive.b, pMaterial->Emissive.a);
3140 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3142 return WINED3D_OK;
3145 /*****
3146 * Get / Set Indices
3147 *****/
3148 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3150 IWineD3DIndexBuffer *oldIdxs;
3152 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3153 oldIdxs = This->updateStateBlock->pIndexData;
3155 This->updateStateBlock->changed.indices = TRUE;
3156 This->updateStateBlock->pIndexData = pIndexData;
3158 /* Handle recording of state blocks */
3159 if (This->isRecordingState) {
3160 TRACE("Recording... not performing anything\n");
3161 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3162 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3163 return WINED3D_OK;
3166 if(oldIdxs != pIndexData) {
3167 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3168 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3169 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3171 return WINED3D_OK;
3174 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3177 *ppIndexData = This->stateBlock->pIndexData;
3179 /* up ref count on ppindexdata */
3180 if (*ppIndexData) {
3181 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3182 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3183 }else{
3184 TRACE("(%p) No index data set\n", This);
3186 TRACE("Returning %p\n", *ppIndexData);
3188 return WINED3D_OK;
3191 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3192 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3194 TRACE("(%p)->(%d)\n", This, BaseIndex);
3196 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3197 TRACE("Application is setting the old value over, nothing to do\n");
3198 return WINED3D_OK;
3201 This->updateStateBlock->baseVertexIndex = BaseIndex;
3203 if (This->isRecordingState) {
3204 TRACE("Recording... not performing anything\n");
3205 return WINED3D_OK;
3207 /* The base vertex index affects the stream sources */
3208 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3209 return WINED3D_OK;
3212 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3214 TRACE("(%p) : base_index %p\n", This, base_index);
3216 *base_index = This->stateBlock->baseVertexIndex;
3218 TRACE("Returning %u\n", *base_index);
3220 return WINED3D_OK;
3223 /*****
3224 * Get / Set Viewports
3225 *****/
3226 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3229 TRACE("(%p)\n", This);
3230 This->updateStateBlock->changed.viewport = TRUE;
3231 This->updateStateBlock->viewport = *pViewport;
3233 /* Handle recording of state blocks */
3234 if (This->isRecordingState) {
3235 TRACE("Recording... not performing anything\n");
3236 return WINED3D_OK;
3239 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3240 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3242 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3243 return WINED3D_OK;
3247 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3249 TRACE("(%p)\n", This);
3250 *pViewport = This->stateBlock->viewport;
3251 return WINED3D_OK;
3254 /*****
3255 * Get / Set Render States
3256 * TODO: Verify against dx9 definitions
3257 *****/
3258 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3261 DWORD oldValue = This->stateBlock->renderState[State];
3263 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3265 This->updateStateBlock->changed.renderState[State] = TRUE;
3266 This->updateStateBlock->renderState[State] = Value;
3268 /* Handle recording of state blocks */
3269 if (This->isRecordingState) {
3270 TRACE("Recording... not performing anything\n");
3271 return WINED3D_OK;
3274 /* Compared here and not before the assignment to allow proper stateblock recording */
3275 if(Value == oldValue) {
3276 TRACE("Application is setting the old value over, nothing to do\n");
3277 } else {
3278 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3281 return WINED3D_OK;
3284 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3286 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3287 *pValue = This->stateBlock->renderState[State];
3288 return WINED3D_OK;
3291 /*****
3292 * Get / Set Sampler States
3293 * TODO: Verify against dx9 definitions
3294 *****/
3296 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3298 DWORD oldValue;
3300 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3301 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3303 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3304 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3307 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3308 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3309 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3312 * SetSampler is designed to allow for more than the standard up to 8 textures
3313 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3314 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3316 * http://developer.nvidia.com/object/General_FAQ.html#t6
3318 * There are two new settings for GForce
3319 * the sampler one:
3320 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3321 * and the texture one:
3322 * GL_MAX_TEXTURE_COORDS_ARB.
3323 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3324 ******************/
3326 oldValue = This->stateBlock->samplerState[Sampler][Type];
3327 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3328 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3330 /* Handle recording of state blocks */
3331 if (This->isRecordingState) {
3332 TRACE("Recording... not performing anything\n");
3333 return WINED3D_OK;
3336 if(oldValue == Value) {
3337 TRACE("Application is setting the old value over, nothing to do\n");
3338 return WINED3D_OK;
3341 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3343 return WINED3D_OK;
3346 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3347 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3349 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3350 This, Sampler, debug_d3dsamplerstate(Type), Type);
3352 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3353 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3356 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3357 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3358 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3360 *Value = This->stateBlock->samplerState[Sampler][Type];
3361 TRACE("(%p) : Returning %#x\n", This, *Value);
3363 return WINED3D_OK;
3366 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3369 This->updateStateBlock->changed.scissorRect = TRUE;
3370 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3371 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3372 return WINED3D_OK;
3374 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3376 if(This->isRecordingState) {
3377 TRACE("Recording... not performing anything\n");
3378 return WINED3D_OK;
3381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3383 return WINED3D_OK;
3386 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3389 *pRect = This->updateStateBlock->scissorRect;
3390 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3391 return WINED3D_OK;
3394 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3396 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3398 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3400 This->updateStateBlock->vertexDecl = pDecl;
3401 This->updateStateBlock->changed.vertexDecl = TRUE;
3403 if (This->isRecordingState) {
3404 TRACE("Recording... not performing anything\n");
3405 return WINED3D_OK;
3406 } else if(pDecl == oldDecl) {
3407 /* Checked after the assignment to allow proper stateblock recording */
3408 TRACE("Application is setting the old declaration over, nothing to do\n");
3409 return WINED3D_OK;
3412 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3413 return WINED3D_OK;
3416 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3419 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3421 *ppDecl = This->stateBlock->vertexDecl;
3422 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3423 return WINED3D_OK;
3426 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3428 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3430 This->updateStateBlock->vertexShader = pShader;
3431 This->updateStateBlock->changed.vertexShader = TRUE;
3433 if (This->isRecordingState) {
3434 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3435 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3436 TRACE("Recording... not performing anything\n");
3437 return WINED3D_OK;
3438 } else if(oldShader == pShader) {
3439 /* Checked here to allow proper stateblock recording */
3440 TRACE("App is setting the old shader over, nothing to do\n");
3441 return WINED3D_OK;
3444 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3445 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3446 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3448 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3450 return WINED3D_OK;
3453 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3456 if (NULL == ppShader) {
3457 return WINED3DERR_INVALIDCALL;
3459 *ppShader = This->stateBlock->vertexShader;
3460 if( NULL != *ppShader)
3461 IWineD3DVertexShader_AddRef(*ppShader);
3463 TRACE("(%p) : returning %p\n", This, *ppShader);
3464 return WINED3D_OK;
3467 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3468 IWineD3DDevice *iface,
3469 UINT start,
3470 CONST BOOL *srcData,
3471 UINT count) {
3473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3474 int i, cnt = min(count, MAX_CONST_B - start);
3476 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3477 iface, srcData, start, count);
3479 if (srcData == NULL || cnt < 0)
3480 return WINED3DERR_INVALIDCALL;
3482 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3483 for (i = 0; i < cnt; i++)
3484 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3486 for (i = start; i < cnt + start; ++i) {
3487 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3490 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3492 return WINED3D_OK;
3495 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3496 IWineD3DDevice *iface,
3497 UINT start,
3498 BOOL *dstData,
3499 UINT count) {
3501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3502 int cnt = min(count, MAX_CONST_B - start);
3504 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3505 iface, dstData, start, count);
3507 if (dstData == NULL || cnt < 0)
3508 return WINED3DERR_INVALIDCALL;
3510 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3511 return WINED3D_OK;
3514 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3515 IWineD3DDevice *iface,
3516 UINT start,
3517 CONST int *srcData,
3518 UINT count) {
3520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3521 int i, cnt = min(count, MAX_CONST_I - start);
3523 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3524 iface, srcData, start, count);
3526 if (srcData == NULL || cnt < 0)
3527 return WINED3DERR_INVALIDCALL;
3529 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3530 for (i = 0; i < cnt; i++)
3531 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3532 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3534 for (i = start; i < cnt + start; ++i) {
3535 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3538 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3540 return WINED3D_OK;
3543 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3544 IWineD3DDevice *iface,
3545 UINT start,
3546 int *dstData,
3547 UINT count) {
3549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3550 int cnt = min(count, MAX_CONST_I - start);
3552 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3553 iface, dstData, start, count);
3555 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3556 return WINED3DERR_INVALIDCALL;
3558 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3559 return WINED3D_OK;
3562 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3563 IWineD3DDevice *iface,
3564 UINT start,
3565 CONST float *srcData,
3566 UINT count) {
3568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3569 UINT i;
3571 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3572 iface, srcData, start, count);
3574 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3575 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3576 return WINED3DERR_INVALIDCALL;
3578 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3579 if(TRACE_ON(d3d)) {
3580 for (i = 0; i < count; i++)
3581 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3582 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3585 if (!This->isRecordingState)
3587 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3588 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3591 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3592 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3594 return WINED3D_OK;
3597 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3598 IWineD3DDevice *iface,
3599 UINT start,
3600 float *dstData,
3601 UINT count) {
3603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3604 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3606 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3607 iface, dstData, start, count);
3609 if (dstData == NULL || cnt < 0)
3610 return WINED3DERR_INVALIDCALL;
3612 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3613 return WINED3D_OK;
3616 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3617 DWORD i;
3618 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3619 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3623 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3624 int i = This->rev_tex_unit_map[unit];
3625 int j = This->texUnitMap[stage];
3627 This->texUnitMap[stage] = unit;
3628 if (i != -1 && i != stage) {
3629 This->texUnitMap[i] = -1;
3632 This->rev_tex_unit_map[unit] = stage;
3633 if (j != -1 && j != unit) {
3634 This->rev_tex_unit_map[j] = -1;
3638 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3639 int i;
3641 for (i = 0; i < MAX_TEXTURES; ++i) {
3642 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3643 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3644 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3645 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3646 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3647 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3648 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3649 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3651 if (color_op == WINED3DTOP_DISABLE) {
3652 /* Not used, and disable higher stages */
3653 while (i < MAX_TEXTURES) {
3654 This->fixed_function_usage_map[i] = FALSE;
3655 ++i;
3657 break;
3660 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3661 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3662 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3663 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3664 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3665 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3666 This->fixed_function_usage_map[i] = TRUE;
3667 } else {
3668 This->fixed_function_usage_map[i] = FALSE;
3671 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3672 This->fixed_function_usage_map[i+1] = TRUE;
3677 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3678 int i, tex;
3680 device_update_fixed_function_usage_map(This);
3682 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3683 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3684 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3685 if (!This->fixed_function_usage_map[i]) continue;
3687 if (This->texUnitMap[i] != i) {
3688 device_map_stage(This, i, i);
3689 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3690 markTextureStagesDirty(This, i);
3693 return;
3696 /* Now work out the mapping */
3697 tex = 0;
3698 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3699 if (!This->fixed_function_usage_map[i]) continue;
3701 if (This->texUnitMap[i] != tex) {
3702 device_map_stage(This, i, tex);
3703 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3704 markTextureStagesDirty(This, i);
3707 ++tex;
3711 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3712 const DWORD *sampler_tokens =
3713 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3714 int i;
3716 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3717 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3718 device_map_stage(This, i, i);
3719 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3720 if (i < MAX_TEXTURES) {
3721 markTextureStagesDirty(This, i);
3727 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3728 const DWORD *vshader_sampler_tokens, int unit)
3730 int current_mapping = This->rev_tex_unit_map[unit];
3732 if (current_mapping == -1) {
3733 /* Not currently used */
3734 return TRUE;
3737 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3738 /* Used by a fragment sampler */
3740 if (!pshader_sampler_tokens) {
3741 /* No pixel shader, check fixed function */
3742 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3745 /* Pixel shader, check the shader's sampler map */
3746 return !pshader_sampler_tokens[current_mapping];
3749 /* Used by a vertex sampler */
3750 return !vshader_sampler_tokens[current_mapping];
3753 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3754 const DWORD *vshader_sampler_tokens =
3755 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3756 const DWORD *pshader_sampler_tokens = NULL;
3757 int start = GL_LIMITS(combined_samplers) - 1;
3758 int i;
3760 if (ps) {
3761 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3763 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3764 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3765 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3768 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3769 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3770 if (vshader_sampler_tokens[i]) {
3771 if (This->texUnitMap[vsampler_idx] != -1) {
3772 /* Already mapped somewhere */
3773 continue;
3776 while (start >= 0) {
3777 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3778 device_map_stage(This, vsampler_idx, start);
3779 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3781 --start;
3782 break;
3785 --start;
3791 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3792 BOOL vs = use_vs(This);
3793 BOOL ps = use_ps(This);
3795 * Rules are:
3796 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3797 * that would be really messy and require shader recompilation
3798 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3799 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3801 if (ps) {
3802 device_map_psamplers(This);
3803 } else {
3804 device_map_fixed_function_samplers(This);
3807 if (vs) {
3808 device_map_vsamplers(This, ps);
3812 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3813 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3814 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3815 This->updateStateBlock->pixelShader = pShader;
3816 This->updateStateBlock->changed.pixelShader = TRUE;
3818 /* Handle recording of state blocks */
3819 if (This->isRecordingState) {
3820 TRACE("Recording... not performing anything\n");
3823 if (This->isRecordingState) {
3824 TRACE("Recording... not performing anything\n");
3825 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3826 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3827 return WINED3D_OK;
3830 if(pShader == oldShader) {
3831 TRACE("App is setting the old pixel shader over, nothing to do\n");
3832 return WINED3D_OK;
3835 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3836 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3838 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3839 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3841 return WINED3D_OK;
3844 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3847 if (NULL == ppShader) {
3848 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3849 return WINED3DERR_INVALIDCALL;
3852 *ppShader = This->stateBlock->pixelShader;
3853 if (NULL != *ppShader) {
3854 IWineD3DPixelShader_AddRef(*ppShader);
3856 TRACE("(%p) : returning %p\n", This, *ppShader);
3857 return WINED3D_OK;
3860 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3861 IWineD3DDevice *iface,
3862 UINT start,
3863 CONST BOOL *srcData,
3864 UINT count) {
3866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3867 int i, cnt = min(count, MAX_CONST_B - start);
3869 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3870 iface, srcData, start, count);
3872 if (srcData == NULL || cnt < 0)
3873 return WINED3DERR_INVALIDCALL;
3875 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3876 for (i = 0; i < cnt; i++)
3877 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3879 for (i = start; i < cnt + start; ++i) {
3880 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3883 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3885 return WINED3D_OK;
3888 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3889 IWineD3DDevice *iface,
3890 UINT start,
3891 BOOL *dstData,
3892 UINT count) {
3894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3895 int cnt = min(count, MAX_CONST_B - start);
3897 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3898 iface, dstData, start, count);
3900 if (dstData == NULL || cnt < 0)
3901 return WINED3DERR_INVALIDCALL;
3903 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3904 return WINED3D_OK;
3907 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3908 IWineD3DDevice *iface,
3909 UINT start,
3910 CONST int *srcData,
3911 UINT count) {
3913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3914 int i, cnt = min(count, MAX_CONST_I - start);
3916 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3917 iface, srcData, start, count);
3919 if (srcData == NULL || cnt < 0)
3920 return WINED3DERR_INVALIDCALL;
3922 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3923 for (i = 0; i < cnt; i++)
3924 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3925 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3927 for (i = start; i < cnt + start; ++i) {
3928 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3931 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3933 return WINED3D_OK;
3936 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3937 IWineD3DDevice *iface,
3938 UINT start,
3939 int *dstData,
3940 UINT count) {
3942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3943 int cnt = min(count, MAX_CONST_I - start);
3945 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3946 iface, dstData, start, count);
3948 if (dstData == NULL || cnt < 0)
3949 return WINED3DERR_INVALIDCALL;
3951 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3952 return WINED3D_OK;
3955 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3956 IWineD3DDevice *iface,
3957 UINT start,
3958 CONST float *srcData,
3959 UINT count) {
3961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3962 UINT i;
3964 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3965 iface, srcData, start, count);
3967 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3968 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3969 return WINED3DERR_INVALIDCALL;
3971 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3972 if(TRACE_ON(d3d)) {
3973 for (i = 0; i < count; i++)
3974 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3975 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3978 if (!This->isRecordingState)
3980 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3981 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3984 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3985 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3987 return WINED3D_OK;
3990 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3991 IWineD3DDevice *iface,
3992 UINT start,
3993 float *dstData,
3994 UINT count) {
3996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3997 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3999 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4000 iface, dstData, start, count);
4002 if (dstData == NULL || cnt < 0)
4003 return WINED3DERR_INVALIDCALL;
4005 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4006 return WINED3D_OK;
4009 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4010 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4011 const WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags)
4013 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4014 unsigned int i;
4015 DWORD DestFVF = dest->fvf;
4016 WINED3DVIEWPORT vp;
4017 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4018 BOOL doClip;
4019 DWORD numTextures;
4021 if (lpStrideData->u.s.normal.lpData) {
4022 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4025 if (lpStrideData->u.s.position.lpData == NULL) {
4026 ERR("Source has no position mask\n");
4027 return WINED3DERR_INVALIDCALL;
4030 /* We might access VBOs from this code, so hold the lock */
4031 ENTER_GL();
4033 if (dest->resource.allocatedMemory == NULL) {
4034 /* This may happen if we do direct locking into a vbo. Unlikely,
4035 * but theoretically possible(ddraw processvertices test)
4037 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4038 if(!dest->resource.allocatedMemory) {
4039 LEAVE_GL();
4040 ERR("Out of memory\n");
4041 return E_OUTOFMEMORY;
4043 if(dest->vbo) {
4044 const void *src;
4045 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4046 checkGLcall("glBindBufferARB");
4047 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4048 if(src) {
4049 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4051 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4052 checkGLcall("glUnmapBufferARB");
4056 /* Get a pointer into the destination vbo(create one if none exists) and
4057 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4059 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4060 dest->Flags |= VBFLAG_CREATEVBO;
4061 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4064 if(dest->vbo) {
4065 unsigned char extrabytes = 0;
4066 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4067 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4068 * this may write 4 extra bytes beyond the area that should be written
4070 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4071 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4072 if(!dest_conv_addr) {
4073 ERR("Out of memory\n");
4074 /* Continue without storing converted vertices */
4076 dest_conv = dest_conv_addr;
4079 /* Should I clip?
4080 * a) WINED3DRS_CLIPPING is enabled
4081 * b) WINED3DVOP_CLIP is passed
4083 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4084 static BOOL warned = FALSE;
4086 * The clipping code is not quite correct. Some things need
4087 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4088 * so disable clipping for now.
4089 * (The graphics in Half-Life are broken, and my processvertices
4090 * test crashes with IDirect3DDevice3)
4091 doClip = TRUE;
4093 doClip = FALSE;
4094 if(!warned) {
4095 warned = TRUE;
4096 FIXME("Clipping is broken and disabled for now\n");
4098 } else doClip = FALSE;
4099 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4101 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4102 WINED3DTS_VIEW,
4103 &view_mat);
4104 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4105 WINED3DTS_PROJECTION,
4106 &proj_mat);
4107 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4108 WINED3DTS_WORLDMATRIX(0),
4109 &world_mat);
4111 TRACE("View mat:\n");
4112 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);
4113 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);
4114 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);
4115 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);
4117 TRACE("Proj mat:\n");
4118 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);
4119 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);
4120 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);
4121 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);
4123 TRACE("World mat:\n");
4124 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);
4125 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);
4126 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);
4127 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);
4129 /* Get the viewport */
4130 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4131 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4132 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4134 multiply_matrix(&mat,&view_mat,&world_mat);
4135 multiply_matrix(&mat,&proj_mat,&mat);
4137 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4139 for (i = 0; i < dwCount; i+= 1) {
4140 unsigned int tex_index;
4142 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4143 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4144 /* The position first */
4145 const float *p =
4146 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4147 float x, y, z, rhw;
4148 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4150 /* Multiplication with world, view and projection matrix */
4151 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);
4152 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);
4153 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);
4154 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);
4156 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4158 /* WARNING: The following things are taken from d3d7 and were not yet checked
4159 * against d3d8 or d3d9!
4162 /* Clipping conditions: From msdn
4164 * A vertex is clipped if it does not match the following requirements
4165 * -rhw < x <= rhw
4166 * -rhw < y <= rhw
4167 * 0 < z <= rhw
4168 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4170 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4171 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4175 if( !doClip ||
4176 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4177 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4178 ( rhw > eps ) ) ) {
4180 /* "Normal" viewport transformation (not clipped)
4181 * 1) The values are divided by rhw
4182 * 2) The y axis is negative, so multiply it with -1
4183 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4184 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4185 * 4) Multiply x with Width/2 and add Width/2
4186 * 5) The same for the height
4187 * 6) Add the viewpoint X and Y to the 2D coordinates and
4188 * The minimum Z value to z
4189 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4191 * Well, basically it's simply a linear transformation into viewport
4192 * coordinates
4195 x /= rhw;
4196 y /= rhw;
4197 z /= rhw;
4199 y *= -1;
4201 x *= vp.Width / 2;
4202 y *= vp.Height / 2;
4203 z *= vp.MaxZ - vp.MinZ;
4205 x += vp.Width / 2 + vp.X;
4206 y += vp.Height / 2 + vp.Y;
4207 z += vp.MinZ;
4209 rhw = 1 / rhw;
4210 } else {
4211 /* That vertex got clipped
4212 * Contrary to OpenGL it is not dropped completely, it just
4213 * undergoes a different calculation.
4215 TRACE("Vertex got clipped\n");
4216 x += rhw;
4217 y += rhw;
4219 x /= 2;
4220 y /= 2;
4222 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4223 * outside of the main vertex buffer memory. That needs some more
4224 * investigation...
4228 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4231 ( (float *) dest_ptr)[0] = x;
4232 ( (float *) dest_ptr)[1] = y;
4233 ( (float *) dest_ptr)[2] = z;
4234 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4236 dest_ptr += 3 * sizeof(float);
4238 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4239 dest_ptr += sizeof(float);
4242 if(dest_conv) {
4243 float w = 1 / rhw;
4244 ( (float *) dest_conv)[0] = x * w;
4245 ( (float *) dest_conv)[1] = y * w;
4246 ( (float *) dest_conv)[2] = z * w;
4247 ( (float *) dest_conv)[3] = w;
4249 dest_conv += 3 * sizeof(float);
4251 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4252 dest_conv += sizeof(float);
4256 if (DestFVF & WINED3DFVF_PSIZE) {
4257 dest_ptr += sizeof(DWORD);
4258 if(dest_conv) dest_conv += sizeof(DWORD);
4260 if (DestFVF & WINED3DFVF_NORMAL) {
4261 const float *normal =
4262 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4263 /* AFAIK this should go into the lighting information */
4264 FIXME("Didn't expect the destination to have a normal\n");
4265 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4266 if(dest_conv) {
4267 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4271 if (DestFVF & WINED3DFVF_DIFFUSE) {
4272 const DWORD *color_d =
4273 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4274 if(!color_d) {
4275 static BOOL warned = FALSE;
4277 if(!warned) {
4278 ERR("No diffuse color in source, but destination has one\n");
4279 warned = TRUE;
4282 *( (DWORD *) dest_ptr) = 0xffffffff;
4283 dest_ptr += sizeof(DWORD);
4285 if(dest_conv) {
4286 *( (DWORD *) dest_conv) = 0xffffffff;
4287 dest_conv += sizeof(DWORD);
4290 else {
4291 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4292 if(dest_conv) {
4293 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4294 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4295 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4296 dest_conv += sizeof(DWORD);
4301 if (DestFVF & WINED3DFVF_SPECULAR) {
4302 /* What's the color value in the feedback buffer? */
4303 const DWORD *color_s =
4304 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4305 if(!color_s) {
4306 static BOOL warned = FALSE;
4308 if(!warned) {
4309 ERR("No specular color in source, but destination has one\n");
4310 warned = TRUE;
4313 *( (DWORD *) dest_ptr) = 0xFF000000;
4314 dest_ptr += sizeof(DWORD);
4316 if(dest_conv) {
4317 *( (DWORD *) dest_conv) = 0xFF000000;
4318 dest_conv += sizeof(DWORD);
4321 else {
4322 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4323 if(dest_conv) {
4324 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4325 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4326 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4327 dest_conv += sizeof(DWORD);
4332 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4333 const float *tex_coord =
4334 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4335 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4336 if(!tex_coord) {
4337 ERR("No source texture, but destination requests one\n");
4338 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4339 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4341 else {
4342 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4343 if(dest_conv) {
4344 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4350 if(dest_conv) {
4351 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4352 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4353 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4354 dwCount * get_flexible_vertex_size(DestFVF),
4355 dest_conv_addr));
4356 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4357 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4360 LEAVE_GL();
4362 return WINED3D_OK;
4364 #undef copy_and_next
4366 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4368 WineDirect3DVertexStridedData strided;
4369 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4370 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4372 if(pVertexDecl) {
4373 ERR("Output vertex declaration not implemented yet\n");
4376 /* Need any context to write to the vbo. */
4377 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4379 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4380 * control the streamIsUP flag, thus restore it afterwards.
4382 This->stateBlock->streamIsUP = FALSE;
4383 memset(&strided, 0, sizeof(strided));
4384 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4385 This->stateBlock->streamIsUP = streamWasUP;
4387 if(vbo || SrcStartIndex) {
4388 unsigned int i;
4389 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4390 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4392 * Also get the start index in, but only loop over all elements if there's something to add at all.
4394 #define FIXSRC(type) \
4395 if(strided.u.s.type.VBO) { \
4396 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4397 strided.u.s.type.VBO = 0; \
4398 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4399 ENTER_GL(); \
4400 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4401 vb->vbo = 0; \
4402 LEAVE_GL(); \
4404 if(strided.u.s.type.lpData) { \
4405 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4407 FIXSRC(position);
4408 FIXSRC(blendWeights);
4409 FIXSRC(blendMatrixIndices);
4410 FIXSRC(normal);
4411 FIXSRC(pSize);
4412 FIXSRC(diffuse);
4413 FIXSRC(specular);
4414 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4415 FIXSRC(texCoords[i]);
4417 FIXSRC(position2);
4418 FIXSRC(normal2);
4419 FIXSRC(tangent);
4420 FIXSRC(binormal);
4421 FIXSRC(tessFactor);
4422 FIXSRC(fog);
4423 FIXSRC(depth);
4424 FIXSRC(sample);
4425 #undef FIXSRC
4428 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4431 /*****
4432 * Get / Set Texture Stage States
4433 * TODO: Verify against dx9 definitions
4434 *****/
4435 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4437 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4439 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4441 if (Stage >= MAX_TEXTURES) {
4442 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4443 return WINED3D_OK;
4446 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4447 This->updateStateBlock->textureState[Stage][Type] = Value;
4449 if (This->isRecordingState) {
4450 TRACE("Recording... not performing anything\n");
4451 return WINED3D_OK;
4454 /* Checked after the assignments to allow proper stateblock recording */
4455 if(oldValue == Value) {
4456 TRACE("App is setting the old value over, nothing to do\n");
4457 return WINED3D_OK;
4460 if(Stage > This->stateBlock->lowest_disabled_stage &&
4461 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4462 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4463 * Changes in other states are important on disabled stages too
4465 return WINED3D_OK;
4468 if(Type == WINED3DTSS_COLOROP) {
4469 int i;
4471 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4472 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4473 * they have to be disabled
4475 * The current stage is dirtified below.
4477 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4478 TRACE("Additionally dirtifying stage %d\n", i);
4479 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4481 This->stateBlock->lowest_disabled_stage = Stage;
4482 TRACE("New lowest disabled: %d\n", Stage);
4483 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4484 /* Previously disabled stage enabled. Stages above it may need enabling
4485 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4486 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4488 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4491 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4492 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4493 break;
4495 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4496 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4498 This->stateBlock->lowest_disabled_stage = i;
4499 TRACE("New lowest disabled: %d\n", i);
4503 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4505 return WINED3D_OK;
4508 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4510 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4511 *pValue = This->updateStateBlock->textureState[Stage][Type];
4512 return WINED3D_OK;
4515 /*****
4516 * Get / Set Texture
4517 *****/
4518 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4520 IWineD3DBaseTexture *oldTexture;
4522 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4524 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4525 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4528 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4529 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4530 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4533 oldTexture = This->updateStateBlock->textures[Stage];
4535 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4536 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4538 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4539 return WINED3DERR_INVALIDCALL;
4542 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4543 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4545 This->updateStateBlock->changed.textures[Stage] = TRUE;
4546 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4547 This->updateStateBlock->textures[Stage] = pTexture;
4549 /* Handle recording of state blocks */
4550 if (This->isRecordingState) {
4551 TRACE("Recording... not performing anything\n");
4552 return WINED3D_OK;
4555 if(oldTexture == pTexture) {
4556 TRACE("App is setting the same texture again, nothing to do\n");
4557 return WINED3D_OK;
4560 /** NOTE: MSDN says that setTexture increases the reference count,
4561 * and that the application must set the texture back to null (or have a leaky application),
4562 * This means we should pass the refcount up to the parent
4563 *******************************/
4564 if (NULL != This->updateStateBlock->textures[Stage]) {
4565 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4566 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4568 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4569 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4570 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4571 * so the COLOROP and ALPHAOP have to be dirtified.
4573 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4574 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4576 if(bindCount == 1) {
4577 new->baseTexture.sampler = Stage;
4579 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4583 if (NULL != oldTexture) {
4584 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4585 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4587 IWineD3DBaseTexture_Release(oldTexture);
4588 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4589 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4590 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4593 if(bindCount && old->baseTexture.sampler == Stage) {
4594 int i;
4595 /* Have to do a search for the other sampler(s) where the texture is bound to
4596 * Shouldn't happen as long as apps bind a texture only to one stage
4598 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4599 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4600 if(This->updateStateBlock->textures[i] == oldTexture) {
4601 old->baseTexture.sampler = i;
4602 break;
4608 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4610 return WINED3D_OK;
4613 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4616 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4618 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4619 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4622 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4623 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4624 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4627 *ppTexture=This->stateBlock->textures[Stage];
4628 if (*ppTexture)
4629 IWineD3DBaseTexture_AddRef(*ppTexture);
4631 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4633 return WINED3D_OK;
4636 /*****
4637 * Get Back Buffer
4638 *****/
4639 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4640 IWineD3DSurface **ppBackBuffer) {
4641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4642 IWineD3DSwapChain *swapChain;
4643 HRESULT hr;
4645 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4647 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4648 if (hr == WINED3D_OK) {
4649 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4650 IWineD3DSwapChain_Release(swapChain);
4651 } else {
4652 *ppBackBuffer = NULL;
4654 return hr;
4657 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4659 WARN("(%p) : stub, calling idirect3d for now\n", This);
4660 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4663 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4665 IWineD3DSwapChain *swapChain;
4666 HRESULT hr;
4668 if(iSwapChain > 0) {
4669 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4670 if (hr == WINED3D_OK) {
4671 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4672 IWineD3DSwapChain_Release(swapChain);
4673 } else {
4674 FIXME("(%p) Error getting display mode\n", This);
4676 } else {
4677 /* Don't read the real display mode,
4678 but return the stored mode instead. X11 can't change the color
4679 depth, and some apps are pretty angry if they SetDisplayMode from
4680 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4682 Also don't relay to the swapchain because with ddraw it's possible
4683 that there isn't a swapchain at all */
4684 pMode->Width = This->ddraw_width;
4685 pMode->Height = This->ddraw_height;
4686 pMode->Format = This->ddraw_format;
4687 pMode->RefreshRate = 0;
4688 hr = WINED3D_OK;
4691 return hr;
4694 /*****
4695 * Stateblock related functions
4696 *****/
4698 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4700 IWineD3DStateBlockImpl *object;
4701 HRESULT temp_result;
4702 int i;
4704 TRACE("(%p)\n", This);
4706 if (This->isRecordingState) {
4707 return WINED3DERR_INVALIDCALL;
4710 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4711 if (NULL == object ) {
4712 FIXME("(%p)Error allocating memory for stateblock\n", This);
4713 return E_OUTOFMEMORY;
4715 TRACE("(%p) created object %p\n", This, object);
4716 object->wineD3DDevice= This;
4717 /** FIXME: object->parent = parent; **/
4718 object->parent = NULL;
4719 object->blockType = WINED3DSBT_RECORDED;
4720 object->ref = 1;
4721 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4723 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4724 list_init(&object->lightMap[i]);
4727 temp_result = allocate_shader_constants(object);
4728 if (WINED3D_OK != temp_result)
4729 return temp_result;
4731 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4732 This->updateStateBlock = object;
4733 This->isRecordingState = TRUE;
4735 TRACE("(%p) recording stateblock %p\n",This , object);
4736 return WINED3D_OK;
4739 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4741 unsigned int i, j;
4742 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4744 if (!This->isRecordingState) {
4745 WARN("(%p) not recording! returning error\n", This);
4746 *ppStateBlock = NULL;
4747 return WINED3DERR_INVALIDCALL;
4750 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4751 if(object->changed.renderState[i]) {
4752 object->contained_render_states[object->num_contained_render_states] = i;
4753 object->num_contained_render_states++;
4756 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4757 if(object->changed.transform[i]) {
4758 object->contained_transform_states[object->num_contained_transform_states] = i;
4759 object->num_contained_transform_states++;
4762 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4763 if(object->changed.vertexShaderConstantsF[i]) {
4764 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4765 object->num_contained_vs_consts_f++;
4768 for(i = 0; i < MAX_CONST_I; i++) {
4769 if (object->changed.vertexShaderConstantsI & (1 << i))
4771 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4772 object->num_contained_vs_consts_i++;
4775 for(i = 0; i < MAX_CONST_B; i++) {
4776 if (object->changed.vertexShaderConstantsB & (1 << i))
4778 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4779 object->num_contained_vs_consts_b++;
4782 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4784 if (object->changed.pixelShaderConstantsF[i])
4786 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4787 ++object->num_contained_ps_consts_f;
4790 for(i = 0; i < MAX_CONST_I; i++) {
4791 if (object->changed.pixelShaderConstantsI & (1 << i))
4793 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4794 object->num_contained_ps_consts_i++;
4797 for(i = 0; i < MAX_CONST_B; i++) {
4798 if (object->changed.pixelShaderConstantsB & (1 << i))
4800 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4801 object->num_contained_ps_consts_b++;
4804 for(i = 0; i < MAX_TEXTURES; i++) {
4805 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4806 if(object->changed.textureState[i][j]) {
4807 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4808 object->contained_tss_states[object->num_contained_tss_states].state = j;
4809 object->num_contained_tss_states++;
4813 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4814 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4815 if(object->changed.samplerState[i][j]) {
4816 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4817 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4818 object->num_contained_sampler_states++;
4823 *ppStateBlock = (IWineD3DStateBlock*) object;
4824 This->isRecordingState = FALSE;
4825 This->updateStateBlock = This->stateBlock;
4826 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4827 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4828 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4829 return WINED3D_OK;
4832 /*****
4833 * Scene related functions
4834 *****/
4835 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4836 /* At the moment we have no need for any functionality at the beginning
4837 of a scene */
4838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4839 TRACE("(%p)\n", This);
4841 if(This->inScene) {
4842 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4843 return WINED3DERR_INVALIDCALL;
4845 This->inScene = TRUE;
4846 return WINED3D_OK;
4849 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4851 TRACE("(%p)\n", This);
4853 if(!This->inScene) {
4854 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4855 return WINED3DERR_INVALIDCALL;
4858 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4859 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4860 glFlush();
4861 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4862 * fails
4865 This->inScene = FALSE;
4866 return WINED3D_OK;
4869 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4870 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4871 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4873 IWineD3DSwapChain *swapChain = NULL;
4874 int i;
4875 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4877 TRACE("(%p) Presenting the frame\n", This);
4879 for(i = 0 ; i < swapchains ; i ++) {
4881 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4882 TRACE("presentinng chain %d, %p\n", i, swapChain);
4883 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4884 IWineD3DSwapChain_Release(swapChain);
4887 return WINED3D_OK;
4890 /* Not called from the VTable (internal subroutine) */
4891 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4892 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4893 float Z, DWORD Stencil) {
4894 GLbitfield glMask = 0;
4895 unsigned int i;
4896 WINED3DRECT curRect;
4897 RECT vp_rect;
4898 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4899 UINT drawable_width, drawable_height;
4900 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4901 IWineD3DSwapChainImpl *swapchain = NULL;
4903 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4904 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4905 * for the cleared parts, and the untouched parts.
4907 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4908 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4909 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4910 * checking all this if the dest surface is in the drawable anyway.
4912 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4913 while(1) {
4914 if(vp->X != 0 || vp->Y != 0 ||
4915 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4916 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4917 break;
4919 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4920 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4921 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4922 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4923 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4924 break;
4926 if(Count > 0 && pRects && (
4927 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4928 pRects[0].x2 < target->currentDesc.Width ||
4929 pRects[0].y2 < target->currentDesc.Height)) {
4930 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4931 break;
4933 break;
4937 target->get_drawable_size(target, &drawable_width, &drawable_height);
4939 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4940 ENTER_GL();
4942 /* Only set the values up once, as they are not changing */
4943 if (Flags & WINED3DCLEAR_STENCIL) {
4944 glClearStencil(Stencil);
4945 checkGLcall("glClearStencil");
4946 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4947 glStencilMask(0xFFFFFFFF);
4950 if (Flags & WINED3DCLEAR_ZBUFFER) {
4951 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4952 glDepthMask(GL_TRUE);
4953 glClearDepth(Z);
4954 checkGLcall("glClearDepth");
4955 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4956 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4958 if (vp->X != 0 || vp->Y != 0 ||
4959 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4960 surface_load_ds_location(This->stencilBufferTarget, location);
4962 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4963 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4964 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4965 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4966 surface_load_ds_location(This->stencilBufferTarget, location);
4968 else if (Count > 0 && pRects && (
4969 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4970 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4971 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4972 surface_load_ds_location(This->stencilBufferTarget, location);
4976 if (Flags & WINED3DCLEAR_TARGET) {
4977 TRACE("Clearing screen with glClear to color %x\n", Color);
4978 glClearColor(D3DCOLOR_R(Color),
4979 D3DCOLOR_G(Color),
4980 D3DCOLOR_B(Color),
4981 D3DCOLOR_A(Color));
4982 checkGLcall("glClearColor");
4984 /* Clear ALL colors! */
4985 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4986 glMask = glMask | GL_COLOR_BUFFER_BIT;
4989 vp_rect.left = vp->X;
4990 vp_rect.top = vp->Y;
4991 vp_rect.right = vp->X + vp->Width;
4992 vp_rect.bottom = vp->Y + vp->Height;
4993 if (!(Count > 0 && pRects)) {
4994 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4995 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4997 if(This->render_offscreen) {
4998 glScissor(vp_rect.left, vp_rect.top,
4999 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5000 } else {
5001 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5002 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5004 checkGLcall("glScissor");
5005 glClear(glMask);
5006 checkGLcall("glClear");
5007 } else {
5008 /* Now process each rect in turn */
5009 for (i = 0; i < Count; i++) {
5010 /* Note gl uses lower left, width/height */
5011 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5012 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5013 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5015 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5016 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5017 curRect.x1, (target->currentDesc.Height - curRect.y2),
5018 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5020 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5021 * The rectangle is not cleared, no error is returned, but further rectanlges are
5022 * still cleared if they are valid
5024 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5025 TRACE("Rectangle with negative dimensions, ignoring\n");
5026 continue;
5029 if(This->render_offscreen) {
5030 glScissor(curRect.x1, curRect.y1,
5031 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5032 } else {
5033 glScissor(curRect.x1, drawable_height - curRect.y2,
5034 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5036 checkGLcall("glScissor");
5038 glClear(glMask);
5039 checkGLcall("glClear");
5043 /* Restore the old values (why..?) */
5044 if (Flags & WINED3DCLEAR_STENCIL) {
5045 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5047 if (Flags & WINED3DCLEAR_TARGET) {
5048 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5049 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5050 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5051 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5052 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5054 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5055 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5057 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5059 if (Flags & WINED3DCLEAR_ZBUFFER) {
5060 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5061 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5062 surface_modify_ds_location(This->stencilBufferTarget, location);
5065 LEAVE_GL();
5067 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5068 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5069 glFlush();
5071 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5074 return WINED3D_OK;
5077 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5078 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5080 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5082 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5083 Count, pRects, Flags, Color, Z, Stencil);
5085 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5086 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5087 /* TODO: What about depth stencil buffers without stencil bits? */
5088 return WINED3DERR_INVALIDCALL;
5091 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5094 /*****
5095 * Drawing functions
5096 *****/
5097 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5098 UINT PrimitiveCount) {
5100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5102 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5103 debug_d3dprimitivetype(PrimitiveType),
5104 StartVertex, PrimitiveCount);
5106 if(!This->stateBlock->vertexDecl) {
5107 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5108 return WINED3DERR_INVALIDCALL;
5111 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5112 if(This->stateBlock->streamIsUP) {
5113 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5114 This->stateBlock->streamIsUP = FALSE;
5117 if(This->stateBlock->loadBaseVertexIndex != 0) {
5118 This->stateBlock->loadBaseVertexIndex = 0;
5119 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5121 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5122 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5123 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5124 return WINED3D_OK;
5127 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5128 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5129 WINED3DPRIMITIVETYPE PrimitiveType,
5130 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5133 UINT idxStride = 2;
5134 IWineD3DIndexBuffer *pIB;
5135 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5136 GLuint vbo;
5138 pIB = This->stateBlock->pIndexData;
5139 if (!pIB) {
5140 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5141 * without an index buffer set. (The first time at least...)
5142 * D3D8 simply dies, but I doubt it can do much harm to return
5143 * D3DERR_INVALIDCALL there as well. */
5144 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5145 return WINED3DERR_INVALIDCALL;
5148 if(!This->stateBlock->vertexDecl) {
5149 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5150 return WINED3DERR_INVALIDCALL;
5153 if(This->stateBlock->streamIsUP) {
5154 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5155 This->stateBlock->streamIsUP = FALSE;
5157 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5159 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5160 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5161 minIndex, NumVertices, startIndex, primCount);
5163 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5164 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5165 idxStride = 2;
5166 } else {
5167 idxStride = 4;
5170 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5171 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5172 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5175 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5176 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5178 return WINED3D_OK;
5181 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5182 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5183 UINT VertexStreamZeroStride) {
5184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5185 IWineD3DVertexBuffer *vb;
5187 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5188 debug_d3dprimitivetype(PrimitiveType),
5189 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5191 if(!This->stateBlock->vertexDecl) {
5192 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5193 return WINED3DERR_INVALIDCALL;
5196 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5197 vb = This->stateBlock->streamSource[0];
5198 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5199 if(vb) IWineD3DVertexBuffer_Release(vb);
5200 This->stateBlock->streamOffset[0] = 0;
5201 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5202 This->stateBlock->streamIsUP = TRUE;
5203 This->stateBlock->loadBaseVertexIndex = 0;
5205 /* TODO: Only mark dirty if drawing from a different UP address */
5206 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5208 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5209 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5211 /* MSDN specifies stream zero settings must be set to NULL */
5212 This->stateBlock->streamStride[0] = 0;
5213 This->stateBlock->streamSource[0] = NULL;
5215 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5216 * the new stream sources or use UP drawing again
5218 return WINED3D_OK;
5221 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5222 UINT MinVertexIndex, UINT NumVertices,
5223 UINT PrimitiveCount, CONST void* pIndexData,
5224 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5225 UINT VertexStreamZeroStride) {
5226 int idxStride;
5227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5228 IWineD3DVertexBuffer *vb;
5229 IWineD3DIndexBuffer *ib;
5231 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5232 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5233 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5234 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5236 if(!This->stateBlock->vertexDecl) {
5237 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5238 return WINED3DERR_INVALIDCALL;
5241 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5242 idxStride = 2;
5243 } else {
5244 idxStride = 4;
5247 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5248 vb = This->stateBlock->streamSource[0];
5249 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5250 if(vb) IWineD3DVertexBuffer_Release(vb);
5251 This->stateBlock->streamIsUP = TRUE;
5252 This->stateBlock->streamOffset[0] = 0;
5253 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5255 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5256 This->stateBlock->baseVertexIndex = 0;
5257 This->stateBlock->loadBaseVertexIndex = 0;
5258 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5259 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5260 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5262 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5264 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5265 This->stateBlock->streamSource[0] = NULL;
5266 This->stateBlock->streamStride[0] = 0;
5267 ib = This->stateBlock->pIndexData;
5268 if(ib) {
5269 IWineD3DIndexBuffer_Release(ib);
5270 This->stateBlock->pIndexData = NULL;
5272 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5273 * SetStreamSource to specify a vertex buffer
5276 return WINED3D_OK;
5279 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5280 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5281 const WineDirect3DVertexStridedData *DrawPrimStrideData)
5283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5285 /* Mark the state dirty until we have nicer tracking
5286 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5287 * that value.
5289 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5290 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5291 This->stateBlock->baseVertexIndex = 0;
5292 This->up_strided = DrawPrimStrideData;
5293 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5294 This->up_strided = NULL;
5295 return WINED3D_OK;
5298 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5299 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5300 const WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, const void *pIndexData,
5301 WINED3DFORMAT IndexDataFormat)
5303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5304 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5306 /* Mark the state dirty until we have nicer tracking
5307 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5308 * that value.
5310 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5311 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5312 This->stateBlock->streamIsUP = TRUE;
5313 This->stateBlock->baseVertexIndex = 0;
5314 This->up_strided = DrawPrimStrideData;
5315 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5316 This->up_strided = NULL;
5317 return WINED3D_OK;
5320 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5321 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5322 * not callable by the app directly no parameter validation checks are needed here.
5324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5325 WINED3DLOCKED_BOX src;
5326 WINED3DLOCKED_BOX dst;
5327 HRESULT hr;
5328 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5330 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5331 * dirtification to improve loading performance.
5333 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5334 if(FAILED(hr)) return hr;
5335 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5336 if(FAILED(hr)) {
5337 IWineD3DVolume_UnlockBox(pSourceVolume);
5338 return hr;
5341 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5343 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5344 if(FAILED(hr)) {
5345 IWineD3DVolume_UnlockBox(pSourceVolume);
5346 } else {
5347 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5349 return hr;
5352 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5353 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5355 HRESULT hr = WINED3D_OK;
5356 WINED3DRESOURCETYPE sourceType;
5357 WINED3DRESOURCETYPE destinationType;
5358 int i ,levels;
5360 /* TODO: think about moving the code into IWineD3DBaseTexture */
5362 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5364 /* verify that the source and destination textures aren't NULL */
5365 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5366 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5367 This, pSourceTexture, pDestinationTexture);
5368 hr = WINED3DERR_INVALIDCALL;
5371 if (pSourceTexture == pDestinationTexture) {
5372 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5373 This, pSourceTexture, pDestinationTexture);
5374 hr = WINED3DERR_INVALIDCALL;
5376 /* Verify that the source and destination textures are the same type */
5377 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5378 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5380 if (sourceType != destinationType) {
5381 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5382 This);
5383 hr = WINED3DERR_INVALIDCALL;
5386 /* check that both textures have the identical numbers of levels */
5387 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5388 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5389 hr = WINED3DERR_INVALIDCALL;
5392 if (WINED3D_OK == hr) {
5394 /* Make sure that the destination texture is loaded */
5395 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5397 /* Update every surface level of the texture */
5398 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5400 switch (sourceType) {
5401 case WINED3DRTYPE_TEXTURE:
5403 IWineD3DSurface *srcSurface;
5404 IWineD3DSurface *destSurface;
5406 for (i = 0 ; i < levels ; ++i) {
5407 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5408 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5409 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5410 IWineD3DSurface_Release(srcSurface);
5411 IWineD3DSurface_Release(destSurface);
5412 if (WINED3D_OK != hr) {
5413 WARN("(%p) : Call to update surface failed\n", This);
5414 return hr;
5418 break;
5419 case WINED3DRTYPE_CUBETEXTURE:
5421 IWineD3DSurface *srcSurface;
5422 IWineD3DSurface *destSurface;
5423 WINED3DCUBEMAP_FACES faceType;
5425 for (i = 0 ; i < levels ; ++i) {
5426 /* Update each cube face */
5427 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5428 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5429 if (WINED3D_OK != hr) {
5430 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5431 } else {
5432 TRACE("Got srcSurface %p\n", srcSurface);
5434 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5435 if (WINED3D_OK != hr) {
5436 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5437 } else {
5438 TRACE("Got desrSurface %p\n", destSurface);
5440 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5441 IWineD3DSurface_Release(srcSurface);
5442 IWineD3DSurface_Release(destSurface);
5443 if (WINED3D_OK != hr) {
5444 WARN("(%p) : Call to update surface failed\n", This);
5445 return hr;
5450 break;
5452 case WINED3DRTYPE_VOLUMETEXTURE:
5454 IWineD3DVolume *srcVolume = NULL;
5455 IWineD3DVolume *destVolume = NULL;
5457 for (i = 0 ; i < levels ; ++i) {
5458 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5459 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5460 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5461 IWineD3DVolume_Release(srcVolume);
5462 IWineD3DVolume_Release(destVolume);
5463 if (WINED3D_OK != hr) {
5464 WARN("(%p) : Call to update volume failed\n", This);
5465 return hr;
5469 break;
5471 default:
5472 FIXME("(%p) : Unsupported source and destination type\n", This);
5473 hr = WINED3DERR_INVALIDCALL;
5477 return hr;
5480 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5481 IWineD3DSwapChain *swapChain;
5482 HRESULT hr;
5483 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5484 if(hr == WINED3D_OK) {
5485 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5486 IWineD3DSwapChain_Release(swapChain);
5488 return hr;
5491 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5492 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5493 IWineD3DBaseTextureImpl *texture;
5494 const struct GlPixelFormatDesc *gl_info;
5495 DWORD i;
5497 TRACE("(%p) : %p\n", This, pNumPasses);
5499 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5500 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5501 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5502 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5504 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5505 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5506 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5509 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5510 if(!texture) continue;
5511 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5512 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5514 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5515 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5516 return E_FAIL;
5518 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5519 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5520 return E_FAIL;
5522 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5523 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5524 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5525 return E_FAIL;
5529 /* return a sensible default */
5530 *pNumPasses = 1;
5532 TRACE("returning D3D_OK\n");
5533 return WINED3D_OK;
5536 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5538 int i;
5540 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5541 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5542 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5543 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5548 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5550 int j;
5551 UINT NewSize;
5552 PALETTEENTRY **palettes;
5554 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5556 if (PaletteNumber >= MAX_PALETTES) {
5557 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5558 return WINED3DERR_INVALIDCALL;
5561 if (PaletteNumber >= This->NumberOfPalettes) {
5562 NewSize = This->NumberOfPalettes;
5563 do {
5564 NewSize *= 2;
5565 } while(PaletteNumber >= NewSize);
5566 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5567 if (!palettes) {
5568 ERR("Out of memory!\n");
5569 return E_OUTOFMEMORY;
5571 This->palettes = palettes;
5572 This->NumberOfPalettes = NewSize;
5575 if (!This->palettes[PaletteNumber]) {
5576 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5577 if (!This->palettes[PaletteNumber]) {
5578 ERR("Out of memory!\n");
5579 return E_OUTOFMEMORY;
5583 for (j = 0; j < 256; ++j) {
5584 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5585 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5586 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5587 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5589 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5590 TRACE("(%p) : returning\n", This);
5591 return WINED3D_OK;
5594 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5596 int j;
5597 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5598 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5599 /* What happens in such situation isn't documented; Native seems to silently abort
5600 on such conditions. Return Invalid Call. */
5601 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5602 return WINED3DERR_INVALIDCALL;
5604 for (j = 0; j < 256; ++j) {
5605 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5606 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5607 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5608 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5610 TRACE("(%p) : returning\n", This);
5611 return WINED3D_OK;
5614 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5616 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5617 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5618 (tested with reference rasterizer). Return Invalid Call. */
5619 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5620 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5621 return WINED3DERR_INVALIDCALL;
5623 /*TODO: stateblocks */
5624 if (This->currentPalette != PaletteNumber) {
5625 This->currentPalette = PaletteNumber;
5626 dirtify_p8_texture_samplers(This);
5628 TRACE("(%p) : returning\n", This);
5629 return WINED3D_OK;
5632 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5634 if (PaletteNumber == NULL) {
5635 WARN("(%p) : returning Invalid Call\n", This);
5636 return WINED3DERR_INVALIDCALL;
5638 /*TODO: stateblocks */
5639 *PaletteNumber = This->currentPalette;
5640 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5641 return WINED3D_OK;
5644 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5646 static BOOL warned;
5647 if (!warned)
5649 FIXME("(%p) : stub\n", This);
5650 warned = TRUE;
5653 This->softwareVertexProcessing = bSoftware;
5654 return WINED3D_OK;
5658 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5660 static BOOL warned;
5661 if (!warned)
5663 FIXME("(%p) : stub\n", This);
5664 warned = TRUE;
5666 return This->softwareVertexProcessing;
5670 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5672 IWineD3DSwapChain *swapChain;
5673 HRESULT hr;
5675 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5677 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5678 if(hr == WINED3D_OK){
5679 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5680 IWineD3DSwapChain_Release(swapChain);
5681 }else{
5682 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5684 return hr;
5688 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5690 static BOOL warned;
5691 if(nSegments != 0.0f) {
5692 if (!warned)
5694 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5695 warned = TRUE;
5698 return WINED3D_OK;
5701 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5703 static BOOL warned;
5704 if (!warned)
5706 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5707 warned = TRUE;
5709 return 0.0f;
5712 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5714 /** TODO: remove casts to IWineD3DSurfaceImpl
5715 * NOTE: move code to surface to accomplish this
5716 ****************************************/
5717 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5718 int srcWidth, srcHeight;
5719 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5720 WINED3DFORMAT destFormat, srcFormat;
5721 UINT destSize;
5722 int srcLeft, destLeft, destTop;
5723 WINED3DPOOL srcPool, destPool;
5724 int offset = 0;
5725 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5726 glDescriptor *glDescription = NULL;
5727 GLenum dummy;
5728 int sampler;
5729 int bpp;
5730 CONVERT_TYPES convert = NO_CONVERSION;
5732 WINED3DSURFACE_DESC winedesc;
5734 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5735 memset(&winedesc, 0, sizeof(winedesc));
5736 winedesc.Width = &srcSurfaceWidth;
5737 winedesc.Height = &srcSurfaceHeight;
5738 winedesc.Pool = &srcPool;
5739 winedesc.Format = &srcFormat;
5741 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5743 winedesc.Width = &destSurfaceWidth;
5744 winedesc.Height = &destSurfaceHeight;
5745 winedesc.Pool = &destPool;
5746 winedesc.Format = &destFormat;
5747 winedesc.Size = &destSize;
5749 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5751 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5752 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5753 return WINED3DERR_INVALIDCALL;
5756 /* This call loads the opengl surface directly, instead of copying the surface to the
5757 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5758 * copy in sysmem and use regular surface loading.
5760 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5761 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5762 if(convert != NO_CONVERSION) {
5763 return IWineD3DSurface_BltFast(pDestinationSurface,
5764 pDestPoint ? pDestPoint->x : 0,
5765 pDestPoint ? pDestPoint->y : 0,
5766 pSourceSurface, pSourceRect, 0);
5769 if (destFormat == WINED3DFMT_UNKNOWN) {
5770 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5771 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5773 /* Get the update surface description */
5774 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5777 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5779 ENTER_GL();
5780 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5781 checkGLcall("glActiveTextureARB");
5782 LEAVE_GL();
5784 /* Make sure the surface is loaded and up to date */
5785 IWineD3DSurface_PreLoad(pDestinationSurface);
5786 IWineD3DSurface_BindTexture(pDestinationSurface);
5788 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5790 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5791 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5792 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5793 srcLeft = pSourceRect ? pSourceRect->left : 0;
5794 destLeft = pDestPoint ? pDestPoint->x : 0;
5795 destTop = pDestPoint ? pDestPoint->y : 0;
5798 /* This function doesn't support compressed textures
5799 the pitch is just bytesPerPixel * width */
5800 if(srcWidth != srcSurfaceWidth || srcLeft ){
5801 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5802 offset += srcLeft * pSrcSurface->bytesPerPixel;
5803 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5805 /* TODO DXT formats */
5807 if(pSourceRect != NULL && pSourceRect->top != 0){
5808 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5810 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5811 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat,
5812 glDescription->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5814 /* Sanity check */
5815 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5817 /* need to lock the surface to get the data */
5818 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5821 ENTER_GL();
5823 /* TODO: Cube and volume support */
5824 if(rowoffset != 0){
5825 /* not a whole row so we have to do it a line at a time */
5826 int j;
5828 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5829 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5831 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5833 glTexSubImage2D(glDescription->target
5834 ,glDescription->level
5835 ,destLeft
5837 ,srcWidth
5839 ,glDescription->glFormat
5840 ,glDescription->glType
5841 ,data /* could be quicker using */
5843 data += rowoffset;
5846 } else { /* Full width, so just write out the whole texture */
5847 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5849 if (WINED3DFMT_DXT1 == destFormat ||
5850 WINED3DFMT_DXT2 == destFormat ||
5851 WINED3DFMT_DXT3 == destFormat ||
5852 WINED3DFMT_DXT4 == destFormat ||
5853 WINED3DFMT_DXT5 == destFormat) {
5854 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5855 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5856 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5857 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5858 } if (destFormat != srcFormat) {
5859 FIXME("Updating mixed format compressed texture is not curretly support\n");
5860 } else {
5861 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
5862 glDescription->glFormatInternal, srcWidth, srcHeight, 0, destSize, data));
5864 } else {
5865 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5869 } else {
5870 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
5871 srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, data);
5874 checkGLcall("glTexSubImage2D");
5876 LEAVE_GL();
5878 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5879 sampler = This->rev_tex_unit_map[0];
5880 if (sampler != -1) {
5881 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5884 return WINED3D_OK;
5887 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5889 struct WineD3DRectPatch *patch;
5890 unsigned int i;
5891 struct list *e;
5892 BOOL found;
5893 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5895 if(!(Handle || pRectPatchInfo)) {
5896 /* TODO: Write a test for the return value, thus the FIXME */
5897 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5898 return WINED3DERR_INVALIDCALL;
5901 if(Handle) {
5902 i = PATCHMAP_HASHFUNC(Handle);
5903 found = FALSE;
5904 LIST_FOR_EACH(e, &This->patches[i]) {
5905 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5906 if(patch->Handle == Handle) {
5907 found = TRUE;
5908 break;
5912 if(!found) {
5913 TRACE("Patch does not exist. Creating a new one\n");
5914 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5915 patch->Handle = Handle;
5916 list_add_head(&This->patches[i], &patch->entry);
5917 } else {
5918 TRACE("Found existing patch %p\n", patch);
5920 } else {
5921 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5922 * attributes we have to tesselate, read back, and draw. This needs a patch
5923 * management structure instance. Create one.
5925 * A possible improvement is to check if a vertex shader is used, and if not directly
5926 * draw the patch.
5928 FIXME("Drawing an uncached patch. This is slow\n");
5929 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5932 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5933 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5934 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5935 HRESULT hr;
5936 TRACE("Tesselation density or patch info changed, retesselating\n");
5938 if(pRectPatchInfo) {
5939 patch->RectPatchInfo = *pRectPatchInfo;
5941 patch->numSegs[0] = pNumSegs[0];
5942 patch->numSegs[1] = pNumSegs[1];
5943 patch->numSegs[2] = pNumSegs[2];
5944 patch->numSegs[3] = pNumSegs[3];
5946 hr = tesselate_rectpatch(This, patch);
5947 if(FAILED(hr)) {
5948 WARN("Patch tesselation failed\n");
5950 /* Do not release the handle to store the params of the patch */
5951 if(!Handle) {
5952 HeapFree(GetProcessHeap(), 0, patch);
5954 return hr;
5958 This->currentPatch = patch;
5959 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5960 This->currentPatch = NULL;
5962 /* Destroy uncached patches */
5963 if(!Handle) {
5964 HeapFree(GetProcessHeap(), 0, patch->mem);
5965 HeapFree(GetProcessHeap(), 0, patch);
5967 return WINED3D_OK;
5970 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5972 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5973 FIXME("(%p) : Stub\n", This);
5974 return WINED3D_OK;
5977 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5979 int i;
5980 struct WineD3DRectPatch *patch;
5981 struct list *e;
5982 TRACE("(%p) Handle(%d)\n", This, Handle);
5984 i = PATCHMAP_HASHFUNC(Handle);
5985 LIST_FOR_EACH(e, &This->patches[i]) {
5986 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5987 if(patch->Handle == Handle) {
5988 TRACE("Deleting patch %p\n", patch);
5989 list_remove(&patch->entry);
5990 HeapFree(GetProcessHeap(), 0, patch->mem);
5991 HeapFree(GetProcessHeap(), 0, patch);
5992 return WINED3D_OK;
5996 /* TODO: Write a test for the return value */
5997 FIXME("Attempt to destroy nonexistent patch\n");
5998 return WINED3DERR_INVALIDCALL;
6001 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6002 HRESULT hr;
6003 IWineD3DSwapChain *swapchain;
6005 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6006 if (SUCCEEDED(hr)) {
6007 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6008 return swapchain;
6011 return NULL;
6014 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6016 IWineD3DSwapChain *swapchain;
6018 swapchain = get_swapchain(surface);
6019 if (swapchain) {
6020 GLenum buffer;
6022 TRACE("Surface %p is onscreen\n", surface);
6024 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6025 ENTER_GL();
6026 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6027 buffer = surface_get_gl_buffer(surface, swapchain);
6028 glDrawBuffer(buffer);
6029 checkGLcall("glDrawBuffer()");
6030 } else {
6031 TRACE("Surface %p is offscreen\n", surface);
6033 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6034 ENTER_GL();
6035 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6036 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6037 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6038 checkGLcall("glFramebufferRenderbufferEXT");
6041 if (rect) {
6042 glEnable(GL_SCISSOR_TEST);
6043 if(!swapchain) {
6044 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6045 } else {
6046 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6047 rect->x2 - rect->x1, rect->y2 - rect->y1);
6049 checkGLcall("glScissor");
6050 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6051 } else {
6052 glDisable(GL_SCISSOR_TEST);
6054 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6056 glDisable(GL_BLEND);
6057 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6059 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6060 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6062 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6063 glClear(GL_COLOR_BUFFER_BIT);
6064 checkGLcall("glClear");
6066 if (This->activeContext->current_fbo) {
6067 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6068 } else {
6069 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6070 checkGLcall("glBindFramebuffer()");
6073 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6074 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6075 glDrawBuffer(GL_BACK);
6076 checkGLcall("glDrawBuffer()");
6079 LEAVE_GL();
6082 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6083 unsigned int r, g, b, a;
6084 DWORD ret;
6086 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6087 destfmt == WINED3DFMT_R8G8B8)
6088 return color;
6090 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6092 a = (color & 0xff000000) >> 24;
6093 r = (color & 0x00ff0000) >> 16;
6094 g = (color & 0x0000ff00) >> 8;
6095 b = (color & 0x000000ff) >> 0;
6097 switch(destfmt)
6099 case WINED3DFMT_R5G6B5:
6100 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6101 r = (r * 32) / 256;
6102 g = (g * 64) / 256;
6103 b = (b * 32) / 256;
6104 ret = r << 11;
6105 ret |= g << 5;
6106 ret |= b;
6107 TRACE("Returning %08x\n", ret);
6108 return ret;
6110 case WINED3DFMT_X1R5G5B5:
6111 case WINED3DFMT_A1R5G5B5:
6112 a = (a * 2) / 256;
6113 r = (r * 32) / 256;
6114 g = (g * 32) / 256;
6115 b = (b * 32) / 256;
6116 ret = a << 15;
6117 ret |= r << 10;
6118 ret |= g << 5;
6119 ret |= b << 0;
6120 TRACE("Returning %08x\n", ret);
6121 return ret;
6123 case WINED3DFMT_A8:
6124 TRACE("Returning %08x\n", a);
6125 return a;
6127 case WINED3DFMT_X4R4G4B4:
6128 case WINED3DFMT_A4R4G4B4:
6129 a = (a * 16) / 256;
6130 r = (r * 16) / 256;
6131 g = (g * 16) / 256;
6132 b = (b * 16) / 256;
6133 ret = a << 12;
6134 ret |= r << 8;
6135 ret |= g << 4;
6136 ret |= b << 0;
6137 TRACE("Returning %08x\n", ret);
6138 return ret;
6140 case WINED3DFMT_R3G3B2:
6141 r = (r * 8) / 256;
6142 g = (g * 8) / 256;
6143 b = (b * 4) / 256;
6144 ret = r << 5;
6145 ret |= g << 2;
6146 ret |= b << 0;
6147 TRACE("Returning %08x\n", ret);
6148 return ret;
6150 case WINED3DFMT_X8B8G8R8:
6151 case WINED3DFMT_A8B8G8R8:
6152 ret = a << 24;
6153 ret |= b << 16;
6154 ret |= g << 8;
6155 ret |= r << 0;
6156 TRACE("Returning %08x\n", ret);
6157 return ret;
6159 case WINED3DFMT_A2R10G10B10:
6160 a = (a * 4) / 256;
6161 r = (r * 1024) / 256;
6162 g = (g * 1024) / 256;
6163 b = (b * 1024) / 256;
6164 ret = a << 30;
6165 ret |= r << 20;
6166 ret |= g << 10;
6167 ret |= b << 0;
6168 TRACE("Returning %08x\n", ret);
6169 return ret;
6171 case WINED3DFMT_A2B10G10R10:
6172 a = (a * 4) / 256;
6173 r = (r * 1024) / 256;
6174 g = (g * 1024) / 256;
6175 b = (b * 1024) / 256;
6176 ret = a << 30;
6177 ret |= b << 20;
6178 ret |= g << 10;
6179 ret |= r << 0;
6180 TRACE("Returning %08x\n", ret);
6181 return ret;
6183 default:
6184 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6185 return 0;
6189 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6191 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6192 WINEDDBLTFX BltFx;
6193 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6195 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6196 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6197 return WINED3DERR_INVALIDCALL;
6200 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6201 color_fill_fbo(iface, pSurface, pRect, color);
6202 return WINED3D_OK;
6203 } else {
6204 /* Just forward this to the DirectDraw blitting engine */
6205 memset(&BltFx, 0, sizeof(BltFx));
6206 BltFx.dwSize = sizeof(BltFx);
6207 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6208 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6209 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6213 /* rendertarget and depth stencil functions */
6214 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6217 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6218 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6219 return WINED3DERR_INVALIDCALL;
6222 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6223 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6224 /* Note inc ref on returned surface */
6225 if(*ppRenderTarget != NULL)
6226 IWineD3DSurface_AddRef(*ppRenderTarget);
6227 return WINED3D_OK;
6230 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6232 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6233 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6234 IWineD3DSwapChainImpl *Swapchain;
6235 HRESULT hr;
6237 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6239 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6240 if(hr != WINED3D_OK) {
6241 ERR("Can't get the swapchain\n");
6242 return hr;
6245 /* Make sure to release the swapchain */
6246 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6248 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6249 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6250 return WINED3DERR_INVALIDCALL;
6252 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6253 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6254 return WINED3DERR_INVALIDCALL;
6257 if(Swapchain->frontBuffer != Front) {
6258 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6260 if(Swapchain->frontBuffer)
6261 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6262 Swapchain->frontBuffer = Front;
6264 if(Swapchain->frontBuffer) {
6265 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6269 if(Back && !Swapchain->backBuffer) {
6270 /* We need memory for the back buffer array - only one back buffer this way */
6271 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6272 if(!Swapchain->backBuffer) {
6273 ERR("Out of memory\n");
6274 return E_OUTOFMEMORY;
6278 if(Swapchain->backBuffer[0] != Back) {
6279 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6281 /* What to do about the context here in the case of multithreading? Not sure.
6282 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6284 ENTER_GL();
6285 if(!Swapchain->backBuffer[0]) {
6286 /* GL was told to draw to the front buffer at creation,
6287 * undo that
6289 glDrawBuffer(GL_BACK);
6290 checkGLcall("glDrawBuffer(GL_BACK)");
6291 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6292 Swapchain->presentParms.BackBufferCount = 1;
6293 } else if (!Back) {
6294 /* That makes problems - disable for now */
6295 /* glDrawBuffer(GL_FRONT); */
6296 checkGLcall("glDrawBuffer(GL_FRONT)");
6297 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6298 Swapchain->presentParms.BackBufferCount = 0;
6300 LEAVE_GL();
6302 if(Swapchain->backBuffer[0])
6303 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6304 Swapchain->backBuffer[0] = Back;
6306 if(Swapchain->backBuffer[0]) {
6307 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6308 } else {
6309 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6310 Swapchain->backBuffer = NULL;
6315 return WINED3D_OK;
6318 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6320 *ppZStencilSurface = This->stencilBufferTarget;
6321 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6323 if(*ppZStencilSurface != NULL) {
6324 /* Note inc ref on returned surface */
6325 IWineD3DSurface_AddRef(*ppZStencilSurface);
6326 return WINED3D_OK;
6327 } else {
6328 return WINED3DERR_NOTFOUND;
6332 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6333 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6336 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6337 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6338 GLenum gl_filter;
6339 POINT offset = {0, 0};
6341 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6342 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6343 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6344 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6346 switch (filter) {
6347 case WINED3DTEXF_LINEAR:
6348 gl_filter = GL_LINEAR;
6349 break;
6351 default:
6352 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6353 case WINED3DTEXF_NONE:
6354 case WINED3DTEXF_POINT:
6355 gl_filter = GL_NEAREST;
6356 break;
6359 /* Attach src surface to src fbo */
6360 src_swapchain = get_swapchain(src_surface);
6361 if (src_swapchain) {
6362 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6364 TRACE("Source surface %p is onscreen\n", src_surface);
6365 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6366 /* Make sure the drawable is up to date. In the offscreen case
6367 * attach_surface_fbo() implicitly takes care of this. */
6368 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6370 if(buffer == GL_FRONT) {
6371 RECT windowsize;
6372 UINT h;
6373 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6374 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6375 h = windowsize.bottom - windowsize.top;
6376 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6377 src_rect->y1 = offset.y + h - src_rect->y1;
6378 src_rect->y2 = offset.y + h - src_rect->y2;
6379 } else {
6380 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6381 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6384 ENTER_GL();
6385 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6386 glReadBuffer(buffer);
6387 checkGLcall("glReadBuffer()");
6388 } else {
6389 TRACE("Source surface %p is offscreen\n", src_surface);
6390 ENTER_GL();
6391 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6392 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6393 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6394 checkGLcall("glReadBuffer()");
6395 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6396 checkGLcall("glFramebufferRenderbufferEXT");
6398 LEAVE_GL();
6400 /* Attach dst surface to dst fbo */
6401 dst_swapchain = get_swapchain(dst_surface);
6402 if (dst_swapchain) {
6403 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6405 TRACE("Destination surface %p is onscreen\n", dst_surface);
6406 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6407 /* Make sure the drawable is up to date. In the offscreen case
6408 * attach_surface_fbo() implicitly takes care of this. */
6409 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6411 if(buffer == GL_FRONT) {
6412 RECT windowsize;
6413 UINT h;
6414 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6415 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6416 h = windowsize.bottom - windowsize.top;
6417 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6418 dst_rect->y1 = offset.y + h - dst_rect->y1;
6419 dst_rect->y2 = offset.y + h - dst_rect->y2;
6420 } else {
6421 /* Screen coords = window coords, surface height = window height */
6422 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6423 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6426 ENTER_GL();
6427 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6428 glDrawBuffer(buffer);
6429 checkGLcall("glDrawBuffer()");
6430 } else {
6431 TRACE("Destination surface %p is offscreen\n", dst_surface);
6433 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6434 if(!src_swapchain) {
6435 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6438 ENTER_GL();
6439 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6440 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6441 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6442 checkGLcall("glDrawBuffer()");
6443 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6444 checkGLcall("glFramebufferRenderbufferEXT");
6446 glDisable(GL_SCISSOR_TEST);
6447 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6449 if (flip) {
6450 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6451 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6452 checkGLcall("glBlitFramebuffer()");
6453 } else {
6454 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6455 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6456 checkGLcall("glBlitFramebuffer()");
6459 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6461 if (This->activeContext->current_fbo) {
6462 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6463 } else {
6464 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6465 checkGLcall("glBindFramebuffer()");
6468 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6469 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6470 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6471 glDrawBuffer(GL_BACK);
6472 checkGLcall("glDrawBuffer()");
6474 LEAVE_GL();
6477 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6479 WINED3DVIEWPORT viewport;
6481 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6483 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6484 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6485 This, RenderTargetIndex, GL_LIMITS(buffers));
6486 return WINED3DERR_INVALIDCALL;
6489 /* MSDN says that null disables the render target
6490 but a device must always be associated with a render target
6491 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6493 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6494 FIXME("Trying to set render target 0 to NULL\n");
6495 return WINED3DERR_INVALIDCALL;
6497 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6498 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);
6499 return WINED3DERR_INVALIDCALL;
6502 /* If we are trying to set what we already have, don't bother */
6503 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6504 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6505 return WINED3D_OK;
6507 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6508 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6509 This->render_targets[RenderTargetIndex] = pRenderTarget;
6511 /* Render target 0 is special */
6512 if(RenderTargetIndex == 0) {
6513 /* Finally, reset the viewport as the MSDN states. */
6514 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6515 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6516 viewport.X = 0;
6517 viewport.Y = 0;
6518 viewport.MaxZ = 1.0f;
6519 viewport.MinZ = 0.0f;
6520 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6521 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6522 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6524 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6526 return WINED3D_OK;
6529 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6531 HRESULT hr = WINED3D_OK;
6532 IWineD3DSurface *tmp;
6534 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6536 if (pNewZStencil == This->stencilBufferTarget) {
6537 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6538 } else {
6539 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6540 * depending on the renter target implementation being used.
6541 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6542 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6543 * stencil buffer and incur an extra memory overhead
6544 ******************************************************/
6546 if (This->stencilBufferTarget) {
6547 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6548 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6549 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6550 } else {
6551 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6552 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6553 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6557 tmp = This->stencilBufferTarget;
6558 This->stencilBufferTarget = pNewZStencil;
6559 /* should we be calling the parent or the wined3d surface? */
6560 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6561 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6562 hr = WINED3D_OK;
6564 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6565 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6566 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6567 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6568 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6572 return hr;
6575 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6576 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6578 /* TODO: the use of Impl is deprecated. */
6579 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6580 WINED3DLOCKED_RECT lockedRect;
6582 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6584 /* some basic validation checks */
6585 if(This->cursorTexture) {
6586 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6587 ENTER_GL();
6588 glDeleteTextures(1, &This->cursorTexture);
6589 LEAVE_GL();
6590 This->cursorTexture = 0;
6593 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6594 This->haveHardwareCursor = TRUE;
6595 else
6596 This->haveHardwareCursor = FALSE;
6598 if(pCursorBitmap) {
6599 WINED3DLOCKED_RECT rect;
6601 /* MSDN: Cursor must be A8R8G8B8 */
6602 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6603 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6604 return WINED3DERR_INVALIDCALL;
6607 /* MSDN: Cursor must be smaller than the display mode */
6608 if(pSur->currentDesc.Width > This->ddraw_width ||
6609 pSur->currentDesc.Height > This->ddraw_height) {
6610 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);
6611 return WINED3DERR_INVALIDCALL;
6614 if (!This->haveHardwareCursor) {
6615 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6617 /* Do not store the surface's pointer because the application may
6618 * release it after setting the cursor image. Windows doesn't
6619 * addref the set surface, so we can't do this either without
6620 * creating circular refcount dependencies. Copy out the gl texture
6621 * instead.
6623 This->cursorWidth = pSur->currentDesc.Width;
6624 This->cursorHeight = pSur->currentDesc.Height;
6625 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6627 const struct GlPixelFormatDesc *glDesc;
6628 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6629 char *mem, *bits = (char *)rect.pBits;
6630 GLint intfmt = glDesc->glInternal;
6631 GLint format = glDesc->glFormat;
6632 GLint type = glDesc->glType;
6633 INT height = This->cursorHeight;
6634 INT width = This->cursorWidth;
6635 INT bpp = tableEntry->bpp;
6636 INT i, sampler;
6638 /* Reformat the texture memory (pitch and width can be
6639 * different) */
6640 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6641 for(i = 0; i < height; i++)
6642 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6643 IWineD3DSurface_UnlockRect(pCursorBitmap);
6644 ENTER_GL();
6646 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6647 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6648 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6651 /* Make sure that a proper texture unit is selected */
6652 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6653 checkGLcall("glActiveTextureARB");
6654 sampler = This->rev_tex_unit_map[0];
6655 if (sampler != -1) {
6656 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6658 /* Create a new cursor texture */
6659 glGenTextures(1, &This->cursorTexture);
6660 checkGLcall("glGenTextures");
6661 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6662 checkGLcall("glBindTexture");
6663 /* Copy the bitmap memory into the cursor texture */
6664 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6665 HeapFree(GetProcessHeap(), 0, mem);
6666 checkGLcall("glTexImage2D");
6668 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6669 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6670 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6673 LEAVE_GL();
6675 else
6677 FIXME("A cursor texture was not returned.\n");
6678 This->cursorTexture = 0;
6681 else
6683 /* Draw a hardware cursor */
6684 ICONINFO cursorInfo;
6685 HCURSOR cursor;
6686 /* Create and clear maskBits because it is not needed for
6687 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6688 * chunks. */
6689 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6690 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6691 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6692 WINED3DLOCK_NO_DIRTY_UPDATE |
6693 WINED3DLOCK_READONLY
6695 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6696 pSur->currentDesc.Height);
6698 cursorInfo.fIcon = FALSE;
6699 cursorInfo.xHotspot = XHotSpot;
6700 cursorInfo.yHotspot = YHotSpot;
6701 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6702 pSur->currentDesc.Height, 1,
6703 1, &maskBits);
6704 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6705 pSur->currentDesc.Height, 1,
6706 32, lockedRect.pBits);
6707 IWineD3DSurface_UnlockRect(pCursorBitmap);
6708 /* Create our cursor and clean up. */
6709 cursor = CreateIconIndirect(&cursorInfo);
6710 SetCursor(cursor);
6711 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6712 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6713 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6714 This->hardwareCursor = cursor;
6715 HeapFree(GetProcessHeap(), 0, maskBits);
6719 This->xHotSpot = XHotSpot;
6720 This->yHotSpot = YHotSpot;
6721 return WINED3D_OK;
6724 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6726 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6728 This->xScreenSpace = XScreenSpace;
6729 This->yScreenSpace = YScreenSpace;
6731 return;
6735 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6737 BOOL oldVisible = This->bCursorVisible;
6738 POINT pt;
6740 TRACE("(%p) : visible(%d)\n", This, bShow);
6743 * When ShowCursor is first called it should make the cursor appear at the OS's last
6744 * known cursor position. Because of this, some applications just repetitively call
6745 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6747 GetCursorPos(&pt);
6748 This->xScreenSpace = pt.x;
6749 This->yScreenSpace = pt.y;
6751 if (This->haveHardwareCursor) {
6752 This->bCursorVisible = bShow;
6753 if (bShow)
6754 SetCursor(This->hardwareCursor);
6755 else
6756 SetCursor(NULL);
6758 else
6760 if (This->cursorTexture)
6761 This->bCursorVisible = bShow;
6764 return oldVisible;
6767 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6768 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6769 IWineD3DResourceImpl *resource;
6770 TRACE("(%p) : state (%u)\n", This, This->state);
6772 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6773 switch (This->state) {
6774 case WINED3D_OK:
6775 return WINED3D_OK;
6776 case WINED3DERR_DEVICELOST:
6778 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6779 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6780 return WINED3DERR_DEVICENOTRESET;
6782 return WINED3DERR_DEVICELOST;
6784 case WINED3DERR_DRIVERINTERNALERROR:
6785 return WINED3DERR_DRIVERINTERNALERROR;
6788 /* Unknown state */
6789 return WINED3DERR_DRIVERINTERNALERROR;
6793 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6795 /** FIXME: Resource tracking needs to be done,
6796 * The closes we can do to this is set the priorities of all managed textures low
6797 * and then reset them.
6798 ***********************************************************/
6799 FIXME("(%p) : stub\n", This);
6800 return WINED3D_OK;
6803 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6805 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6807 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6808 if(surface->Flags & SFLAG_DIBSECTION) {
6809 /* Release the DC */
6810 SelectObject(surface->hDC, surface->dib.holdbitmap);
6811 DeleteDC(surface->hDC);
6812 /* Release the DIB section */
6813 DeleteObject(surface->dib.DIBsection);
6814 surface->dib.bitmap_data = NULL;
6815 surface->resource.allocatedMemory = NULL;
6816 surface->Flags &= ~SFLAG_DIBSECTION;
6818 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6819 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6820 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6821 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6822 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6823 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6824 } else {
6825 surface->pow2Width = surface->pow2Height = 1;
6826 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6827 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6829 surface->glRect.left = 0;
6830 surface->glRect.top = 0;
6831 surface->glRect.right = surface->pow2Width;
6832 surface->glRect.bottom = surface->pow2Height;
6834 if(surface->glDescription.textureName) {
6835 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6836 ENTER_GL();
6837 glDeleteTextures(1, &surface->glDescription.textureName);
6838 LEAVE_GL();
6839 surface->glDescription.textureName = 0;
6840 surface->Flags &= ~SFLAG_CLIENT;
6842 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6843 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6844 surface->Flags |= SFLAG_NONPOW2;
6845 } else {
6846 surface->Flags &= ~SFLAG_NONPOW2;
6848 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6849 surface->resource.allocatedMemory = NULL;
6850 surface->resource.heapMemory = NULL;
6851 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6852 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6853 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6854 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6855 } else {
6856 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6860 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6861 TRACE("Unloading resource %p\n", resource);
6862 IWineD3DResource_UnLoad(resource);
6863 IWineD3DResource_Release(resource);
6864 return S_OK;
6867 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6869 UINT i, count;
6870 WINED3DDISPLAYMODE m;
6871 HRESULT hr;
6873 /* All Windowed modes are supported, as is leaving the current mode */
6874 if(pp->Windowed) return TRUE;
6875 if(!pp->BackBufferWidth) return TRUE;
6876 if(!pp->BackBufferHeight) return TRUE;
6878 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6879 for(i = 0; i < count; i++) {
6880 memset(&m, 0, sizeof(m));
6881 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6882 if(FAILED(hr)) {
6883 ERR("EnumAdapterModes failed\n");
6885 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6886 /* Mode found, it is supported */
6887 return TRUE;
6890 /* Mode not found -> not supported */
6891 return FALSE;
6894 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6896 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6897 UINT i;
6898 IWineD3DBaseShaderImpl *shader;
6900 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6901 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6902 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6905 ENTER_GL();
6906 if(This->depth_blt_texture) {
6907 glDeleteTextures(1, &This->depth_blt_texture);
6908 This->depth_blt_texture = 0;
6910 if (This->depth_blt_rb) {
6911 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
6912 This->depth_blt_rb = 0;
6913 This->depth_blt_rb_w = 0;
6914 This->depth_blt_rb_h = 0;
6916 LEAVE_GL();
6918 This->blitter->free_private(iface);
6919 This->frag_pipe->free_private(iface);
6920 This->shader_backend->shader_free_private(iface);
6922 ENTER_GL();
6923 for (i = 0; i < GL_LIMITS(textures); i++) {
6924 /* Textures are recreated below */
6925 glDeleteTextures(1, &This->dummyTextureName[i]);
6926 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6927 This->dummyTextureName[i] = 0;
6929 LEAVE_GL();
6931 while(This->numContexts) {
6932 DestroyContext(This, This->contexts[0]);
6934 This->activeContext = NULL;
6935 HeapFree(GetProcessHeap(), 0, swapchain->context);
6936 swapchain->context = NULL;
6937 swapchain->num_contexts = 0;
6940 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6942 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6943 HRESULT hr;
6944 IWineD3DSurfaceImpl *target;
6946 /* Recreate the primary swapchain's context */
6947 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6948 if(swapchain->backBuffer) {
6949 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6950 } else {
6951 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6953 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
6954 &swapchain->presentParms);
6955 swapchain->num_contexts = 1;
6956 This->activeContext = swapchain->context[0];
6958 create_dummy_textures(This);
6960 hr = This->shader_backend->shader_alloc_private(iface);
6961 if(FAILED(hr)) {
6962 ERR("Failed to recreate shader private data\n");
6963 goto err_out;
6965 hr = This->frag_pipe->alloc_private(iface);
6966 if(FAILED(hr)) {
6967 TRACE("Fragment pipeline private data couldn't be allocated\n");
6968 goto err_out;
6970 hr = This->blitter->alloc_private(iface);
6971 if(FAILED(hr)) {
6972 TRACE("Blitter private data couldn't be allocated\n");
6973 goto err_out;
6976 return WINED3D_OK;
6978 err_out:
6979 This->blitter->free_private(iface);
6980 This->frag_pipe->free_private(iface);
6981 This->shader_backend->shader_free_private(iface);
6982 return hr;
6985 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6987 IWineD3DSwapChainImpl *swapchain;
6988 HRESULT hr;
6989 BOOL DisplayModeChanged = FALSE;
6990 WINED3DDISPLAYMODE mode;
6991 TRACE("(%p)\n", This);
6993 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6994 if(FAILED(hr)) {
6995 ERR("Failed to get the first implicit swapchain\n");
6996 return hr;
6999 if(!is_display_mode_supported(This, pPresentationParameters)) {
7000 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7001 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7002 pPresentationParameters->BackBufferHeight);
7003 return WINED3DERR_INVALIDCALL;
7006 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7007 * on an existing gl context, so there's no real need for recreation.
7009 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7011 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7013 TRACE("New params:\n");
7014 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7015 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7016 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7017 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7018 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7019 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7020 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7021 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7022 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7023 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7024 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7025 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7026 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7028 /* No special treatment of these parameters. Just store them */
7029 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7030 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7031 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7032 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7034 /* What to do about these? */
7035 if(pPresentationParameters->BackBufferCount != 0 &&
7036 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7037 ERR("Cannot change the back buffer count yet\n");
7039 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7040 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7041 ERR("Cannot change the back buffer format yet\n");
7043 if(pPresentationParameters->hDeviceWindow != NULL &&
7044 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7045 ERR("Cannot change the device window yet\n");
7047 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7048 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7049 return WINED3DERR_INVALIDCALL;
7052 /* Reset the depth stencil */
7053 if (pPresentationParameters->EnableAutoDepthStencil)
7054 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7055 else
7056 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7058 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7060 if(pPresentationParameters->Windowed) {
7061 mode.Width = swapchain->orig_width;
7062 mode.Height = swapchain->orig_height;
7063 mode.RefreshRate = 0;
7064 mode.Format = swapchain->presentParms.BackBufferFormat;
7065 } else {
7066 mode.Width = pPresentationParameters->BackBufferWidth;
7067 mode.Height = pPresentationParameters->BackBufferHeight;
7068 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7069 mode.Format = swapchain->presentParms.BackBufferFormat;
7072 /* Should Width == 800 && Height == 0 set 800x600? */
7073 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7074 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7075 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7077 UINT i;
7079 if(!pPresentationParameters->Windowed) {
7080 DisplayModeChanged = TRUE;
7082 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7083 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7085 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7086 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7087 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7089 if(This->auto_depth_stencil_buffer) {
7090 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7094 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7095 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7096 DisplayModeChanged) {
7098 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7100 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7101 if(swapchain->presentParms.Windowed) {
7102 /* switch from windowed to fs */
7103 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7104 pPresentationParameters->BackBufferWidth,
7105 pPresentationParameters->BackBufferHeight);
7106 } else {
7107 /* Fullscreen -> fullscreen mode change */
7108 MoveWindow(swapchain->win_handle, 0, 0,
7109 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7110 TRUE);
7112 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7113 /* Fullscreen -> windowed switch */
7114 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7116 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7117 } else if(!pPresentationParameters->Windowed) {
7118 DWORD style = This->style, exStyle = This->exStyle;
7119 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7120 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7121 * Reset to clear up their mess. Guild Wars also loses the device during that.
7123 This->style = 0;
7124 This->exStyle = 0;
7125 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7126 pPresentationParameters->BackBufferWidth,
7127 pPresentationParameters->BackBufferHeight);
7128 This->style = style;
7129 This->exStyle = exStyle;
7132 TRACE("Resetting stateblock\n");
7133 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7134 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7136 /* Note: No parent needed for initial internal stateblock */
7137 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7138 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7139 else TRACE("Created stateblock %p\n", This->stateBlock);
7140 This->updateStateBlock = This->stateBlock;
7141 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7143 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7144 if(FAILED(hr)) {
7145 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7148 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7149 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7151 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7152 * first use
7154 return hr;
7157 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7159 /** FIXME: always true at the moment **/
7160 if(!bEnableDialogs) {
7161 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7163 return WINED3D_OK;
7167 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7169 TRACE("(%p) : pParameters %p\n", This, pParameters);
7171 *pParameters = This->createParms;
7172 return WINED3D_OK;
7175 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7176 IWineD3DSwapChain *swapchain;
7178 TRACE("Relaying to swapchain\n");
7180 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7181 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7182 IWineD3DSwapChain_Release(swapchain);
7184 return;
7187 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7188 IWineD3DSwapChain *swapchain;
7190 TRACE("Relaying to swapchain\n");
7192 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7193 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7194 IWineD3DSwapChain_Release(swapchain);
7196 return;
7200 /** ********************************************************
7201 * Notification functions
7202 ** ********************************************************/
7203 /** This function must be called in the release of a resource when ref == 0,
7204 * the contents of resource must still be correct,
7205 * any handles to other resource held by the caller must be closed
7206 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7207 *****************************************************/
7208 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7211 TRACE("(%p) : Adding Resource %p\n", This, resource);
7212 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7215 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7218 TRACE("(%p) : Removing resource %p\n", This, resource);
7220 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7224 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7226 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7227 int counter;
7229 TRACE("(%p) : resource %p\n", This, resource);
7231 context_resource_released(iface, resource, type);
7233 switch (type) {
7234 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7235 case WINED3DRTYPE_SURFACE: {
7236 unsigned int i;
7238 /* Cleanup any FBO attachments if d3d is enabled */
7239 if(This->d3d_initialized) {
7240 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7241 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7243 TRACE("Last active render target destroyed\n");
7244 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7245 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7246 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7247 * and the lastActiveRenderTarget member shouldn't matter
7249 if(swapchain) {
7250 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7251 TRACE("Activating primary back buffer\n");
7252 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7253 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7254 /* Single buffering environment */
7255 TRACE("Activating primary front buffer\n");
7256 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7257 } else {
7258 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7259 /* Implicit render target destroyed, that means the device is being destroyed
7260 * whatever we set here, it shouldn't matter
7262 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7264 } else {
7265 /* May happen during ddraw uninitialization */
7266 TRACE("Render target set, but swapchain does not exist!\n");
7267 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7271 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7272 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7273 This->render_targets[i] = NULL;
7276 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7277 This->stencilBufferTarget = NULL;
7281 break;
7283 case WINED3DRTYPE_TEXTURE:
7284 case WINED3DRTYPE_CUBETEXTURE:
7285 case WINED3DRTYPE_VOLUMETEXTURE:
7286 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7287 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7288 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7289 This->stateBlock->textures[counter] = NULL;
7291 if (This->updateStateBlock != This->stateBlock ){
7292 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7293 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7294 This->updateStateBlock->textures[counter] = NULL;
7298 break;
7299 case WINED3DRTYPE_VOLUME:
7300 /* TODO: nothing really? */
7301 break;
7302 case WINED3DRTYPE_VERTEXBUFFER:
7303 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7305 int streamNumber;
7306 TRACE("Cleaning up stream pointers\n");
7308 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7309 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7310 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7312 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7313 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7314 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7315 This->updateStateBlock->streamSource[streamNumber] = 0;
7316 /* Set changed flag? */
7319 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) */
7320 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7321 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7322 This->stateBlock->streamSource[streamNumber] = 0;
7327 break;
7328 case WINED3DRTYPE_INDEXBUFFER:
7329 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7330 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7331 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7332 This->updateStateBlock->pIndexData = NULL;
7335 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7336 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7337 This->stateBlock->pIndexData = NULL;
7341 break;
7342 default:
7343 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7344 break;
7348 /* Remove the resource from the resourceStore */
7349 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7351 TRACE("Resource released\n");
7355 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7357 IWineD3DResourceImpl *resource, *cursor;
7358 HRESULT ret;
7359 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7361 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7362 TRACE("enumerating resource %p\n", resource);
7363 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7364 ret = pCallback((IWineD3DResource *) resource, pData);
7365 if(ret == S_FALSE) {
7366 TRACE("Canceling enumeration\n");
7367 break;
7370 return WINED3D_OK;
7373 /**********************************************************
7374 * IWineD3DDevice VTbl follows
7375 **********************************************************/
7377 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7379 /*** IUnknown methods ***/
7380 IWineD3DDeviceImpl_QueryInterface,
7381 IWineD3DDeviceImpl_AddRef,
7382 IWineD3DDeviceImpl_Release,
7383 /*** IWineD3DDevice methods ***/
7384 IWineD3DDeviceImpl_GetParent,
7385 /*** Creation methods**/
7386 IWineD3DDeviceImpl_CreateVertexBuffer,
7387 IWineD3DDeviceImpl_CreateIndexBuffer,
7388 IWineD3DDeviceImpl_CreateStateBlock,
7389 IWineD3DDeviceImpl_CreateSurface,
7390 IWineD3DDeviceImpl_CreateTexture,
7391 IWineD3DDeviceImpl_CreateVolumeTexture,
7392 IWineD3DDeviceImpl_CreateVolume,
7393 IWineD3DDeviceImpl_CreateCubeTexture,
7394 IWineD3DDeviceImpl_CreateQuery,
7395 IWineD3DDeviceImpl_CreateSwapChain,
7396 IWineD3DDeviceImpl_CreateVertexDeclaration,
7397 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7398 IWineD3DDeviceImpl_CreateVertexShader,
7399 IWineD3DDeviceImpl_CreatePixelShader,
7400 IWineD3DDeviceImpl_CreatePalette,
7401 /*** Odd functions **/
7402 IWineD3DDeviceImpl_Init3D,
7403 IWineD3DDeviceImpl_InitGDI,
7404 IWineD3DDeviceImpl_Uninit3D,
7405 IWineD3DDeviceImpl_UninitGDI,
7406 IWineD3DDeviceImpl_SetMultithreaded,
7407 IWineD3DDeviceImpl_EvictManagedResources,
7408 IWineD3DDeviceImpl_GetAvailableTextureMem,
7409 IWineD3DDeviceImpl_GetBackBuffer,
7410 IWineD3DDeviceImpl_GetCreationParameters,
7411 IWineD3DDeviceImpl_GetDeviceCaps,
7412 IWineD3DDeviceImpl_GetDirect3D,
7413 IWineD3DDeviceImpl_GetDisplayMode,
7414 IWineD3DDeviceImpl_SetDisplayMode,
7415 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7416 IWineD3DDeviceImpl_GetRasterStatus,
7417 IWineD3DDeviceImpl_GetSwapChain,
7418 IWineD3DDeviceImpl_Reset,
7419 IWineD3DDeviceImpl_SetDialogBoxMode,
7420 IWineD3DDeviceImpl_SetCursorProperties,
7421 IWineD3DDeviceImpl_SetCursorPosition,
7422 IWineD3DDeviceImpl_ShowCursor,
7423 IWineD3DDeviceImpl_TestCooperativeLevel,
7424 /*** Getters and setters **/
7425 IWineD3DDeviceImpl_SetClipPlane,
7426 IWineD3DDeviceImpl_GetClipPlane,
7427 IWineD3DDeviceImpl_SetClipStatus,
7428 IWineD3DDeviceImpl_GetClipStatus,
7429 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7430 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7431 IWineD3DDeviceImpl_SetDepthStencilSurface,
7432 IWineD3DDeviceImpl_GetDepthStencilSurface,
7433 IWineD3DDeviceImpl_SetGammaRamp,
7434 IWineD3DDeviceImpl_GetGammaRamp,
7435 IWineD3DDeviceImpl_SetIndices,
7436 IWineD3DDeviceImpl_GetIndices,
7437 IWineD3DDeviceImpl_SetBaseVertexIndex,
7438 IWineD3DDeviceImpl_GetBaseVertexIndex,
7439 IWineD3DDeviceImpl_SetLight,
7440 IWineD3DDeviceImpl_GetLight,
7441 IWineD3DDeviceImpl_SetLightEnable,
7442 IWineD3DDeviceImpl_GetLightEnable,
7443 IWineD3DDeviceImpl_SetMaterial,
7444 IWineD3DDeviceImpl_GetMaterial,
7445 IWineD3DDeviceImpl_SetNPatchMode,
7446 IWineD3DDeviceImpl_GetNPatchMode,
7447 IWineD3DDeviceImpl_SetPaletteEntries,
7448 IWineD3DDeviceImpl_GetPaletteEntries,
7449 IWineD3DDeviceImpl_SetPixelShader,
7450 IWineD3DDeviceImpl_GetPixelShader,
7451 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7452 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7453 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7454 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7455 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7456 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7457 IWineD3DDeviceImpl_SetRenderState,
7458 IWineD3DDeviceImpl_GetRenderState,
7459 IWineD3DDeviceImpl_SetRenderTarget,
7460 IWineD3DDeviceImpl_GetRenderTarget,
7461 IWineD3DDeviceImpl_SetFrontBackBuffers,
7462 IWineD3DDeviceImpl_SetSamplerState,
7463 IWineD3DDeviceImpl_GetSamplerState,
7464 IWineD3DDeviceImpl_SetScissorRect,
7465 IWineD3DDeviceImpl_GetScissorRect,
7466 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7467 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7468 IWineD3DDeviceImpl_SetStreamSource,
7469 IWineD3DDeviceImpl_GetStreamSource,
7470 IWineD3DDeviceImpl_SetStreamSourceFreq,
7471 IWineD3DDeviceImpl_GetStreamSourceFreq,
7472 IWineD3DDeviceImpl_SetTexture,
7473 IWineD3DDeviceImpl_GetTexture,
7474 IWineD3DDeviceImpl_SetTextureStageState,
7475 IWineD3DDeviceImpl_GetTextureStageState,
7476 IWineD3DDeviceImpl_SetTransform,
7477 IWineD3DDeviceImpl_GetTransform,
7478 IWineD3DDeviceImpl_SetVertexDeclaration,
7479 IWineD3DDeviceImpl_GetVertexDeclaration,
7480 IWineD3DDeviceImpl_SetVertexShader,
7481 IWineD3DDeviceImpl_GetVertexShader,
7482 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7483 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7484 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7485 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7486 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7487 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7488 IWineD3DDeviceImpl_SetViewport,
7489 IWineD3DDeviceImpl_GetViewport,
7490 IWineD3DDeviceImpl_MultiplyTransform,
7491 IWineD3DDeviceImpl_ValidateDevice,
7492 IWineD3DDeviceImpl_ProcessVertices,
7493 /*** State block ***/
7494 IWineD3DDeviceImpl_BeginStateBlock,
7495 IWineD3DDeviceImpl_EndStateBlock,
7496 /*** Scene management ***/
7497 IWineD3DDeviceImpl_BeginScene,
7498 IWineD3DDeviceImpl_EndScene,
7499 IWineD3DDeviceImpl_Present,
7500 IWineD3DDeviceImpl_Clear,
7501 /*** Drawing ***/
7502 IWineD3DDeviceImpl_DrawPrimitive,
7503 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7504 IWineD3DDeviceImpl_DrawPrimitiveUP,
7505 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7506 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7507 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7508 IWineD3DDeviceImpl_DrawRectPatch,
7509 IWineD3DDeviceImpl_DrawTriPatch,
7510 IWineD3DDeviceImpl_DeletePatch,
7511 IWineD3DDeviceImpl_ColorFill,
7512 IWineD3DDeviceImpl_UpdateTexture,
7513 IWineD3DDeviceImpl_UpdateSurface,
7514 IWineD3DDeviceImpl_GetFrontBufferData,
7515 /*** object tracking ***/
7516 IWineD3DDeviceImpl_ResourceReleased,
7517 IWineD3DDeviceImpl_EnumResources
7520 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7521 WINED3DRS_ALPHABLENDENABLE ,
7522 WINED3DRS_ALPHAFUNC ,
7523 WINED3DRS_ALPHAREF ,
7524 WINED3DRS_ALPHATESTENABLE ,
7525 WINED3DRS_BLENDOP ,
7526 WINED3DRS_COLORWRITEENABLE ,
7527 WINED3DRS_DESTBLEND ,
7528 WINED3DRS_DITHERENABLE ,
7529 WINED3DRS_FILLMODE ,
7530 WINED3DRS_FOGDENSITY ,
7531 WINED3DRS_FOGEND ,
7532 WINED3DRS_FOGSTART ,
7533 WINED3DRS_LASTPIXEL ,
7534 WINED3DRS_SHADEMODE ,
7535 WINED3DRS_SRCBLEND ,
7536 WINED3DRS_STENCILENABLE ,
7537 WINED3DRS_STENCILFAIL ,
7538 WINED3DRS_STENCILFUNC ,
7539 WINED3DRS_STENCILMASK ,
7540 WINED3DRS_STENCILPASS ,
7541 WINED3DRS_STENCILREF ,
7542 WINED3DRS_STENCILWRITEMASK ,
7543 WINED3DRS_STENCILZFAIL ,
7544 WINED3DRS_TEXTUREFACTOR ,
7545 WINED3DRS_WRAP0 ,
7546 WINED3DRS_WRAP1 ,
7547 WINED3DRS_WRAP2 ,
7548 WINED3DRS_WRAP3 ,
7549 WINED3DRS_WRAP4 ,
7550 WINED3DRS_WRAP5 ,
7551 WINED3DRS_WRAP6 ,
7552 WINED3DRS_WRAP7 ,
7553 WINED3DRS_ZENABLE ,
7554 WINED3DRS_ZFUNC ,
7555 WINED3DRS_ZWRITEENABLE
7558 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7559 WINED3DTSS_ADDRESSW ,
7560 WINED3DTSS_ALPHAARG0 ,
7561 WINED3DTSS_ALPHAARG1 ,
7562 WINED3DTSS_ALPHAARG2 ,
7563 WINED3DTSS_ALPHAOP ,
7564 WINED3DTSS_BUMPENVLOFFSET ,
7565 WINED3DTSS_BUMPENVLSCALE ,
7566 WINED3DTSS_BUMPENVMAT00 ,
7567 WINED3DTSS_BUMPENVMAT01 ,
7568 WINED3DTSS_BUMPENVMAT10 ,
7569 WINED3DTSS_BUMPENVMAT11 ,
7570 WINED3DTSS_COLORARG0 ,
7571 WINED3DTSS_COLORARG1 ,
7572 WINED3DTSS_COLORARG2 ,
7573 WINED3DTSS_COLOROP ,
7574 WINED3DTSS_RESULTARG ,
7575 WINED3DTSS_TEXCOORDINDEX ,
7576 WINED3DTSS_TEXTURETRANSFORMFLAGS
7579 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7580 WINED3DSAMP_ADDRESSU ,
7581 WINED3DSAMP_ADDRESSV ,
7582 WINED3DSAMP_ADDRESSW ,
7583 WINED3DSAMP_BORDERCOLOR ,
7584 WINED3DSAMP_MAGFILTER ,
7585 WINED3DSAMP_MINFILTER ,
7586 WINED3DSAMP_MIPFILTER ,
7587 WINED3DSAMP_MIPMAPLODBIAS ,
7588 WINED3DSAMP_MAXMIPLEVEL ,
7589 WINED3DSAMP_MAXANISOTROPY ,
7590 WINED3DSAMP_SRGBTEXTURE ,
7591 WINED3DSAMP_ELEMENTINDEX
7594 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7595 WINED3DRS_AMBIENT ,
7596 WINED3DRS_AMBIENTMATERIALSOURCE ,
7597 WINED3DRS_CLIPPING ,
7598 WINED3DRS_CLIPPLANEENABLE ,
7599 WINED3DRS_COLORVERTEX ,
7600 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7601 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7602 WINED3DRS_FOGDENSITY ,
7603 WINED3DRS_FOGEND ,
7604 WINED3DRS_FOGSTART ,
7605 WINED3DRS_FOGTABLEMODE ,
7606 WINED3DRS_FOGVERTEXMODE ,
7607 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7608 WINED3DRS_LIGHTING ,
7609 WINED3DRS_LOCALVIEWER ,
7610 WINED3DRS_MULTISAMPLEANTIALIAS ,
7611 WINED3DRS_MULTISAMPLEMASK ,
7612 WINED3DRS_NORMALIZENORMALS ,
7613 WINED3DRS_PATCHEDGESTYLE ,
7614 WINED3DRS_POINTSCALE_A ,
7615 WINED3DRS_POINTSCALE_B ,
7616 WINED3DRS_POINTSCALE_C ,
7617 WINED3DRS_POINTSCALEENABLE ,
7618 WINED3DRS_POINTSIZE ,
7619 WINED3DRS_POINTSIZE_MAX ,
7620 WINED3DRS_POINTSIZE_MIN ,
7621 WINED3DRS_POINTSPRITEENABLE ,
7622 WINED3DRS_RANGEFOGENABLE ,
7623 WINED3DRS_SPECULARMATERIALSOURCE ,
7624 WINED3DRS_TWEENFACTOR ,
7625 WINED3DRS_VERTEXBLEND ,
7626 WINED3DRS_CULLMODE ,
7627 WINED3DRS_FOGCOLOR
7630 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7631 WINED3DTSS_TEXCOORDINDEX ,
7632 WINED3DTSS_TEXTURETRANSFORMFLAGS
7635 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7636 WINED3DSAMP_DMAPOFFSET
7639 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7640 DWORD rep = This->StateTable[state].representative;
7641 DWORD idx;
7642 BYTE shift;
7643 UINT i;
7644 WineD3DContext *context;
7646 if(!rep) return;
7647 for(i = 0; i < This->numContexts; i++) {
7648 context = This->contexts[i];
7649 if(isStateDirty(context, rep)) continue;
7651 context->dirtyArray[context->numDirtyEntries++] = rep;
7652 idx = rep >> 5;
7653 shift = rep & 0x1f;
7654 context->isStateDirty[idx] |= (1 << shift);
7658 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7659 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7660 /* The drawable size of a pbuffer render target is the current pbuffer size
7662 *width = dev->pbufferWidth;
7663 *height = dev->pbufferHeight;
7666 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7667 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7669 *width = This->pow2Width;
7670 *height = This->pow2Height;
7673 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7674 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7675 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7676 * current context's drawable, which is the size of the back buffer of the swapchain
7677 * the active context belongs to. The back buffer of the swapchain is stored as the
7678 * surface the context belongs to.
7680 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7681 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;