wined3d: Convert transform to a bitmap in struct SAVEDSTATES.
[wine/testsucceed.git] / dlls / wined3d / device.c
blob8c98962e7b5511d90f7f0db1cf28935cd5365f28
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 |= 1 << StreamNumber;
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 |= 1 << StreamNumber;
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 >> 5] |= 1 << (d3dts & 0x1f);
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 |= 1 << Index;
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 This->fixed_function_usage_map = 0;
3642 for (i = 0; i < MAX_TEXTURES; ++i) {
3643 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3644 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3645 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3646 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3647 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3648 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3649 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3650 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3652 if (color_op == WINED3DTOP_DISABLE) {
3653 /* Not used, and disable higher stages */
3654 break;
3657 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3658 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3659 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3660 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3661 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3662 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3663 This->fixed_function_usage_map |= (1 << i);
3666 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3667 This->fixed_function_usage_map |= (1 << (i + 1));
3672 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3673 int i, tex;
3674 WORD ffu_map;
3676 device_update_fixed_function_usage_map(This);
3677 ffu_map = This->fixed_function_usage_map;
3679 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3680 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3681 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3683 if (!(ffu_map & 1)) continue;
3685 if (This->texUnitMap[i] != i) {
3686 device_map_stage(This, i, i);
3687 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3688 markTextureStagesDirty(This, i);
3691 return;
3694 /* Now work out the mapping */
3695 tex = 0;
3696 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3698 if (!(ffu_map & 1)) continue;
3700 if (This->texUnitMap[i] != tex) {
3701 device_map_stage(This, i, tex);
3702 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3703 markTextureStagesDirty(This, i);
3706 ++tex;
3710 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3711 const DWORD *sampler_tokens =
3712 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3713 int i;
3715 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3716 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3717 device_map_stage(This, i, i);
3718 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3719 if (i < MAX_TEXTURES) {
3720 markTextureStagesDirty(This, i);
3726 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3727 const DWORD *vshader_sampler_tokens, int unit)
3729 int current_mapping = This->rev_tex_unit_map[unit];
3731 if (current_mapping == -1) {
3732 /* Not currently used */
3733 return TRUE;
3736 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3737 /* Used by a fragment sampler */
3739 if (!pshader_sampler_tokens) {
3740 /* No pixel shader, check fixed function */
3741 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3744 /* Pixel shader, check the shader's sampler map */
3745 return !pshader_sampler_tokens[current_mapping];
3748 /* Used by a vertex sampler */
3749 return !vshader_sampler_tokens[current_mapping];
3752 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3753 const DWORD *vshader_sampler_tokens =
3754 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3755 const DWORD *pshader_sampler_tokens = NULL;
3756 int start = GL_LIMITS(combined_samplers) - 1;
3757 int i;
3759 if (ps) {
3760 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3762 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3763 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3764 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3767 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3768 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3769 if (vshader_sampler_tokens[i]) {
3770 if (This->texUnitMap[vsampler_idx] != -1) {
3771 /* Already mapped somewhere */
3772 continue;
3775 while (start >= 0) {
3776 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3777 device_map_stage(This, vsampler_idx, start);
3778 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3780 --start;
3781 break;
3784 --start;
3790 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3791 BOOL vs = use_vs(This->stateBlock);
3792 BOOL ps = use_ps(This->stateBlock);
3794 * Rules are:
3795 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3796 * that would be really messy and require shader recompilation
3797 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3798 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3800 if (ps) {
3801 device_map_psamplers(This);
3802 } else {
3803 device_map_fixed_function_samplers(This);
3806 if (vs) {
3807 device_map_vsamplers(This, ps);
3811 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3813 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3814 This->updateStateBlock->pixelShader = pShader;
3815 This->updateStateBlock->changed.pixelShader = TRUE;
3817 /* Handle recording of state blocks */
3818 if (This->isRecordingState) {
3819 TRACE("Recording... not performing anything\n");
3822 if (This->isRecordingState) {
3823 TRACE("Recording... not performing anything\n");
3824 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3825 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3826 return WINED3D_OK;
3829 if(pShader == oldShader) {
3830 TRACE("App is setting the old pixel shader over, nothing to do\n");
3831 return WINED3D_OK;
3834 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3835 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3837 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3838 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3840 return WINED3D_OK;
3843 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3846 if (NULL == ppShader) {
3847 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3848 return WINED3DERR_INVALIDCALL;
3851 *ppShader = This->stateBlock->pixelShader;
3852 if (NULL != *ppShader) {
3853 IWineD3DPixelShader_AddRef(*ppShader);
3855 TRACE("(%p) : returning %p\n", This, *ppShader);
3856 return WINED3D_OK;
3859 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3860 IWineD3DDevice *iface,
3861 UINT start,
3862 CONST BOOL *srcData,
3863 UINT count) {
3865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3866 int i, cnt = min(count, MAX_CONST_B - start);
3868 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3869 iface, srcData, start, count);
3871 if (srcData == NULL || cnt < 0)
3872 return WINED3DERR_INVALIDCALL;
3874 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3875 for (i = 0; i < cnt; i++)
3876 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3878 for (i = start; i < cnt + start; ++i) {
3879 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3882 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3884 return WINED3D_OK;
3887 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3888 IWineD3DDevice *iface,
3889 UINT start,
3890 BOOL *dstData,
3891 UINT count) {
3893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3894 int cnt = min(count, MAX_CONST_B - start);
3896 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3897 iface, dstData, start, count);
3899 if (dstData == NULL || cnt < 0)
3900 return WINED3DERR_INVALIDCALL;
3902 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3903 return WINED3D_OK;
3906 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3907 IWineD3DDevice *iface,
3908 UINT start,
3909 CONST int *srcData,
3910 UINT count) {
3912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3913 int i, cnt = min(count, MAX_CONST_I - start);
3915 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3916 iface, srcData, start, count);
3918 if (srcData == NULL || cnt < 0)
3919 return WINED3DERR_INVALIDCALL;
3921 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3922 for (i = 0; i < cnt; i++)
3923 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3924 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3926 for (i = start; i < cnt + start; ++i) {
3927 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3930 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3932 return WINED3D_OK;
3935 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3936 IWineD3DDevice *iface,
3937 UINT start,
3938 int *dstData,
3939 UINT count) {
3941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3942 int cnt = min(count, MAX_CONST_I - start);
3944 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3945 iface, dstData, start, count);
3947 if (dstData == NULL || cnt < 0)
3948 return WINED3DERR_INVALIDCALL;
3950 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3951 return WINED3D_OK;
3954 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3955 IWineD3DDevice *iface,
3956 UINT start,
3957 CONST float *srcData,
3958 UINT count) {
3960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3961 UINT i;
3963 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3964 iface, srcData, start, count);
3966 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3967 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3968 return WINED3DERR_INVALIDCALL;
3970 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3971 if(TRACE_ON(d3d)) {
3972 for (i = 0; i < count; i++)
3973 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3974 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3977 if (!This->isRecordingState)
3979 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3980 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3983 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3984 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3986 return WINED3D_OK;
3989 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3990 IWineD3DDevice *iface,
3991 UINT start,
3992 float *dstData,
3993 UINT count) {
3995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3996 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3998 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3999 iface, dstData, start, count);
4001 if (dstData == NULL || cnt < 0)
4002 return WINED3DERR_INVALIDCALL;
4004 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4005 return WINED3D_OK;
4008 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4009 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4010 const WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags)
4012 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4013 unsigned int i;
4014 DWORD DestFVF = dest->fvf;
4015 WINED3DVIEWPORT vp;
4016 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4017 BOOL doClip;
4018 DWORD numTextures;
4020 if (lpStrideData->u.s.normal.lpData) {
4021 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4024 if (lpStrideData->u.s.position.lpData == NULL) {
4025 ERR("Source has no position mask\n");
4026 return WINED3DERR_INVALIDCALL;
4029 /* We might access VBOs from this code, so hold the lock */
4030 ENTER_GL();
4032 if (dest->resource.allocatedMemory == NULL) {
4033 /* This may happen if we do direct locking into a vbo. Unlikely,
4034 * but theoretically possible(ddraw processvertices test)
4036 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4037 if(!dest->resource.allocatedMemory) {
4038 LEAVE_GL();
4039 ERR("Out of memory\n");
4040 return E_OUTOFMEMORY;
4042 if(dest->vbo) {
4043 const void *src;
4044 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4045 checkGLcall("glBindBufferARB");
4046 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4047 if(src) {
4048 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4050 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4051 checkGLcall("glUnmapBufferARB");
4055 /* Get a pointer into the destination vbo(create one if none exists) and
4056 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4058 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4059 dest->Flags |= VBFLAG_CREATEVBO;
4060 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4063 if(dest->vbo) {
4064 unsigned char extrabytes = 0;
4065 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4066 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4067 * this may write 4 extra bytes beyond the area that should be written
4069 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4070 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4071 if(!dest_conv_addr) {
4072 ERR("Out of memory\n");
4073 /* Continue without storing converted vertices */
4075 dest_conv = dest_conv_addr;
4078 /* Should I clip?
4079 * a) WINED3DRS_CLIPPING is enabled
4080 * b) WINED3DVOP_CLIP is passed
4082 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4083 static BOOL warned = FALSE;
4085 * The clipping code is not quite correct. Some things need
4086 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4087 * so disable clipping for now.
4088 * (The graphics in Half-Life are broken, and my processvertices
4089 * test crashes with IDirect3DDevice3)
4090 doClip = TRUE;
4092 doClip = FALSE;
4093 if(!warned) {
4094 warned = TRUE;
4095 FIXME("Clipping is broken and disabled for now\n");
4097 } else doClip = FALSE;
4098 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4100 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4101 WINED3DTS_VIEW,
4102 &view_mat);
4103 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4104 WINED3DTS_PROJECTION,
4105 &proj_mat);
4106 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4107 WINED3DTS_WORLDMATRIX(0),
4108 &world_mat);
4110 TRACE("View mat:\n");
4111 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);
4112 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);
4113 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);
4114 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);
4116 TRACE("Proj mat:\n");
4117 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);
4118 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);
4119 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);
4120 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);
4122 TRACE("World mat:\n");
4123 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);
4124 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);
4125 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);
4126 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);
4128 /* Get the viewport */
4129 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4130 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4131 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4133 multiply_matrix(&mat,&view_mat,&world_mat);
4134 multiply_matrix(&mat,&proj_mat,&mat);
4136 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4138 for (i = 0; i < dwCount; i+= 1) {
4139 unsigned int tex_index;
4141 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4142 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4143 /* The position first */
4144 const float *p =
4145 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4146 float x, y, z, rhw;
4147 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4149 /* Multiplication with world, view and projection matrix */
4150 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);
4151 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);
4152 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);
4153 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);
4155 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4157 /* WARNING: The following things are taken from d3d7 and were not yet checked
4158 * against d3d8 or d3d9!
4161 /* Clipping conditions: From msdn
4163 * A vertex is clipped if it does not match the following requirements
4164 * -rhw < x <= rhw
4165 * -rhw < y <= rhw
4166 * 0 < z <= rhw
4167 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4169 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4170 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4174 if( !doClip ||
4175 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4176 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4177 ( rhw > eps ) ) ) {
4179 /* "Normal" viewport transformation (not clipped)
4180 * 1) The values are divided by rhw
4181 * 2) The y axis is negative, so multiply it with -1
4182 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4183 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4184 * 4) Multiply x with Width/2 and add Width/2
4185 * 5) The same for the height
4186 * 6) Add the viewpoint X and Y to the 2D coordinates and
4187 * The minimum Z value to z
4188 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4190 * Well, basically it's simply a linear transformation into viewport
4191 * coordinates
4194 x /= rhw;
4195 y /= rhw;
4196 z /= rhw;
4198 y *= -1;
4200 x *= vp.Width / 2;
4201 y *= vp.Height / 2;
4202 z *= vp.MaxZ - vp.MinZ;
4204 x += vp.Width / 2 + vp.X;
4205 y += vp.Height / 2 + vp.Y;
4206 z += vp.MinZ;
4208 rhw = 1 / rhw;
4209 } else {
4210 /* That vertex got clipped
4211 * Contrary to OpenGL it is not dropped completely, it just
4212 * undergoes a different calculation.
4214 TRACE("Vertex got clipped\n");
4215 x += rhw;
4216 y += rhw;
4218 x /= 2;
4219 y /= 2;
4221 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4222 * outside of the main vertex buffer memory. That needs some more
4223 * investigation...
4227 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4230 ( (float *) dest_ptr)[0] = x;
4231 ( (float *) dest_ptr)[1] = y;
4232 ( (float *) dest_ptr)[2] = z;
4233 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4235 dest_ptr += 3 * sizeof(float);
4237 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4238 dest_ptr += sizeof(float);
4241 if(dest_conv) {
4242 float w = 1 / rhw;
4243 ( (float *) dest_conv)[0] = x * w;
4244 ( (float *) dest_conv)[1] = y * w;
4245 ( (float *) dest_conv)[2] = z * w;
4246 ( (float *) dest_conv)[3] = w;
4248 dest_conv += 3 * sizeof(float);
4250 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4251 dest_conv += sizeof(float);
4255 if (DestFVF & WINED3DFVF_PSIZE) {
4256 dest_ptr += sizeof(DWORD);
4257 if(dest_conv) dest_conv += sizeof(DWORD);
4259 if (DestFVF & WINED3DFVF_NORMAL) {
4260 const float *normal =
4261 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4262 /* AFAIK this should go into the lighting information */
4263 FIXME("Didn't expect the destination to have a normal\n");
4264 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4265 if(dest_conv) {
4266 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4270 if (DestFVF & WINED3DFVF_DIFFUSE) {
4271 const DWORD *color_d =
4272 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4273 if(!color_d) {
4274 static BOOL warned = FALSE;
4276 if(!warned) {
4277 ERR("No diffuse color in source, but destination has one\n");
4278 warned = TRUE;
4281 *( (DWORD *) dest_ptr) = 0xffffffff;
4282 dest_ptr += sizeof(DWORD);
4284 if(dest_conv) {
4285 *( (DWORD *) dest_conv) = 0xffffffff;
4286 dest_conv += sizeof(DWORD);
4289 else {
4290 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4291 if(dest_conv) {
4292 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4293 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4294 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4295 dest_conv += sizeof(DWORD);
4300 if (DestFVF & WINED3DFVF_SPECULAR) {
4301 /* What's the color value in the feedback buffer? */
4302 const DWORD *color_s =
4303 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4304 if(!color_s) {
4305 static BOOL warned = FALSE;
4307 if(!warned) {
4308 ERR("No specular color in source, but destination has one\n");
4309 warned = TRUE;
4312 *( (DWORD *) dest_ptr) = 0xFF000000;
4313 dest_ptr += sizeof(DWORD);
4315 if(dest_conv) {
4316 *( (DWORD *) dest_conv) = 0xFF000000;
4317 dest_conv += sizeof(DWORD);
4320 else {
4321 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4322 if(dest_conv) {
4323 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4324 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4325 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4326 dest_conv += sizeof(DWORD);
4331 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4332 const float *tex_coord =
4333 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4334 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4335 if(!tex_coord) {
4336 ERR("No source texture, but destination requests one\n");
4337 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4338 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4340 else {
4341 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4342 if(dest_conv) {
4343 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4349 if(dest_conv) {
4350 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4351 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4352 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4353 dwCount * get_flexible_vertex_size(DestFVF),
4354 dest_conv_addr));
4355 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4356 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4359 LEAVE_GL();
4361 return WINED3D_OK;
4363 #undef copy_and_next
4365 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4367 WineDirect3DVertexStridedData strided;
4368 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4369 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4371 if(pVertexDecl) {
4372 ERR("Output vertex declaration not implemented yet\n");
4375 /* Need any context to write to the vbo. */
4376 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4378 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4379 * control the streamIsUP flag, thus restore it afterwards.
4381 This->stateBlock->streamIsUP = FALSE;
4382 memset(&strided, 0, sizeof(strided));
4383 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4384 This->stateBlock->streamIsUP = streamWasUP;
4386 if(vbo || SrcStartIndex) {
4387 unsigned int i;
4388 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4389 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4391 * Also get the start index in, but only loop over all elements if there's something to add at all.
4393 #define FIXSRC(type) \
4394 if(strided.u.s.type.VBO) { \
4395 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4396 strided.u.s.type.VBO = 0; \
4397 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4398 ENTER_GL(); \
4399 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4400 vb->vbo = 0; \
4401 LEAVE_GL(); \
4403 if(strided.u.s.type.lpData) { \
4404 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4406 FIXSRC(position);
4407 FIXSRC(blendWeights);
4408 FIXSRC(blendMatrixIndices);
4409 FIXSRC(normal);
4410 FIXSRC(pSize);
4411 FIXSRC(diffuse);
4412 FIXSRC(specular);
4413 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4414 FIXSRC(texCoords[i]);
4416 FIXSRC(position2);
4417 FIXSRC(normal2);
4418 FIXSRC(tangent);
4419 FIXSRC(binormal);
4420 FIXSRC(tessFactor);
4421 FIXSRC(fog);
4422 FIXSRC(depth);
4423 FIXSRC(sample);
4424 #undef FIXSRC
4427 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4430 /*****
4431 * Get / Set Texture Stage States
4432 * TODO: Verify against dx9 definitions
4433 *****/
4434 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4436 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4438 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4440 if (Stage >= MAX_TEXTURES) {
4441 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4442 return WINED3D_OK;
4445 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4446 This->updateStateBlock->textureState[Stage][Type] = Value;
4448 if (This->isRecordingState) {
4449 TRACE("Recording... not performing anything\n");
4450 return WINED3D_OK;
4453 /* Checked after the assignments to allow proper stateblock recording */
4454 if(oldValue == Value) {
4455 TRACE("App is setting the old value over, nothing to do\n");
4456 return WINED3D_OK;
4459 if(Stage > This->stateBlock->lowest_disabled_stage &&
4460 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4461 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4462 * Changes in other states are important on disabled stages too
4464 return WINED3D_OK;
4467 if(Type == WINED3DTSS_COLOROP) {
4468 int i;
4470 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4471 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4472 * they have to be disabled
4474 * The current stage is dirtified below.
4476 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4477 TRACE("Additionally dirtifying stage %d\n", i);
4478 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4480 This->stateBlock->lowest_disabled_stage = Stage;
4481 TRACE("New lowest disabled: %d\n", Stage);
4482 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4483 /* Previously disabled stage enabled. Stages above it may need enabling
4484 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4485 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4487 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4490 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4491 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4492 break;
4494 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4495 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4497 This->stateBlock->lowest_disabled_stage = i;
4498 TRACE("New lowest disabled: %d\n", i);
4502 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4504 return WINED3D_OK;
4507 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4509 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4510 *pValue = This->updateStateBlock->textureState[Stage][Type];
4511 return WINED3D_OK;
4514 /*****
4515 * Get / Set Texture
4516 *****/
4517 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4519 IWineD3DBaseTexture *oldTexture;
4521 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4523 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4524 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4527 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4528 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4529 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4532 oldTexture = This->updateStateBlock->textures[Stage];
4534 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4535 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4537 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4538 return WINED3DERR_INVALIDCALL;
4541 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4542 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4544 This->updateStateBlock->changed.textures |= 1 << Stage;
4545 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4546 This->updateStateBlock->textures[Stage] = pTexture;
4548 /* Handle recording of state blocks */
4549 if (This->isRecordingState) {
4550 TRACE("Recording... not performing anything\n");
4551 return WINED3D_OK;
4554 if(oldTexture == pTexture) {
4555 TRACE("App is setting the same texture again, nothing to do\n");
4556 return WINED3D_OK;
4559 /** NOTE: MSDN says that setTexture increases the reference count,
4560 * and that the application must set the texture back to null (or have a leaky application),
4561 * This means we should pass the refcount up to the parent
4562 *******************************/
4563 if (NULL != This->updateStateBlock->textures[Stage]) {
4564 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4565 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4567 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4568 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4569 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4570 * so the COLOROP and ALPHAOP have to be dirtified.
4572 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4573 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4575 if(bindCount == 1) {
4576 new->baseTexture.sampler = Stage;
4578 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4582 if (NULL != oldTexture) {
4583 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4584 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4586 IWineD3DBaseTexture_Release(oldTexture);
4587 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4588 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4589 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4592 if(bindCount && old->baseTexture.sampler == Stage) {
4593 int i;
4594 /* Have to do a search for the other sampler(s) where the texture is bound to
4595 * Shouldn't happen as long as apps bind a texture only to one stage
4597 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4598 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4599 if(This->updateStateBlock->textures[i] == oldTexture) {
4600 old->baseTexture.sampler = i;
4601 break;
4607 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4609 return WINED3D_OK;
4612 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4615 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4617 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4618 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4621 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4622 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4623 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4626 *ppTexture=This->stateBlock->textures[Stage];
4627 if (*ppTexture)
4628 IWineD3DBaseTexture_AddRef(*ppTexture);
4630 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4632 return WINED3D_OK;
4635 /*****
4636 * Get Back Buffer
4637 *****/
4638 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4639 IWineD3DSurface **ppBackBuffer) {
4640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4641 IWineD3DSwapChain *swapChain;
4642 HRESULT hr;
4644 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4646 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4647 if (hr == WINED3D_OK) {
4648 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4649 IWineD3DSwapChain_Release(swapChain);
4650 } else {
4651 *ppBackBuffer = NULL;
4653 return hr;
4656 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4658 WARN("(%p) : stub, calling idirect3d for now\n", This);
4659 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4662 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4664 IWineD3DSwapChain *swapChain;
4665 HRESULT hr;
4667 if(iSwapChain > 0) {
4668 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4669 if (hr == WINED3D_OK) {
4670 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4671 IWineD3DSwapChain_Release(swapChain);
4672 } else {
4673 FIXME("(%p) Error getting display mode\n", This);
4675 } else {
4676 /* Don't read the real display mode,
4677 but return the stored mode instead. X11 can't change the color
4678 depth, and some apps are pretty angry if they SetDisplayMode from
4679 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4681 Also don't relay to the swapchain because with ddraw it's possible
4682 that there isn't a swapchain at all */
4683 pMode->Width = This->ddraw_width;
4684 pMode->Height = This->ddraw_height;
4685 pMode->Format = This->ddraw_format;
4686 pMode->RefreshRate = 0;
4687 hr = WINED3D_OK;
4690 return hr;
4693 /*****
4694 * Stateblock related functions
4695 *****/
4697 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4699 IWineD3DStateBlockImpl *object;
4700 HRESULT temp_result;
4701 int i;
4703 TRACE("(%p)\n", This);
4705 if (This->isRecordingState) {
4706 return WINED3DERR_INVALIDCALL;
4709 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4710 if (NULL == object ) {
4711 FIXME("(%p)Error allocating memory for stateblock\n", This);
4712 return E_OUTOFMEMORY;
4714 TRACE("(%p) created object %p\n", This, object);
4715 object->wineD3DDevice= This;
4716 /** FIXME: object->parent = parent; **/
4717 object->parent = NULL;
4718 object->blockType = WINED3DSBT_RECORDED;
4719 object->ref = 1;
4720 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4722 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4723 list_init(&object->lightMap[i]);
4726 temp_result = allocate_shader_constants(object);
4727 if (WINED3D_OK != temp_result)
4728 return temp_result;
4730 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4731 This->updateStateBlock = object;
4732 This->isRecordingState = TRUE;
4734 TRACE("(%p) recording stateblock %p\n",This , object);
4735 return WINED3D_OK;
4738 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4740 unsigned int i, j;
4741 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4743 if (!This->isRecordingState) {
4744 WARN("(%p) not recording! returning error\n", This);
4745 *ppStateBlock = NULL;
4746 return WINED3DERR_INVALIDCALL;
4749 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4750 if(object->changed.renderState[i]) {
4751 object->contained_render_states[object->num_contained_render_states] = i;
4752 object->num_contained_render_states++;
4756 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
4758 DWORD map = object->changed.transform[i];
4759 for (j = 0; map; map >>= 1, ++j)
4761 if (!(map & 1)) continue;
4763 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
4766 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4767 if(object->changed.vertexShaderConstantsF[i]) {
4768 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4769 object->num_contained_vs_consts_f++;
4772 for(i = 0; i < MAX_CONST_I; i++) {
4773 if (object->changed.vertexShaderConstantsI & (1 << i))
4775 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4776 object->num_contained_vs_consts_i++;
4779 for(i = 0; i < MAX_CONST_B; i++) {
4780 if (object->changed.vertexShaderConstantsB & (1 << i))
4782 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4783 object->num_contained_vs_consts_b++;
4786 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4788 if (object->changed.pixelShaderConstantsF[i])
4790 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4791 ++object->num_contained_ps_consts_f;
4794 for(i = 0; i < MAX_CONST_I; i++) {
4795 if (object->changed.pixelShaderConstantsI & (1 << i))
4797 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4798 object->num_contained_ps_consts_i++;
4801 for(i = 0; i < MAX_CONST_B; i++) {
4802 if (object->changed.pixelShaderConstantsB & (1 << i))
4804 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4805 object->num_contained_ps_consts_b++;
4808 for(i = 0; i < MAX_TEXTURES; i++) {
4809 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4810 if(object->changed.textureState[i][j]) {
4811 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4812 object->contained_tss_states[object->num_contained_tss_states].state = j;
4813 object->num_contained_tss_states++;
4817 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4818 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4819 if(object->changed.samplerState[i][j]) {
4820 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4821 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4822 object->num_contained_sampler_states++;
4827 *ppStateBlock = (IWineD3DStateBlock*) object;
4828 This->isRecordingState = FALSE;
4829 This->updateStateBlock = This->stateBlock;
4830 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4831 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4832 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4833 return WINED3D_OK;
4836 /*****
4837 * Scene related functions
4838 *****/
4839 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4840 /* At the moment we have no need for any functionality at the beginning
4841 of a scene */
4842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4843 TRACE("(%p)\n", This);
4845 if(This->inScene) {
4846 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4847 return WINED3DERR_INVALIDCALL;
4849 This->inScene = TRUE;
4850 return WINED3D_OK;
4853 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4854 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4855 TRACE("(%p)\n", This);
4857 if(!This->inScene) {
4858 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4859 return WINED3DERR_INVALIDCALL;
4862 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4863 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4864 glFlush();
4865 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4866 * fails
4869 This->inScene = FALSE;
4870 return WINED3D_OK;
4873 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4874 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4875 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4877 IWineD3DSwapChain *swapChain = NULL;
4878 int i;
4879 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4881 TRACE("(%p) Presenting the frame\n", This);
4883 for(i = 0 ; i < swapchains ; i ++) {
4885 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4886 TRACE("presentinng chain %d, %p\n", i, swapChain);
4887 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4888 IWineD3DSwapChain_Release(swapChain);
4891 return WINED3D_OK;
4894 /* Not called from the VTable (internal subroutine) */
4895 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4896 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4897 float Z, DWORD Stencil) {
4898 GLbitfield glMask = 0;
4899 unsigned int i;
4900 WINED3DRECT curRect;
4901 RECT vp_rect;
4902 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4903 UINT drawable_width, drawable_height;
4904 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4905 IWineD3DSwapChainImpl *swapchain = NULL;
4907 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4908 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4909 * for the cleared parts, and the untouched parts.
4911 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4912 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4913 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4914 * checking all this if the dest surface is in the drawable anyway.
4916 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4917 while(1) {
4918 if(vp->X != 0 || vp->Y != 0 ||
4919 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4920 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4921 break;
4923 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4924 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4925 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4926 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4927 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4928 break;
4930 if(Count > 0 && pRects && (
4931 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4932 pRects[0].x2 < target->currentDesc.Width ||
4933 pRects[0].y2 < target->currentDesc.Height)) {
4934 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4935 break;
4937 break;
4941 target->get_drawable_size(target, &drawable_width, &drawable_height);
4943 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4944 ENTER_GL();
4946 /* Only set the values up once, as they are not changing */
4947 if (Flags & WINED3DCLEAR_STENCIL) {
4948 glClearStencil(Stencil);
4949 checkGLcall("glClearStencil");
4950 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4951 glStencilMask(0xFFFFFFFF);
4954 if (Flags & WINED3DCLEAR_ZBUFFER) {
4955 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4956 glDepthMask(GL_TRUE);
4957 glClearDepth(Z);
4958 checkGLcall("glClearDepth");
4959 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4960 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4962 if (vp->X != 0 || vp->Y != 0 ||
4963 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4964 surface_load_ds_location(This->stencilBufferTarget, location);
4966 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4967 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4968 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4969 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4970 surface_load_ds_location(This->stencilBufferTarget, location);
4972 else if (Count > 0 && pRects && (
4973 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4974 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4975 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4976 surface_load_ds_location(This->stencilBufferTarget, location);
4980 if (Flags & WINED3DCLEAR_TARGET) {
4981 TRACE("Clearing screen with glClear to color %x\n", Color);
4982 glClearColor(D3DCOLOR_R(Color),
4983 D3DCOLOR_G(Color),
4984 D3DCOLOR_B(Color),
4985 D3DCOLOR_A(Color));
4986 checkGLcall("glClearColor");
4988 /* Clear ALL colors! */
4989 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4990 glMask = glMask | GL_COLOR_BUFFER_BIT;
4993 vp_rect.left = vp->X;
4994 vp_rect.top = vp->Y;
4995 vp_rect.right = vp->X + vp->Width;
4996 vp_rect.bottom = vp->Y + vp->Height;
4997 if (!(Count > 0 && pRects)) {
4998 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4999 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5001 if(This->render_offscreen) {
5002 glScissor(vp_rect.left, vp_rect.top,
5003 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5004 } else {
5005 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5006 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5008 checkGLcall("glScissor");
5009 glClear(glMask);
5010 checkGLcall("glClear");
5011 } else {
5012 /* Now process each rect in turn */
5013 for (i = 0; i < Count; i++) {
5014 /* Note gl uses lower left, width/height */
5015 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5016 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5017 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5019 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5020 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5021 curRect.x1, (target->currentDesc.Height - curRect.y2),
5022 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5024 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5025 * The rectangle is not cleared, no error is returned, but further rectanlges are
5026 * still cleared if they are valid
5028 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5029 TRACE("Rectangle with negative dimensions, ignoring\n");
5030 continue;
5033 if(This->render_offscreen) {
5034 glScissor(curRect.x1, curRect.y1,
5035 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5036 } else {
5037 glScissor(curRect.x1, drawable_height - curRect.y2,
5038 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5040 checkGLcall("glScissor");
5042 glClear(glMask);
5043 checkGLcall("glClear");
5047 /* Restore the old values (why..?) */
5048 if (Flags & WINED3DCLEAR_STENCIL) {
5049 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5051 if (Flags & WINED3DCLEAR_TARGET) {
5052 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5053 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5054 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5055 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5056 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5058 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5059 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5061 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5063 if (Flags & WINED3DCLEAR_ZBUFFER) {
5064 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5065 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5066 surface_modify_ds_location(This->stencilBufferTarget, location);
5069 LEAVE_GL();
5071 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5072 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5073 glFlush();
5075 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5078 return WINED3D_OK;
5081 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5082 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5084 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5086 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5087 Count, pRects, Flags, Color, Z, Stencil);
5089 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5090 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5091 /* TODO: What about depth stencil buffers without stencil bits? */
5092 return WINED3DERR_INVALIDCALL;
5095 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5098 /*****
5099 * Drawing functions
5100 *****/
5101 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5102 UINT PrimitiveCount) {
5104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5106 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5107 debug_d3dprimitivetype(PrimitiveType),
5108 StartVertex, PrimitiveCount);
5110 if(!This->stateBlock->vertexDecl) {
5111 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5112 return WINED3DERR_INVALIDCALL;
5115 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5116 if(This->stateBlock->streamIsUP) {
5117 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5118 This->stateBlock->streamIsUP = FALSE;
5121 if(This->stateBlock->loadBaseVertexIndex != 0) {
5122 This->stateBlock->loadBaseVertexIndex = 0;
5123 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5125 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5126 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5127 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5128 return WINED3D_OK;
5131 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5132 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5133 WINED3DPRIMITIVETYPE PrimitiveType,
5134 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5137 UINT idxStride = 2;
5138 IWineD3DIndexBuffer *pIB;
5139 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5140 GLuint vbo;
5142 pIB = This->stateBlock->pIndexData;
5143 if (!pIB) {
5144 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5145 * without an index buffer set. (The first time at least...)
5146 * D3D8 simply dies, but I doubt it can do much harm to return
5147 * D3DERR_INVALIDCALL there as well. */
5148 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5149 return WINED3DERR_INVALIDCALL;
5152 if(!This->stateBlock->vertexDecl) {
5153 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5154 return WINED3DERR_INVALIDCALL;
5157 if(This->stateBlock->streamIsUP) {
5158 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5159 This->stateBlock->streamIsUP = FALSE;
5161 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5163 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5164 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5165 minIndex, NumVertices, startIndex, primCount);
5167 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5168 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5169 idxStride = 2;
5170 } else {
5171 idxStride = 4;
5174 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5175 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5176 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5179 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5180 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5182 return WINED3D_OK;
5185 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5186 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5187 UINT VertexStreamZeroStride) {
5188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5189 IWineD3DVertexBuffer *vb;
5191 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5192 debug_d3dprimitivetype(PrimitiveType),
5193 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5195 if(!This->stateBlock->vertexDecl) {
5196 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5197 return WINED3DERR_INVALIDCALL;
5200 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5201 vb = This->stateBlock->streamSource[0];
5202 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5203 if(vb) IWineD3DVertexBuffer_Release(vb);
5204 This->stateBlock->streamOffset[0] = 0;
5205 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5206 This->stateBlock->streamIsUP = TRUE;
5207 This->stateBlock->loadBaseVertexIndex = 0;
5209 /* TODO: Only mark dirty if drawing from a different UP address */
5210 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5212 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5213 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5215 /* MSDN specifies stream zero settings must be set to NULL */
5216 This->stateBlock->streamStride[0] = 0;
5217 This->stateBlock->streamSource[0] = NULL;
5219 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5220 * the new stream sources or use UP drawing again
5222 return WINED3D_OK;
5225 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5226 UINT MinVertexIndex, UINT NumVertices,
5227 UINT PrimitiveCount, CONST void* pIndexData,
5228 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5229 UINT VertexStreamZeroStride) {
5230 int idxStride;
5231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5232 IWineD3DVertexBuffer *vb;
5233 IWineD3DIndexBuffer *ib;
5235 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5236 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5237 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5238 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5240 if(!This->stateBlock->vertexDecl) {
5241 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5242 return WINED3DERR_INVALIDCALL;
5245 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5246 idxStride = 2;
5247 } else {
5248 idxStride = 4;
5251 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5252 vb = This->stateBlock->streamSource[0];
5253 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5254 if(vb) IWineD3DVertexBuffer_Release(vb);
5255 This->stateBlock->streamIsUP = TRUE;
5256 This->stateBlock->streamOffset[0] = 0;
5257 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5259 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5260 This->stateBlock->baseVertexIndex = 0;
5261 This->stateBlock->loadBaseVertexIndex = 0;
5262 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5263 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5266 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5268 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5269 This->stateBlock->streamSource[0] = NULL;
5270 This->stateBlock->streamStride[0] = 0;
5271 ib = This->stateBlock->pIndexData;
5272 if(ib) {
5273 IWineD3DIndexBuffer_Release(ib);
5274 This->stateBlock->pIndexData = NULL;
5276 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5277 * SetStreamSource to specify a vertex buffer
5280 return WINED3D_OK;
5283 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5284 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5285 const WineDirect3DVertexStridedData *DrawPrimStrideData)
5287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5289 /* Mark the state dirty until we have nicer tracking
5290 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5291 * that value.
5293 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5294 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5295 This->stateBlock->baseVertexIndex = 0;
5296 This->up_strided = DrawPrimStrideData;
5297 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5298 This->up_strided = NULL;
5299 return WINED3D_OK;
5302 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5303 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5304 const WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, const void *pIndexData,
5305 WINED3DFORMAT IndexDataFormat)
5307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5308 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5310 /* Mark the state dirty until we have nicer tracking
5311 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5312 * that value.
5314 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5315 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5316 This->stateBlock->streamIsUP = TRUE;
5317 This->stateBlock->baseVertexIndex = 0;
5318 This->up_strided = DrawPrimStrideData;
5319 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5320 This->up_strided = NULL;
5321 return WINED3D_OK;
5324 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5325 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5326 * not callable by the app directly no parameter validation checks are needed here.
5328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5329 WINED3DLOCKED_BOX src;
5330 WINED3DLOCKED_BOX dst;
5331 HRESULT hr;
5332 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5334 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5335 * dirtification to improve loading performance.
5337 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5338 if(FAILED(hr)) return hr;
5339 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5340 if(FAILED(hr)) {
5341 IWineD3DVolume_UnlockBox(pSourceVolume);
5342 return hr;
5345 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5347 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5348 if(FAILED(hr)) {
5349 IWineD3DVolume_UnlockBox(pSourceVolume);
5350 } else {
5351 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5353 return hr;
5356 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5357 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5359 HRESULT hr = WINED3D_OK;
5360 WINED3DRESOURCETYPE sourceType;
5361 WINED3DRESOURCETYPE destinationType;
5362 int i ,levels;
5364 /* TODO: think about moving the code into IWineD3DBaseTexture */
5366 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5368 /* verify that the source and destination textures aren't NULL */
5369 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5370 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5371 This, pSourceTexture, pDestinationTexture);
5372 hr = WINED3DERR_INVALIDCALL;
5375 if (pSourceTexture == pDestinationTexture) {
5376 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5377 This, pSourceTexture, pDestinationTexture);
5378 hr = WINED3DERR_INVALIDCALL;
5380 /* Verify that the source and destination textures are the same type */
5381 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5382 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5384 if (sourceType != destinationType) {
5385 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5386 This);
5387 hr = WINED3DERR_INVALIDCALL;
5390 /* check that both textures have the identical numbers of levels */
5391 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5392 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5393 hr = WINED3DERR_INVALIDCALL;
5396 if (WINED3D_OK == hr) {
5398 /* Make sure that the destination texture is loaded */
5399 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5401 /* Update every surface level of the texture */
5402 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5404 switch (sourceType) {
5405 case WINED3DRTYPE_TEXTURE:
5407 IWineD3DSurface *srcSurface;
5408 IWineD3DSurface *destSurface;
5410 for (i = 0 ; i < levels ; ++i) {
5411 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5412 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5413 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5414 IWineD3DSurface_Release(srcSurface);
5415 IWineD3DSurface_Release(destSurface);
5416 if (WINED3D_OK != hr) {
5417 WARN("(%p) : Call to update surface failed\n", This);
5418 return hr;
5422 break;
5423 case WINED3DRTYPE_CUBETEXTURE:
5425 IWineD3DSurface *srcSurface;
5426 IWineD3DSurface *destSurface;
5427 WINED3DCUBEMAP_FACES faceType;
5429 for (i = 0 ; i < levels ; ++i) {
5430 /* Update each cube face */
5431 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5432 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5433 if (WINED3D_OK != hr) {
5434 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5435 } else {
5436 TRACE("Got srcSurface %p\n", srcSurface);
5438 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5439 if (WINED3D_OK != hr) {
5440 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5441 } else {
5442 TRACE("Got desrSurface %p\n", destSurface);
5444 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5445 IWineD3DSurface_Release(srcSurface);
5446 IWineD3DSurface_Release(destSurface);
5447 if (WINED3D_OK != hr) {
5448 WARN("(%p) : Call to update surface failed\n", This);
5449 return hr;
5454 break;
5456 case WINED3DRTYPE_VOLUMETEXTURE:
5458 IWineD3DVolume *srcVolume = NULL;
5459 IWineD3DVolume *destVolume = NULL;
5461 for (i = 0 ; i < levels ; ++i) {
5462 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5463 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5464 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5465 IWineD3DVolume_Release(srcVolume);
5466 IWineD3DVolume_Release(destVolume);
5467 if (WINED3D_OK != hr) {
5468 WARN("(%p) : Call to update volume failed\n", This);
5469 return hr;
5473 break;
5475 default:
5476 FIXME("(%p) : Unsupported source and destination type\n", This);
5477 hr = WINED3DERR_INVALIDCALL;
5481 return hr;
5484 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5485 IWineD3DSwapChain *swapChain;
5486 HRESULT hr;
5487 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5488 if(hr == WINED3D_OK) {
5489 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5490 IWineD3DSwapChain_Release(swapChain);
5492 return hr;
5495 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5497 IWineD3DBaseTextureImpl *texture;
5498 const struct GlPixelFormatDesc *gl_info;
5499 DWORD i;
5501 TRACE("(%p) : %p\n", This, pNumPasses);
5503 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5504 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5505 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5506 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5508 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5509 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5510 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5513 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5514 if(!texture) continue;
5515 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5516 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5518 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5519 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5520 return E_FAIL;
5522 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5523 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5524 return E_FAIL;
5526 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5527 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5528 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5529 return E_FAIL;
5533 /* return a sensible default */
5534 *pNumPasses = 1;
5536 TRACE("returning D3D_OK\n");
5537 return WINED3D_OK;
5540 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5542 int i;
5544 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5545 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5546 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5547 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5552 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5554 int j;
5555 UINT NewSize;
5556 PALETTEENTRY **palettes;
5558 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5560 if (PaletteNumber >= MAX_PALETTES) {
5561 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5562 return WINED3DERR_INVALIDCALL;
5565 if (PaletteNumber >= This->NumberOfPalettes) {
5566 NewSize = This->NumberOfPalettes;
5567 do {
5568 NewSize *= 2;
5569 } while(PaletteNumber >= NewSize);
5570 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5571 if (!palettes) {
5572 ERR("Out of memory!\n");
5573 return E_OUTOFMEMORY;
5575 This->palettes = palettes;
5576 This->NumberOfPalettes = NewSize;
5579 if (!This->palettes[PaletteNumber]) {
5580 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5581 if (!This->palettes[PaletteNumber]) {
5582 ERR("Out of memory!\n");
5583 return E_OUTOFMEMORY;
5587 for (j = 0; j < 256; ++j) {
5588 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5589 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5590 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5591 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5593 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5594 TRACE("(%p) : returning\n", This);
5595 return WINED3D_OK;
5598 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5600 int j;
5601 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5602 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5603 /* What happens in such situation isn't documented; Native seems to silently abort
5604 on such conditions. Return Invalid Call. */
5605 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5606 return WINED3DERR_INVALIDCALL;
5608 for (j = 0; j < 256; ++j) {
5609 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5610 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5611 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5612 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5614 TRACE("(%p) : returning\n", This);
5615 return WINED3D_OK;
5618 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5620 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5621 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5622 (tested with reference rasterizer). Return Invalid Call. */
5623 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5624 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5625 return WINED3DERR_INVALIDCALL;
5627 /*TODO: stateblocks */
5628 if (This->currentPalette != PaletteNumber) {
5629 This->currentPalette = PaletteNumber;
5630 dirtify_p8_texture_samplers(This);
5632 TRACE("(%p) : returning\n", This);
5633 return WINED3D_OK;
5636 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5638 if (PaletteNumber == NULL) {
5639 WARN("(%p) : returning Invalid Call\n", This);
5640 return WINED3DERR_INVALIDCALL;
5642 /*TODO: stateblocks */
5643 *PaletteNumber = This->currentPalette;
5644 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5645 return WINED3D_OK;
5648 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5650 static BOOL warned;
5651 if (!warned)
5653 FIXME("(%p) : stub\n", This);
5654 warned = TRUE;
5657 This->softwareVertexProcessing = bSoftware;
5658 return WINED3D_OK;
5662 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5664 static BOOL warned;
5665 if (!warned)
5667 FIXME("(%p) : stub\n", This);
5668 warned = TRUE;
5670 return This->softwareVertexProcessing;
5674 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5676 IWineD3DSwapChain *swapChain;
5677 HRESULT hr;
5679 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5681 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5682 if(hr == WINED3D_OK){
5683 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5684 IWineD3DSwapChain_Release(swapChain);
5685 }else{
5686 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5688 return hr;
5692 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5694 static BOOL warned;
5695 if(nSegments != 0.0f) {
5696 if (!warned)
5698 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5699 warned = TRUE;
5702 return WINED3D_OK;
5705 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5707 static BOOL warned;
5708 if (!warned)
5710 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5711 warned = TRUE;
5713 return 0.0f;
5716 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5718 /** TODO: remove casts to IWineD3DSurfaceImpl
5719 * NOTE: move code to surface to accomplish this
5720 ****************************************/
5721 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5722 int srcWidth, srcHeight;
5723 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5724 WINED3DFORMAT destFormat, srcFormat;
5725 UINT destSize;
5726 int srcLeft, destLeft, destTop;
5727 WINED3DPOOL srcPool, destPool;
5728 int offset = 0;
5729 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5730 glDescriptor *glDescription = NULL;
5731 GLenum dummy;
5732 int sampler;
5733 int bpp;
5734 CONVERT_TYPES convert = NO_CONVERSION;
5736 WINED3DSURFACE_DESC winedesc;
5738 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5739 memset(&winedesc, 0, sizeof(winedesc));
5740 winedesc.Width = &srcSurfaceWidth;
5741 winedesc.Height = &srcSurfaceHeight;
5742 winedesc.Pool = &srcPool;
5743 winedesc.Format = &srcFormat;
5745 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5747 winedesc.Width = &destSurfaceWidth;
5748 winedesc.Height = &destSurfaceHeight;
5749 winedesc.Pool = &destPool;
5750 winedesc.Format = &destFormat;
5751 winedesc.Size = &destSize;
5753 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5755 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5756 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5757 return WINED3DERR_INVALIDCALL;
5760 /* This call loads the opengl surface directly, instead of copying the surface to the
5761 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5762 * copy in sysmem and use regular surface loading.
5764 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5765 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5766 if(convert != NO_CONVERSION) {
5767 return IWineD3DSurface_BltFast(pDestinationSurface,
5768 pDestPoint ? pDestPoint->x : 0,
5769 pDestPoint ? pDestPoint->y : 0,
5770 pSourceSurface, pSourceRect, 0);
5773 if (destFormat == WINED3DFMT_UNKNOWN) {
5774 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5775 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5777 /* Get the update surface description */
5778 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5781 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5783 ENTER_GL();
5784 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5785 checkGLcall("glActiveTextureARB");
5786 LEAVE_GL();
5788 /* Make sure the surface is loaded and up to date */
5789 IWineD3DSurface_PreLoad(pDestinationSurface);
5790 IWineD3DSurface_BindTexture(pDestinationSurface);
5792 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5794 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5795 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5796 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5797 srcLeft = pSourceRect ? pSourceRect->left : 0;
5798 destLeft = pDestPoint ? pDestPoint->x : 0;
5799 destTop = pDestPoint ? pDestPoint->y : 0;
5802 /* This function doesn't support compressed textures
5803 the pitch is just bytesPerPixel * width */
5804 if(srcWidth != srcSurfaceWidth || srcLeft ){
5805 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5806 offset += srcLeft * pSrcSurface->bytesPerPixel;
5807 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5809 /* TODO DXT formats */
5811 if(pSourceRect != NULL && pSourceRect->top != 0){
5812 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5814 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5815 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat,
5816 glDescription->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5818 /* Sanity check */
5819 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5821 /* need to lock the surface to get the data */
5822 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5825 ENTER_GL();
5827 /* TODO: Cube and volume support */
5828 if(rowoffset != 0){
5829 /* not a whole row so we have to do it a line at a time */
5830 int j;
5832 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5833 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5835 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5837 glTexSubImage2D(glDescription->target
5838 ,glDescription->level
5839 ,destLeft
5841 ,srcWidth
5843 ,glDescription->glFormat
5844 ,glDescription->glType
5845 ,data /* could be quicker using */
5847 data += rowoffset;
5850 } else { /* Full width, so just write out the whole texture */
5851 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5853 if (WINED3DFMT_DXT1 == destFormat ||
5854 WINED3DFMT_DXT2 == destFormat ||
5855 WINED3DFMT_DXT3 == destFormat ||
5856 WINED3DFMT_DXT4 == destFormat ||
5857 WINED3DFMT_DXT5 == destFormat) {
5858 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5859 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5860 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5861 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5862 } if (destFormat != srcFormat) {
5863 FIXME("Updating mixed format compressed texture is not curretly support\n");
5864 } else {
5865 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
5866 glDescription->glFormatInternal, srcWidth, srcHeight, 0, destSize, data));
5868 } else {
5869 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5873 } else {
5874 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
5875 srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, data);
5878 checkGLcall("glTexSubImage2D");
5880 LEAVE_GL();
5882 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5883 sampler = This->rev_tex_unit_map[0];
5884 if (sampler != -1) {
5885 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5888 return WINED3D_OK;
5891 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5893 struct WineD3DRectPatch *patch;
5894 unsigned int i;
5895 struct list *e;
5896 BOOL found;
5897 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5899 if(!(Handle || pRectPatchInfo)) {
5900 /* TODO: Write a test for the return value, thus the FIXME */
5901 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5902 return WINED3DERR_INVALIDCALL;
5905 if(Handle) {
5906 i = PATCHMAP_HASHFUNC(Handle);
5907 found = FALSE;
5908 LIST_FOR_EACH(e, &This->patches[i]) {
5909 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5910 if(patch->Handle == Handle) {
5911 found = TRUE;
5912 break;
5916 if(!found) {
5917 TRACE("Patch does not exist. Creating a new one\n");
5918 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5919 patch->Handle = Handle;
5920 list_add_head(&This->patches[i], &patch->entry);
5921 } else {
5922 TRACE("Found existing patch %p\n", patch);
5924 } else {
5925 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5926 * attributes we have to tesselate, read back, and draw. This needs a patch
5927 * management structure instance. Create one.
5929 * A possible improvement is to check if a vertex shader is used, and if not directly
5930 * draw the patch.
5932 FIXME("Drawing an uncached patch. This is slow\n");
5933 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5936 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5937 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5938 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5939 HRESULT hr;
5940 TRACE("Tesselation density or patch info changed, retesselating\n");
5942 if(pRectPatchInfo) {
5943 patch->RectPatchInfo = *pRectPatchInfo;
5945 patch->numSegs[0] = pNumSegs[0];
5946 patch->numSegs[1] = pNumSegs[1];
5947 patch->numSegs[2] = pNumSegs[2];
5948 patch->numSegs[3] = pNumSegs[3];
5950 hr = tesselate_rectpatch(This, patch);
5951 if(FAILED(hr)) {
5952 WARN("Patch tesselation failed\n");
5954 /* Do not release the handle to store the params of the patch */
5955 if(!Handle) {
5956 HeapFree(GetProcessHeap(), 0, patch);
5958 return hr;
5962 This->currentPatch = patch;
5963 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5964 This->currentPatch = NULL;
5966 /* Destroy uncached patches */
5967 if(!Handle) {
5968 HeapFree(GetProcessHeap(), 0, patch->mem);
5969 HeapFree(GetProcessHeap(), 0, patch);
5971 return WINED3D_OK;
5974 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5976 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5977 FIXME("(%p) : Stub\n", This);
5978 return WINED3D_OK;
5981 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5983 int i;
5984 struct WineD3DRectPatch *patch;
5985 struct list *e;
5986 TRACE("(%p) Handle(%d)\n", This, Handle);
5988 i = PATCHMAP_HASHFUNC(Handle);
5989 LIST_FOR_EACH(e, &This->patches[i]) {
5990 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5991 if(patch->Handle == Handle) {
5992 TRACE("Deleting patch %p\n", patch);
5993 list_remove(&patch->entry);
5994 HeapFree(GetProcessHeap(), 0, patch->mem);
5995 HeapFree(GetProcessHeap(), 0, patch);
5996 return WINED3D_OK;
6000 /* TODO: Write a test for the return value */
6001 FIXME("Attempt to destroy nonexistent patch\n");
6002 return WINED3DERR_INVALIDCALL;
6005 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6006 HRESULT hr;
6007 IWineD3DSwapChain *swapchain;
6009 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6010 if (SUCCEEDED(hr)) {
6011 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6012 return swapchain;
6015 return NULL;
6018 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6020 IWineD3DSwapChain *swapchain;
6022 swapchain = get_swapchain(surface);
6023 if (swapchain) {
6024 GLenum buffer;
6026 TRACE("Surface %p is onscreen\n", surface);
6028 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6029 ENTER_GL();
6030 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6031 buffer = surface_get_gl_buffer(surface, swapchain);
6032 glDrawBuffer(buffer);
6033 checkGLcall("glDrawBuffer()");
6034 } else {
6035 TRACE("Surface %p is offscreen\n", surface);
6037 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6038 ENTER_GL();
6039 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6040 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6041 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6042 checkGLcall("glFramebufferRenderbufferEXT");
6045 if (rect) {
6046 glEnable(GL_SCISSOR_TEST);
6047 if(!swapchain) {
6048 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6049 } else {
6050 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6051 rect->x2 - rect->x1, rect->y2 - rect->y1);
6053 checkGLcall("glScissor");
6054 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6055 } else {
6056 glDisable(GL_SCISSOR_TEST);
6058 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6060 glDisable(GL_BLEND);
6061 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6063 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6064 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6066 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6067 glClear(GL_COLOR_BUFFER_BIT);
6068 checkGLcall("glClear");
6070 if (This->activeContext->current_fbo) {
6071 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6072 } else {
6073 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6074 checkGLcall("glBindFramebuffer()");
6077 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6078 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6079 glDrawBuffer(GL_BACK);
6080 checkGLcall("glDrawBuffer()");
6083 LEAVE_GL();
6086 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6087 unsigned int r, g, b, a;
6088 DWORD ret;
6090 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6091 destfmt == WINED3DFMT_R8G8B8)
6092 return color;
6094 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6096 a = (color & 0xff000000) >> 24;
6097 r = (color & 0x00ff0000) >> 16;
6098 g = (color & 0x0000ff00) >> 8;
6099 b = (color & 0x000000ff) >> 0;
6101 switch(destfmt)
6103 case WINED3DFMT_R5G6B5:
6104 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6105 r = (r * 32) / 256;
6106 g = (g * 64) / 256;
6107 b = (b * 32) / 256;
6108 ret = r << 11;
6109 ret |= g << 5;
6110 ret |= b;
6111 TRACE("Returning %08x\n", ret);
6112 return ret;
6114 case WINED3DFMT_X1R5G5B5:
6115 case WINED3DFMT_A1R5G5B5:
6116 a = (a * 2) / 256;
6117 r = (r * 32) / 256;
6118 g = (g * 32) / 256;
6119 b = (b * 32) / 256;
6120 ret = a << 15;
6121 ret |= r << 10;
6122 ret |= g << 5;
6123 ret |= b << 0;
6124 TRACE("Returning %08x\n", ret);
6125 return ret;
6127 case WINED3DFMT_A8:
6128 TRACE("Returning %08x\n", a);
6129 return a;
6131 case WINED3DFMT_X4R4G4B4:
6132 case WINED3DFMT_A4R4G4B4:
6133 a = (a * 16) / 256;
6134 r = (r * 16) / 256;
6135 g = (g * 16) / 256;
6136 b = (b * 16) / 256;
6137 ret = a << 12;
6138 ret |= r << 8;
6139 ret |= g << 4;
6140 ret |= b << 0;
6141 TRACE("Returning %08x\n", ret);
6142 return ret;
6144 case WINED3DFMT_R3G3B2:
6145 r = (r * 8) / 256;
6146 g = (g * 8) / 256;
6147 b = (b * 4) / 256;
6148 ret = r << 5;
6149 ret |= g << 2;
6150 ret |= b << 0;
6151 TRACE("Returning %08x\n", ret);
6152 return ret;
6154 case WINED3DFMT_X8B8G8R8:
6155 case WINED3DFMT_A8B8G8R8:
6156 ret = a << 24;
6157 ret |= b << 16;
6158 ret |= g << 8;
6159 ret |= r << 0;
6160 TRACE("Returning %08x\n", ret);
6161 return ret;
6163 case WINED3DFMT_A2R10G10B10:
6164 a = (a * 4) / 256;
6165 r = (r * 1024) / 256;
6166 g = (g * 1024) / 256;
6167 b = (b * 1024) / 256;
6168 ret = a << 30;
6169 ret |= r << 20;
6170 ret |= g << 10;
6171 ret |= b << 0;
6172 TRACE("Returning %08x\n", ret);
6173 return ret;
6175 case WINED3DFMT_A2B10G10R10:
6176 a = (a * 4) / 256;
6177 r = (r * 1024) / 256;
6178 g = (g * 1024) / 256;
6179 b = (b * 1024) / 256;
6180 ret = a << 30;
6181 ret |= b << 20;
6182 ret |= g << 10;
6183 ret |= r << 0;
6184 TRACE("Returning %08x\n", ret);
6185 return ret;
6187 default:
6188 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6189 return 0;
6193 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6195 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6196 WINEDDBLTFX BltFx;
6197 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6199 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6200 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6201 return WINED3DERR_INVALIDCALL;
6204 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6205 color_fill_fbo(iface, pSurface, pRect, color);
6206 return WINED3D_OK;
6207 } else {
6208 /* Just forward this to the DirectDraw blitting engine */
6209 memset(&BltFx, 0, sizeof(BltFx));
6210 BltFx.dwSize = sizeof(BltFx);
6211 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6212 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6213 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6217 /* rendertarget and depth stencil functions */
6218 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6219 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6221 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6222 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6223 return WINED3DERR_INVALIDCALL;
6226 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6227 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6228 /* Note inc ref on returned surface */
6229 if(*ppRenderTarget != NULL)
6230 IWineD3DSurface_AddRef(*ppRenderTarget);
6231 return WINED3D_OK;
6234 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6236 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6237 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6238 IWineD3DSwapChainImpl *Swapchain;
6239 HRESULT hr;
6241 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6243 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6244 if(hr != WINED3D_OK) {
6245 ERR("Can't get the swapchain\n");
6246 return hr;
6249 /* Make sure to release the swapchain */
6250 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6252 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6253 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6254 return WINED3DERR_INVALIDCALL;
6256 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6257 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6258 return WINED3DERR_INVALIDCALL;
6261 if(Swapchain->frontBuffer != Front) {
6262 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6264 if(Swapchain->frontBuffer)
6265 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6266 Swapchain->frontBuffer = Front;
6268 if(Swapchain->frontBuffer) {
6269 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6273 if(Back && !Swapchain->backBuffer) {
6274 /* We need memory for the back buffer array - only one back buffer this way */
6275 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6276 if(!Swapchain->backBuffer) {
6277 ERR("Out of memory\n");
6278 return E_OUTOFMEMORY;
6282 if(Swapchain->backBuffer[0] != Back) {
6283 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6285 /* What to do about the context here in the case of multithreading? Not sure.
6286 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6288 ENTER_GL();
6289 if(!Swapchain->backBuffer[0]) {
6290 /* GL was told to draw to the front buffer at creation,
6291 * undo that
6293 glDrawBuffer(GL_BACK);
6294 checkGLcall("glDrawBuffer(GL_BACK)");
6295 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6296 Swapchain->presentParms.BackBufferCount = 1;
6297 } else if (!Back) {
6298 /* That makes problems - disable for now */
6299 /* glDrawBuffer(GL_FRONT); */
6300 checkGLcall("glDrawBuffer(GL_FRONT)");
6301 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6302 Swapchain->presentParms.BackBufferCount = 0;
6304 LEAVE_GL();
6306 if(Swapchain->backBuffer[0])
6307 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6308 Swapchain->backBuffer[0] = Back;
6310 if(Swapchain->backBuffer[0]) {
6311 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6312 } else {
6313 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6314 Swapchain->backBuffer = NULL;
6319 return WINED3D_OK;
6322 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6324 *ppZStencilSurface = This->stencilBufferTarget;
6325 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6327 if(*ppZStencilSurface != NULL) {
6328 /* Note inc ref on returned surface */
6329 IWineD3DSurface_AddRef(*ppZStencilSurface);
6330 return WINED3D_OK;
6331 } else {
6332 return WINED3DERR_NOTFOUND;
6336 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6337 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6340 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6341 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6342 GLenum gl_filter;
6343 POINT offset = {0, 0};
6345 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6346 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6347 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6348 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6350 switch (filter) {
6351 case WINED3DTEXF_LINEAR:
6352 gl_filter = GL_LINEAR;
6353 break;
6355 default:
6356 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6357 case WINED3DTEXF_NONE:
6358 case WINED3DTEXF_POINT:
6359 gl_filter = GL_NEAREST;
6360 break;
6363 /* Attach src surface to src fbo */
6364 src_swapchain = get_swapchain(src_surface);
6365 if (src_swapchain) {
6366 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6368 TRACE("Source surface %p is onscreen\n", src_surface);
6369 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6370 /* Make sure the drawable is up to date. In the offscreen case
6371 * attach_surface_fbo() implicitly takes care of this. */
6372 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6374 if(buffer == GL_FRONT) {
6375 RECT windowsize;
6376 UINT h;
6377 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6378 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6379 h = windowsize.bottom - windowsize.top;
6380 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6381 src_rect->y1 = offset.y + h - src_rect->y1;
6382 src_rect->y2 = offset.y + h - src_rect->y2;
6383 } else {
6384 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6385 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6388 ENTER_GL();
6389 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6390 glReadBuffer(buffer);
6391 checkGLcall("glReadBuffer()");
6392 } else {
6393 TRACE("Source surface %p is offscreen\n", src_surface);
6394 ENTER_GL();
6395 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6396 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6397 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6398 checkGLcall("glReadBuffer()");
6399 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6400 checkGLcall("glFramebufferRenderbufferEXT");
6402 LEAVE_GL();
6404 /* Attach dst surface to dst fbo */
6405 dst_swapchain = get_swapchain(dst_surface);
6406 if (dst_swapchain) {
6407 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6409 TRACE("Destination surface %p is onscreen\n", dst_surface);
6410 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6411 /* Make sure the drawable is up to date. In the offscreen case
6412 * attach_surface_fbo() implicitly takes care of this. */
6413 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6415 if(buffer == GL_FRONT) {
6416 RECT windowsize;
6417 UINT h;
6418 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6419 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6420 h = windowsize.bottom - windowsize.top;
6421 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6422 dst_rect->y1 = offset.y + h - dst_rect->y1;
6423 dst_rect->y2 = offset.y + h - dst_rect->y2;
6424 } else {
6425 /* Screen coords = window coords, surface height = window height */
6426 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6427 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6430 ENTER_GL();
6431 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6432 glDrawBuffer(buffer);
6433 checkGLcall("glDrawBuffer()");
6434 } else {
6435 TRACE("Destination surface %p is offscreen\n", dst_surface);
6437 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6438 if(!src_swapchain) {
6439 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6442 ENTER_GL();
6443 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6444 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6445 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6446 checkGLcall("glDrawBuffer()");
6447 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6448 checkGLcall("glFramebufferRenderbufferEXT");
6450 glDisable(GL_SCISSOR_TEST);
6451 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6453 if (flip) {
6454 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6455 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6456 checkGLcall("glBlitFramebuffer()");
6457 } else {
6458 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6459 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6460 checkGLcall("glBlitFramebuffer()");
6463 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6465 if (This->activeContext->current_fbo) {
6466 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6467 } else {
6468 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6469 checkGLcall("glBindFramebuffer()");
6472 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6473 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6474 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6475 glDrawBuffer(GL_BACK);
6476 checkGLcall("glDrawBuffer()");
6478 LEAVE_GL();
6481 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6483 WINED3DVIEWPORT viewport;
6485 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6487 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6488 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6489 This, RenderTargetIndex, GL_LIMITS(buffers));
6490 return WINED3DERR_INVALIDCALL;
6493 /* MSDN says that null disables the render target
6494 but a device must always be associated with a render target
6495 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6497 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6498 FIXME("Trying to set render target 0 to NULL\n");
6499 return WINED3DERR_INVALIDCALL;
6501 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6502 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);
6503 return WINED3DERR_INVALIDCALL;
6506 /* If we are trying to set what we already have, don't bother */
6507 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6508 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6509 return WINED3D_OK;
6511 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6512 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6513 This->render_targets[RenderTargetIndex] = pRenderTarget;
6515 /* Render target 0 is special */
6516 if(RenderTargetIndex == 0) {
6517 /* Finally, reset the viewport as the MSDN states. */
6518 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6519 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6520 viewport.X = 0;
6521 viewport.Y = 0;
6522 viewport.MaxZ = 1.0f;
6523 viewport.MinZ = 0.0f;
6524 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6525 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6526 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6528 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6530 return WINED3D_OK;
6533 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6535 HRESULT hr = WINED3D_OK;
6536 IWineD3DSurface *tmp;
6538 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6540 if (pNewZStencil == This->stencilBufferTarget) {
6541 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6542 } else {
6543 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6544 * depending on the renter target implementation being used.
6545 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6546 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6547 * stencil buffer and incur an extra memory overhead
6548 ******************************************************/
6550 if (This->stencilBufferTarget) {
6551 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6552 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6553 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6554 } else {
6555 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6556 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6557 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6561 tmp = This->stencilBufferTarget;
6562 This->stencilBufferTarget = pNewZStencil;
6563 /* should we be calling the parent or the wined3d surface? */
6564 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6565 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6566 hr = WINED3D_OK;
6568 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6569 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6570 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6571 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6572 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6576 return hr;
6579 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6580 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6582 /* TODO: the use of Impl is deprecated. */
6583 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6584 WINED3DLOCKED_RECT lockedRect;
6586 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6588 /* some basic validation checks */
6589 if(This->cursorTexture) {
6590 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6591 ENTER_GL();
6592 glDeleteTextures(1, &This->cursorTexture);
6593 LEAVE_GL();
6594 This->cursorTexture = 0;
6597 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6598 This->haveHardwareCursor = TRUE;
6599 else
6600 This->haveHardwareCursor = FALSE;
6602 if(pCursorBitmap) {
6603 WINED3DLOCKED_RECT rect;
6605 /* MSDN: Cursor must be A8R8G8B8 */
6606 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6607 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6608 return WINED3DERR_INVALIDCALL;
6611 /* MSDN: Cursor must be smaller than the display mode */
6612 if(pSur->currentDesc.Width > This->ddraw_width ||
6613 pSur->currentDesc.Height > This->ddraw_height) {
6614 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);
6615 return WINED3DERR_INVALIDCALL;
6618 if (!This->haveHardwareCursor) {
6619 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6621 /* Do not store the surface's pointer because the application may
6622 * release it after setting the cursor image. Windows doesn't
6623 * addref the set surface, so we can't do this either without
6624 * creating circular refcount dependencies. Copy out the gl texture
6625 * instead.
6627 This->cursorWidth = pSur->currentDesc.Width;
6628 This->cursorHeight = pSur->currentDesc.Height;
6629 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6631 const struct GlPixelFormatDesc *glDesc;
6632 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6633 char *mem, *bits = (char *)rect.pBits;
6634 GLint intfmt = glDesc->glInternal;
6635 GLint format = glDesc->glFormat;
6636 GLint type = glDesc->glType;
6637 INT height = This->cursorHeight;
6638 INT width = This->cursorWidth;
6639 INT bpp = tableEntry->bpp;
6640 INT i, sampler;
6642 /* Reformat the texture memory (pitch and width can be
6643 * different) */
6644 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6645 for(i = 0; i < height; i++)
6646 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6647 IWineD3DSurface_UnlockRect(pCursorBitmap);
6648 ENTER_GL();
6650 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6651 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6652 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6655 /* Make sure that a proper texture unit is selected */
6656 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6657 checkGLcall("glActiveTextureARB");
6658 sampler = This->rev_tex_unit_map[0];
6659 if (sampler != -1) {
6660 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6662 /* Create a new cursor texture */
6663 glGenTextures(1, &This->cursorTexture);
6664 checkGLcall("glGenTextures");
6665 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6666 checkGLcall("glBindTexture");
6667 /* Copy the bitmap memory into the cursor texture */
6668 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6669 HeapFree(GetProcessHeap(), 0, mem);
6670 checkGLcall("glTexImage2D");
6672 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6673 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6674 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6677 LEAVE_GL();
6679 else
6681 FIXME("A cursor texture was not returned.\n");
6682 This->cursorTexture = 0;
6685 else
6687 /* Draw a hardware cursor */
6688 ICONINFO cursorInfo;
6689 HCURSOR cursor;
6690 /* Create and clear maskBits because it is not needed for
6691 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6692 * chunks. */
6693 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6694 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6695 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6696 WINED3DLOCK_NO_DIRTY_UPDATE |
6697 WINED3DLOCK_READONLY
6699 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6700 pSur->currentDesc.Height);
6702 cursorInfo.fIcon = FALSE;
6703 cursorInfo.xHotspot = XHotSpot;
6704 cursorInfo.yHotspot = YHotSpot;
6705 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6706 pSur->currentDesc.Height, 1,
6707 1, &maskBits);
6708 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6709 pSur->currentDesc.Height, 1,
6710 32, lockedRect.pBits);
6711 IWineD3DSurface_UnlockRect(pCursorBitmap);
6712 /* Create our cursor and clean up. */
6713 cursor = CreateIconIndirect(&cursorInfo);
6714 SetCursor(cursor);
6715 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6716 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6717 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6718 This->hardwareCursor = cursor;
6719 HeapFree(GetProcessHeap(), 0, maskBits);
6723 This->xHotSpot = XHotSpot;
6724 This->yHotSpot = YHotSpot;
6725 return WINED3D_OK;
6728 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6730 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6732 This->xScreenSpace = XScreenSpace;
6733 This->yScreenSpace = YScreenSpace;
6735 return;
6739 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6741 BOOL oldVisible = This->bCursorVisible;
6742 POINT pt;
6744 TRACE("(%p) : visible(%d)\n", This, bShow);
6747 * When ShowCursor is first called it should make the cursor appear at the OS's last
6748 * known cursor position. Because of this, some applications just repetitively call
6749 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6751 GetCursorPos(&pt);
6752 This->xScreenSpace = pt.x;
6753 This->yScreenSpace = pt.y;
6755 if (This->haveHardwareCursor) {
6756 This->bCursorVisible = bShow;
6757 if (bShow)
6758 SetCursor(This->hardwareCursor);
6759 else
6760 SetCursor(NULL);
6762 else
6764 if (This->cursorTexture)
6765 This->bCursorVisible = bShow;
6768 return oldVisible;
6771 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6773 IWineD3DResourceImpl *resource;
6774 TRACE("(%p) : state (%u)\n", This, This->state);
6776 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6777 switch (This->state) {
6778 case WINED3D_OK:
6779 return WINED3D_OK;
6780 case WINED3DERR_DEVICELOST:
6782 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6783 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6784 return WINED3DERR_DEVICENOTRESET;
6786 return WINED3DERR_DEVICELOST;
6788 case WINED3DERR_DRIVERINTERNALERROR:
6789 return WINED3DERR_DRIVERINTERNALERROR;
6792 /* Unknown state */
6793 return WINED3DERR_DRIVERINTERNALERROR;
6797 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6799 /** FIXME: Resource tracking needs to be done,
6800 * The closes we can do to this is set the priorities of all managed textures low
6801 * and then reset them.
6802 ***********************************************************/
6803 FIXME("(%p) : stub\n", This);
6804 return WINED3D_OK;
6807 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6809 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6811 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6812 if(surface->Flags & SFLAG_DIBSECTION) {
6813 /* Release the DC */
6814 SelectObject(surface->hDC, surface->dib.holdbitmap);
6815 DeleteDC(surface->hDC);
6816 /* Release the DIB section */
6817 DeleteObject(surface->dib.DIBsection);
6818 surface->dib.bitmap_data = NULL;
6819 surface->resource.allocatedMemory = NULL;
6820 surface->Flags &= ~SFLAG_DIBSECTION;
6822 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6823 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6824 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6825 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6826 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6827 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6828 } else {
6829 surface->pow2Width = surface->pow2Height = 1;
6830 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6831 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6833 surface->glRect.left = 0;
6834 surface->glRect.top = 0;
6835 surface->glRect.right = surface->pow2Width;
6836 surface->glRect.bottom = surface->pow2Height;
6838 if(surface->glDescription.textureName) {
6839 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6840 ENTER_GL();
6841 glDeleteTextures(1, &surface->glDescription.textureName);
6842 LEAVE_GL();
6843 surface->glDescription.textureName = 0;
6844 surface->Flags &= ~SFLAG_CLIENT;
6846 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6847 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6848 surface->Flags |= SFLAG_NONPOW2;
6849 } else {
6850 surface->Flags &= ~SFLAG_NONPOW2;
6852 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6853 surface->resource.allocatedMemory = NULL;
6854 surface->resource.heapMemory = NULL;
6855 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6856 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6857 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6858 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6859 } else {
6860 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6864 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6865 TRACE("Unloading resource %p\n", resource);
6866 IWineD3DResource_UnLoad(resource);
6867 IWineD3DResource_Release(resource);
6868 return S_OK;
6871 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6873 UINT i, count;
6874 WINED3DDISPLAYMODE m;
6875 HRESULT hr;
6877 /* All Windowed modes are supported, as is leaving the current mode */
6878 if(pp->Windowed) return TRUE;
6879 if(!pp->BackBufferWidth) return TRUE;
6880 if(!pp->BackBufferHeight) return TRUE;
6882 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6883 for(i = 0; i < count; i++) {
6884 memset(&m, 0, sizeof(m));
6885 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6886 if(FAILED(hr)) {
6887 ERR("EnumAdapterModes failed\n");
6889 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6890 /* Mode found, it is supported */
6891 return TRUE;
6894 /* Mode not found -> not supported */
6895 return FALSE;
6898 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6900 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6901 UINT i;
6902 IWineD3DBaseShaderImpl *shader;
6904 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6905 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6906 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6909 ENTER_GL();
6910 if(This->depth_blt_texture) {
6911 glDeleteTextures(1, &This->depth_blt_texture);
6912 This->depth_blt_texture = 0;
6914 if (This->depth_blt_rb) {
6915 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
6916 This->depth_blt_rb = 0;
6917 This->depth_blt_rb_w = 0;
6918 This->depth_blt_rb_h = 0;
6920 LEAVE_GL();
6922 This->blitter->free_private(iface);
6923 This->frag_pipe->free_private(iface);
6924 This->shader_backend->shader_free_private(iface);
6926 ENTER_GL();
6927 for (i = 0; i < GL_LIMITS(textures); i++) {
6928 /* Textures are recreated below */
6929 glDeleteTextures(1, &This->dummyTextureName[i]);
6930 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6931 This->dummyTextureName[i] = 0;
6933 LEAVE_GL();
6935 while(This->numContexts) {
6936 DestroyContext(This, This->contexts[0]);
6938 This->activeContext = NULL;
6939 HeapFree(GetProcessHeap(), 0, swapchain->context);
6940 swapchain->context = NULL;
6941 swapchain->num_contexts = 0;
6944 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6946 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6947 HRESULT hr;
6948 IWineD3DSurfaceImpl *target;
6950 /* Recreate the primary swapchain's context */
6951 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6952 if(swapchain->backBuffer) {
6953 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6954 } else {
6955 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6957 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
6958 &swapchain->presentParms);
6959 swapchain->num_contexts = 1;
6960 This->activeContext = swapchain->context[0];
6962 create_dummy_textures(This);
6964 hr = This->shader_backend->shader_alloc_private(iface);
6965 if(FAILED(hr)) {
6966 ERR("Failed to recreate shader private data\n");
6967 goto err_out;
6969 hr = This->frag_pipe->alloc_private(iface);
6970 if(FAILED(hr)) {
6971 TRACE("Fragment pipeline private data couldn't be allocated\n");
6972 goto err_out;
6974 hr = This->blitter->alloc_private(iface);
6975 if(FAILED(hr)) {
6976 TRACE("Blitter private data couldn't be allocated\n");
6977 goto err_out;
6980 return WINED3D_OK;
6982 err_out:
6983 This->blitter->free_private(iface);
6984 This->frag_pipe->free_private(iface);
6985 This->shader_backend->shader_free_private(iface);
6986 return hr;
6989 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6991 IWineD3DSwapChainImpl *swapchain;
6992 HRESULT hr;
6993 BOOL DisplayModeChanged = FALSE;
6994 WINED3DDISPLAYMODE mode;
6995 TRACE("(%p)\n", This);
6997 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6998 if(FAILED(hr)) {
6999 ERR("Failed to get the first implicit swapchain\n");
7000 return hr;
7003 if(!is_display_mode_supported(This, pPresentationParameters)) {
7004 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7005 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7006 pPresentationParameters->BackBufferHeight);
7007 return WINED3DERR_INVALIDCALL;
7010 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7011 * on an existing gl context, so there's no real need for recreation.
7013 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7015 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7017 TRACE("New params:\n");
7018 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7019 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7020 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7021 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7022 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7023 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7024 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7025 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7026 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7027 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7028 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7029 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7030 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7032 /* No special treatment of these parameters. Just store them */
7033 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7034 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7035 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7036 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7038 /* What to do about these? */
7039 if(pPresentationParameters->BackBufferCount != 0 &&
7040 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7041 ERR("Cannot change the back buffer count yet\n");
7043 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7044 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7045 ERR("Cannot change the back buffer format yet\n");
7047 if(pPresentationParameters->hDeviceWindow != NULL &&
7048 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7049 ERR("Cannot change the device window yet\n");
7051 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7052 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7053 return WINED3DERR_INVALIDCALL;
7056 /* Reset the depth stencil */
7057 if (pPresentationParameters->EnableAutoDepthStencil)
7058 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7059 else
7060 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7062 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7064 if(pPresentationParameters->Windowed) {
7065 mode.Width = swapchain->orig_width;
7066 mode.Height = swapchain->orig_height;
7067 mode.RefreshRate = 0;
7068 mode.Format = swapchain->presentParms.BackBufferFormat;
7069 } else {
7070 mode.Width = pPresentationParameters->BackBufferWidth;
7071 mode.Height = pPresentationParameters->BackBufferHeight;
7072 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7073 mode.Format = swapchain->presentParms.BackBufferFormat;
7076 /* Should Width == 800 && Height == 0 set 800x600? */
7077 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7078 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7079 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7081 UINT i;
7083 if(!pPresentationParameters->Windowed) {
7084 DisplayModeChanged = TRUE;
7086 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7087 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7089 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7090 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7091 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7093 if(This->auto_depth_stencil_buffer) {
7094 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7098 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7099 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7100 DisplayModeChanged) {
7102 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7104 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7105 if(swapchain->presentParms.Windowed) {
7106 /* switch from windowed to fs */
7107 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7108 pPresentationParameters->BackBufferWidth,
7109 pPresentationParameters->BackBufferHeight);
7110 } else {
7111 /* Fullscreen -> fullscreen mode change */
7112 MoveWindow(swapchain->win_handle, 0, 0,
7113 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7114 TRUE);
7116 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7117 /* Fullscreen -> windowed switch */
7118 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7120 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7121 } else if(!pPresentationParameters->Windowed) {
7122 DWORD style = This->style, exStyle = This->exStyle;
7123 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7124 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7125 * Reset to clear up their mess. Guild Wars also loses the device during that.
7127 This->style = 0;
7128 This->exStyle = 0;
7129 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7130 pPresentationParameters->BackBufferWidth,
7131 pPresentationParameters->BackBufferHeight);
7132 This->style = style;
7133 This->exStyle = exStyle;
7136 TRACE("Resetting stateblock\n");
7137 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7138 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7140 /* Note: No parent needed for initial internal stateblock */
7141 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7142 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7143 else TRACE("Created stateblock %p\n", This->stateBlock);
7144 This->updateStateBlock = This->stateBlock;
7145 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7147 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7148 if(FAILED(hr)) {
7149 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7152 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7153 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7155 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7156 * first use
7158 return hr;
7161 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7163 /** FIXME: always true at the moment **/
7164 if(!bEnableDialogs) {
7165 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7167 return WINED3D_OK;
7171 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7173 TRACE("(%p) : pParameters %p\n", This, pParameters);
7175 *pParameters = This->createParms;
7176 return WINED3D_OK;
7179 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7180 IWineD3DSwapChain *swapchain;
7182 TRACE("Relaying to swapchain\n");
7184 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7185 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7186 IWineD3DSwapChain_Release(swapchain);
7188 return;
7191 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7192 IWineD3DSwapChain *swapchain;
7194 TRACE("Relaying to swapchain\n");
7196 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7197 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7198 IWineD3DSwapChain_Release(swapchain);
7200 return;
7204 /** ********************************************************
7205 * Notification functions
7206 ** ********************************************************/
7207 /** This function must be called in the release of a resource when ref == 0,
7208 * the contents of resource must still be correct,
7209 * any handles to other resource held by the caller must be closed
7210 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7211 *****************************************************/
7212 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7215 TRACE("(%p) : Adding Resource %p\n", This, resource);
7216 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7219 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7222 TRACE("(%p) : Removing resource %p\n", This, resource);
7224 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7228 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7230 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7231 int counter;
7233 TRACE("(%p) : resource %p\n", This, resource);
7235 context_resource_released(iface, resource, type);
7237 switch (type) {
7238 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7239 case WINED3DRTYPE_SURFACE: {
7240 unsigned int i;
7242 /* Cleanup any FBO attachments if d3d is enabled */
7243 if(This->d3d_initialized) {
7244 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7245 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7247 TRACE("Last active render target destroyed\n");
7248 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7249 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7250 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7251 * and the lastActiveRenderTarget member shouldn't matter
7253 if(swapchain) {
7254 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7255 TRACE("Activating primary back buffer\n");
7256 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7257 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7258 /* Single buffering environment */
7259 TRACE("Activating primary front buffer\n");
7260 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7261 } else {
7262 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7263 /* Implicit render target destroyed, that means the device is being destroyed
7264 * whatever we set here, it shouldn't matter
7266 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7268 } else {
7269 /* May happen during ddraw uninitialization */
7270 TRACE("Render target set, but swapchain does not exist!\n");
7271 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7275 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7276 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7277 This->render_targets[i] = NULL;
7280 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7281 This->stencilBufferTarget = NULL;
7285 break;
7287 case WINED3DRTYPE_TEXTURE:
7288 case WINED3DRTYPE_CUBETEXTURE:
7289 case WINED3DRTYPE_VOLUMETEXTURE:
7290 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7291 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7292 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7293 This->stateBlock->textures[counter] = NULL;
7295 if (This->updateStateBlock != This->stateBlock ){
7296 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7297 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7298 This->updateStateBlock->textures[counter] = NULL;
7302 break;
7303 case WINED3DRTYPE_VOLUME:
7304 /* TODO: nothing really? */
7305 break;
7306 case WINED3DRTYPE_VERTEXBUFFER:
7307 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7309 int streamNumber;
7310 TRACE("Cleaning up stream pointers\n");
7312 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7313 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7314 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7316 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7317 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7318 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7319 This->updateStateBlock->streamSource[streamNumber] = 0;
7320 /* Set changed flag? */
7323 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) */
7324 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7325 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7326 This->stateBlock->streamSource[streamNumber] = 0;
7331 break;
7332 case WINED3DRTYPE_INDEXBUFFER:
7333 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7334 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7335 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7336 This->updateStateBlock->pIndexData = NULL;
7339 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7340 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7341 This->stateBlock->pIndexData = NULL;
7345 break;
7346 default:
7347 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7348 break;
7352 /* Remove the resource from the resourceStore */
7353 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7355 TRACE("Resource released\n");
7359 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7361 IWineD3DResourceImpl *resource, *cursor;
7362 HRESULT ret;
7363 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7365 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7366 TRACE("enumerating resource %p\n", resource);
7367 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7368 ret = pCallback((IWineD3DResource *) resource, pData);
7369 if(ret == S_FALSE) {
7370 TRACE("Canceling enumeration\n");
7371 break;
7374 return WINED3D_OK;
7377 /**********************************************************
7378 * IWineD3DDevice VTbl follows
7379 **********************************************************/
7381 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7383 /*** IUnknown methods ***/
7384 IWineD3DDeviceImpl_QueryInterface,
7385 IWineD3DDeviceImpl_AddRef,
7386 IWineD3DDeviceImpl_Release,
7387 /*** IWineD3DDevice methods ***/
7388 IWineD3DDeviceImpl_GetParent,
7389 /*** Creation methods**/
7390 IWineD3DDeviceImpl_CreateVertexBuffer,
7391 IWineD3DDeviceImpl_CreateIndexBuffer,
7392 IWineD3DDeviceImpl_CreateStateBlock,
7393 IWineD3DDeviceImpl_CreateSurface,
7394 IWineD3DDeviceImpl_CreateTexture,
7395 IWineD3DDeviceImpl_CreateVolumeTexture,
7396 IWineD3DDeviceImpl_CreateVolume,
7397 IWineD3DDeviceImpl_CreateCubeTexture,
7398 IWineD3DDeviceImpl_CreateQuery,
7399 IWineD3DDeviceImpl_CreateSwapChain,
7400 IWineD3DDeviceImpl_CreateVertexDeclaration,
7401 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7402 IWineD3DDeviceImpl_CreateVertexShader,
7403 IWineD3DDeviceImpl_CreatePixelShader,
7404 IWineD3DDeviceImpl_CreatePalette,
7405 /*** Odd functions **/
7406 IWineD3DDeviceImpl_Init3D,
7407 IWineD3DDeviceImpl_InitGDI,
7408 IWineD3DDeviceImpl_Uninit3D,
7409 IWineD3DDeviceImpl_UninitGDI,
7410 IWineD3DDeviceImpl_SetMultithreaded,
7411 IWineD3DDeviceImpl_EvictManagedResources,
7412 IWineD3DDeviceImpl_GetAvailableTextureMem,
7413 IWineD3DDeviceImpl_GetBackBuffer,
7414 IWineD3DDeviceImpl_GetCreationParameters,
7415 IWineD3DDeviceImpl_GetDeviceCaps,
7416 IWineD3DDeviceImpl_GetDirect3D,
7417 IWineD3DDeviceImpl_GetDisplayMode,
7418 IWineD3DDeviceImpl_SetDisplayMode,
7419 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7420 IWineD3DDeviceImpl_GetRasterStatus,
7421 IWineD3DDeviceImpl_GetSwapChain,
7422 IWineD3DDeviceImpl_Reset,
7423 IWineD3DDeviceImpl_SetDialogBoxMode,
7424 IWineD3DDeviceImpl_SetCursorProperties,
7425 IWineD3DDeviceImpl_SetCursorPosition,
7426 IWineD3DDeviceImpl_ShowCursor,
7427 IWineD3DDeviceImpl_TestCooperativeLevel,
7428 /*** Getters and setters **/
7429 IWineD3DDeviceImpl_SetClipPlane,
7430 IWineD3DDeviceImpl_GetClipPlane,
7431 IWineD3DDeviceImpl_SetClipStatus,
7432 IWineD3DDeviceImpl_GetClipStatus,
7433 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7434 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7435 IWineD3DDeviceImpl_SetDepthStencilSurface,
7436 IWineD3DDeviceImpl_GetDepthStencilSurface,
7437 IWineD3DDeviceImpl_SetGammaRamp,
7438 IWineD3DDeviceImpl_GetGammaRamp,
7439 IWineD3DDeviceImpl_SetIndices,
7440 IWineD3DDeviceImpl_GetIndices,
7441 IWineD3DDeviceImpl_SetBaseVertexIndex,
7442 IWineD3DDeviceImpl_GetBaseVertexIndex,
7443 IWineD3DDeviceImpl_SetLight,
7444 IWineD3DDeviceImpl_GetLight,
7445 IWineD3DDeviceImpl_SetLightEnable,
7446 IWineD3DDeviceImpl_GetLightEnable,
7447 IWineD3DDeviceImpl_SetMaterial,
7448 IWineD3DDeviceImpl_GetMaterial,
7449 IWineD3DDeviceImpl_SetNPatchMode,
7450 IWineD3DDeviceImpl_GetNPatchMode,
7451 IWineD3DDeviceImpl_SetPaletteEntries,
7452 IWineD3DDeviceImpl_GetPaletteEntries,
7453 IWineD3DDeviceImpl_SetPixelShader,
7454 IWineD3DDeviceImpl_GetPixelShader,
7455 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7456 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7457 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7458 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7459 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7460 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7461 IWineD3DDeviceImpl_SetRenderState,
7462 IWineD3DDeviceImpl_GetRenderState,
7463 IWineD3DDeviceImpl_SetRenderTarget,
7464 IWineD3DDeviceImpl_GetRenderTarget,
7465 IWineD3DDeviceImpl_SetFrontBackBuffers,
7466 IWineD3DDeviceImpl_SetSamplerState,
7467 IWineD3DDeviceImpl_GetSamplerState,
7468 IWineD3DDeviceImpl_SetScissorRect,
7469 IWineD3DDeviceImpl_GetScissorRect,
7470 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7471 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7472 IWineD3DDeviceImpl_SetStreamSource,
7473 IWineD3DDeviceImpl_GetStreamSource,
7474 IWineD3DDeviceImpl_SetStreamSourceFreq,
7475 IWineD3DDeviceImpl_GetStreamSourceFreq,
7476 IWineD3DDeviceImpl_SetTexture,
7477 IWineD3DDeviceImpl_GetTexture,
7478 IWineD3DDeviceImpl_SetTextureStageState,
7479 IWineD3DDeviceImpl_GetTextureStageState,
7480 IWineD3DDeviceImpl_SetTransform,
7481 IWineD3DDeviceImpl_GetTransform,
7482 IWineD3DDeviceImpl_SetVertexDeclaration,
7483 IWineD3DDeviceImpl_GetVertexDeclaration,
7484 IWineD3DDeviceImpl_SetVertexShader,
7485 IWineD3DDeviceImpl_GetVertexShader,
7486 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7487 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7488 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7489 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7490 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7491 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7492 IWineD3DDeviceImpl_SetViewport,
7493 IWineD3DDeviceImpl_GetViewport,
7494 IWineD3DDeviceImpl_MultiplyTransform,
7495 IWineD3DDeviceImpl_ValidateDevice,
7496 IWineD3DDeviceImpl_ProcessVertices,
7497 /*** State block ***/
7498 IWineD3DDeviceImpl_BeginStateBlock,
7499 IWineD3DDeviceImpl_EndStateBlock,
7500 /*** Scene management ***/
7501 IWineD3DDeviceImpl_BeginScene,
7502 IWineD3DDeviceImpl_EndScene,
7503 IWineD3DDeviceImpl_Present,
7504 IWineD3DDeviceImpl_Clear,
7505 /*** Drawing ***/
7506 IWineD3DDeviceImpl_DrawPrimitive,
7507 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7508 IWineD3DDeviceImpl_DrawPrimitiveUP,
7509 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7510 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7511 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7512 IWineD3DDeviceImpl_DrawRectPatch,
7513 IWineD3DDeviceImpl_DrawTriPatch,
7514 IWineD3DDeviceImpl_DeletePatch,
7515 IWineD3DDeviceImpl_ColorFill,
7516 IWineD3DDeviceImpl_UpdateTexture,
7517 IWineD3DDeviceImpl_UpdateSurface,
7518 IWineD3DDeviceImpl_GetFrontBufferData,
7519 /*** object tracking ***/
7520 IWineD3DDeviceImpl_ResourceReleased,
7521 IWineD3DDeviceImpl_EnumResources
7524 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7525 WINED3DRS_ALPHABLENDENABLE ,
7526 WINED3DRS_ALPHAFUNC ,
7527 WINED3DRS_ALPHAREF ,
7528 WINED3DRS_ALPHATESTENABLE ,
7529 WINED3DRS_BLENDOP ,
7530 WINED3DRS_COLORWRITEENABLE ,
7531 WINED3DRS_DESTBLEND ,
7532 WINED3DRS_DITHERENABLE ,
7533 WINED3DRS_FILLMODE ,
7534 WINED3DRS_FOGDENSITY ,
7535 WINED3DRS_FOGEND ,
7536 WINED3DRS_FOGSTART ,
7537 WINED3DRS_LASTPIXEL ,
7538 WINED3DRS_SHADEMODE ,
7539 WINED3DRS_SRCBLEND ,
7540 WINED3DRS_STENCILENABLE ,
7541 WINED3DRS_STENCILFAIL ,
7542 WINED3DRS_STENCILFUNC ,
7543 WINED3DRS_STENCILMASK ,
7544 WINED3DRS_STENCILPASS ,
7545 WINED3DRS_STENCILREF ,
7546 WINED3DRS_STENCILWRITEMASK ,
7547 WINED3DRS_STENCILZFAIL ,
7548 WINED3DRS_TEXTUREFACTOR ,
7549 WINED3DRS_WRAP0 ,
7550 WINED3DRS_WRAP1 ,
7551 WINED3DRS_WRAP2 ,
7552 WINED3DRS_WRAP3 ,
7553 WINED3DRS_WRAP4 ,
7554 WINED3DRS_WRAP5 ,
7555 WINED3DRS_WRAP6 ,
7556 WINED3DRS_WRAP7 ,
7557 WINED3DRS_ZENABLE ,
7558 WINED3DRS_ZFUNC ,
7559 WINED3DRS_ZWRITEENABLE
7562 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7563 WINED3DTSS_ADDRESSW ,
7564 WINED3DTSS_ALPHAARG0 ,
7565 WINED3DTSS_ALPHAARG1 ,
7566 WINED3DTSS_ALPHAARG2 ,
7567 WINED3DTSS_ALPHAOP ,
7568 WINED3DTSS_BUMPENVLOFFSET ,
7569 WINED3DTSS_BUMPENVLSCALE ,
7570 WINED3DTSS_BUMPENVMAT00 ,
7571 WINED3DTSS_BUMPENVMAT01 ,
7572 WINED3DTSS_BUMPENVMAT10 ,
7573 WINED3DTSS_BUMPENVMAT11 ,
7574 WINED3DTSS_COLORARG0 ,
7575 WINED3DTSS_COLORARG1 ,
7576 WINED3DTSS_COLORARG2 ,
7577 WINED3DTSS_COLOROP ,
7578 WINED3DTSS_RESULTARG ,
7579 WINED3DTSS_TEXCOORDINDEX ,
7580 WINED3DTSS_TEXTURETRANSFORMFLAGS
7583 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7584 WINED3DSAMP_ADDRESSU ,
7585 WINED3DSAMP_ADDRESSV ,
7586 WINED3DSAMP_ADDRESSW ,
7587 WINED3DSAMP_BORDERCOLOR ,
7588 WINED3DSAMP_MAGFILTER ,
7589 WINED3DSAMP_MINFILTER ,
7590 WINED3DSAMP_MIPFILTER ,
7591 WINED3DSAMP_MIPMAPLODBIAS ,
7592 WINED3DSAMP_MAXMIPLEVEL ,
7593 WINED3DSAMP_MAXANISOTROPY ,
7594 WINED3DSAMP_SRGBTEXTURE ,
7595 WINED3DSAMP_ELEMENTINDEX
7598 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7599 WINED3DRS_AMBIENT ,
7600 WINED3DRS_AMBIENTMATERIALSOURCE ,
7601 WINED3DRS_CLIPPING ,
7602 WINED3DRS_CLIPPLANEENABLE ,
7603 WINED3DRS_COLORVERTEX ,
7604 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7605 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7606 WINED3DRS_FOGDENSITY ,
7607 WINED3DRS_FOGEND ,
7608 WINED3DRS_FOGSTART ,
7609 WINED3DRS_FOGTABLEMODE ,
7610 WINED3DRS_FOGVERTEXMODE ,
7611 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7612 WINED3DRS_LIGHTING ,
7613 WINED3DRS_LOCALVIEWER ,
7614 WINED3DRS_MULTISAMPLEANTIALIAS ,
7615 WINED3DRS_MULTISAMPLEMASK ,
7616 WINED3DRS_NORMALIZENORMALS ,
7617 WINED3DRS_PATCHEDGESTYLE ,
7618 WINED3DRS_POINTSCALE_A ,
7619 WINED3DRS_POINTSCALE_B ,
7620 WINED3DRS_POINTSCALE_C ,
7621 WINED3DRS_POINTSCALEENABLE ,
7622 WINED3DRS_POINTSIZE ,
7623 WINED3DRS_POINTSIZE_MAX ,
7624 WINED3DRS_POINTSIZE_MIN ,
7625 WINED3DRS_POINTSPRITEENABLE ,
7626 WINED3DRS_RANGEFOGENABLE ,
7627 WINED3DRS_SPECULARMATERIALSOURCE ,
7628 WINED3DRS_TWEENFACTOR ,
7629 WINED3DRS_VERTEXBLEND ,
7630 WINED3DRS_CULLMODE ,
7631 WINED3DRS_FOGCOLOR
7634 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7635 WINED3DTSS_TEXCOORDINDEX ,
7636 WINED3DTSS_TEXTURETRANSFORMFLAGS
7639 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7640 WINED3DSAMP_DMAPOFFSET
7643 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7644 DWORD rep = This->StateTable[state].representative;
7645 DWORD idx;
7646 BYTE shift;
7647 UINT i;
7648 WineD3DContext *context;
7650 if(!rep) return;
7651 for(i = 0; i < This->numContexts; i++) {
7652 context = This->contexts[i];
7653 if(isStateDirty(context, rep)) continue;
7655 context->dirtyArray[context->numDirtyEntries++] = rep;
7656 idx = rep >> 5;
7657 shift = rep & 0x1f;
7658 context->isStateDirty[idx] |= (1 << shift);
7662 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7663 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7664 /* The drawable size of a pbuffer render target is the current pbuffer size
7666 *width = dev->pbufferWidth;
7667 *height = dev->pbufferHeight;
7670 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7671 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7673 *width = This->pow2Width;
7674 *height = This->pow2Height;
7677 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7678 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7679 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7680 * current context's drawable, which is the size of the back buffer of the swapchain
7681 * the active context belongs to. The back buffer of the swapchain is stored as the
7682 * surface the context belongs to.
7684 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7685 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;