cryptui: Add a header bitmap to CryptUIWizImport's interior pages.
[wine/wine64.git] / dlls / wined3d / device.c
blob36fbcba5405a21ba7cad3db0ea791bd3abaae680
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 {
1768 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1769 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1771 elements[idx].UsageIndex = 0;
1772 idx++;
1774 if (has_blend && (num_blends > 0)) {
1775 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1776 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1777 else {
1778 switch(num_blends) {
1779 case 1: elements[idx].Type = WINED3DDECLTYPE_FLOAT1; break;
1780 case 2: elements[idx].Type = WINED3DDECLTYPE_FLOAT2; break;
1781 case 3: elements[idx].Type = WINED3DDECLTYPE_FLOAT3; break;
1782 case 4: elements[idx].Type = WINED3DDECLTYPE_FLOAT4; break;
1783 default:
1784 ERR("Unexpected amount of blend values: %u\n", num_blends);
1787 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1788 elements[idx].UsageIndex = 0;
1789 idx++;
1791 if (has_blend_idx) {
1792 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1793 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1794 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1795 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1796 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1797 else
1798 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1799 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1800 elements[idx].UsageIndex = 0;
1801 idx++;
1803 if (has_normal) {
1804 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1805 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1806 elements[idx].UsageIndex = 0;
1807 idx++;
1809 if (has_psize) {
1810 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1811 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1812 elements[idx].UsageIndex = 0;
1813 idx++;
1815 if (has_diffuse) {
1816 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1817 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1818 elements[idx].UsageIndex = 0;
1819 idx++;
1821 if (has_specular) {
1822 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1823 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1824 elements[idx].UsageIndex = 1;
1825 idx++;
1827 for (idx2 = 0; idx2 < num_textures; idx2++) {
1828 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1829 switch (numcoords) {
1830 case WINED3DFVF_TEXTUREFORMAT1:
1831 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1832 break;
1833 case WINED3DFVF_TEXTUREFORMAT2:
1834 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1835 break;
1836 case WINED3DFVF_TEXTUREFORMAT3:
1837 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1838 break;
1839 case WINED3DFVF_TEXTUREFORMAT4:
1840 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1841 break;
1843 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1844 elements[idx].UsageIndex = idx2;
1845 idx++;
1848 /* Now compute offsets, and initialize the rest of the fields */
1849 for (idx = 0, offset = 0; idx < size-1; idx++) {
1850 elements[idx].Stream = 0;
1851 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1852 elements[idx].Offset = offset;
1853 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1856 *ppVertexElements = elements;
1857 return size;
1860 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1861 WINED3DVERTEXELEMENT* elements = NULL;
1862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1863 unsigned int size;
1864 DWORD hr;
1866 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1867 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1869 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1870 HeapFree(GetProcessHeap(), 0, elements);
1871 if (hr != S_OK) return hr;
1873 return WINED3D_OK;
1876 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1878 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1879 HRESULT hr = WINED3D_OK;
1881 if (!pFunction) return WINED3DERR_INVALIDCALL;
1883 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1884 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1886 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1888 if (vertex_declaration) {
1889 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1892 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1894 if (WINED3D_OK != hr) {
1895 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1896 IWineD3DVertexShader_Release(*ppVertexShader);
1897 return WINED3DERR_INVALIDCALL;
1899 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1901 return WINED3D_OK;
1904 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1906 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1907 HRESULT hr = WINED3D_OK;
1909 if (!pFunction) return WINED3DERR_INVALIDCALL;
1911 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1912 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1913 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1914 if (WINED3D_OK == hr) {
1915 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1916 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1917 } else {
1918 WARN("(%p) : Failed to create pixel shader\n", This);
1921 return hr;
1924 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1925 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1928 IWineD3DPaletteImpl *object;
1929 HRESULT hr;
1930 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1932 /* Create the new object */
1933 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1934 if(!object) {
1935 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1936 return E_OUTOFMEMORY;
1939 object->lpVtbl = &IWineD3DPalette_Vtbl;
1940 object->ref = 1;
1941 object->Flags = Flags;
1942 object->parent = Parent;
1943 object->wineD3DDevice = This;
1944 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1946 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1948 if(!object->hpal) {
1949 HeapFree( GetProcessHeap(), 0, object);
1950 return E_OUTOFMEMORY;
1953 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1954 if(FAILED(hr)) {
1955 IWineD3DPalette_Release((IWineD3DPalette *) object);
1956 return hr;
1959 *Palette = (IWineD3DPalette *) object;
1961 return WINED3D_OK;
1964 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1965 HBITMAP hbm;
1966 BITMAP bm;
1967 HRESULT hr;
1968 HDC dcb = NULL, dcs = NULL;
1969 WINEDDCOLORKEY colorkey;
1971 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1972 if(hbm)
1974 GetObjectA(hbm, sizeof(BITMAP), &bm);
1975 dcb = CreateCompatibleDC(NULL);
1976 if(!dcb) goto out;
1977 SelectObject(dcb, hbm);
1979 else
1981 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1982 * couldn't be loaded
1984 memset(&bm, 0, sizeof(bm));
1985 bm.bmWidth = 32;
1986 bm.bmHeight = 32;
1989 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1990 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1991 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1992 if(FAILED(hr)) {
1993 ERR("Wine logo requested, but failed to create surface\n");
1994 goto out;
1997 if(dcb) {
1998 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1999 if(FAILED(hr)) goto out;
2000 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2001 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2003 colorkey.dwColorSpaceLowValue = 0;
2004 colorkey.dwColorSpaceHighValue = 0;
2005 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2006 } else {
2007 /* Fill the surface with a white color to show that wined3d is there */
2008 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2011 out:
2012 if(dcb) {
2013 DeleteDC(dcb);
2015 if(hbm) {
2016 DeleteObject(hbm);
2018 return;
2021 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2022 unsigned int i;
2023 /* Under DirectX you can have texture stage operations even if no texture is
2024 bound, whereas opengl will only do texture operations when a valid texture is
2025 bound. We emulate this by creating dummy textures and binding them to each
2026 texture stage, but disable all stages by default. Hence if a stage is enabled
2027 then the default texture will kick in until replaced by a SetTexture call */
2028 ENTER_GL();
2030 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2031 /* The dummy texture does not have client storage backing */
2032 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2033 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2035 for (i = 0; i < GL_LIMITS(textures); i++) {
2036 GLubyte white = 255;
2038 /* Make appropriate texture active */
2039 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2040 checkGLcall("glActiveTextureARB");
2042 /* Generate an opengl texture name */
2043 glGenTextures(1, &This->dummyTextureName[i]);
2044 checkGLcall("glGenTextures");
2045 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2047 /* Generate a dummy 2d texture (not using 1d because they cause many
2048 * DRI drivers fall back to sw) */
2049 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2050 checkGLcall("glBindTexture");
2052 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2053 checkGLcall("glTexImage2D");
2055 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2056 /* Reenable because if supported it is enabled by default */
2057 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2058 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2061 LEAVE_GL();
2064 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2066 IWineD3DSwapChainImpl *swapchain = NULL;
2067 HRESULT hr;
2068 DWORD state;
2069 unsigned int i;
2071 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateSwapChain);
2072 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2073 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2075 /* TODO: Test if OpenGL is compiled in and loaded */
2077 TRACE("(%p) : Creating stateblock\n", This);
2078 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2079 hr = IWineD3DDevice_CreateStateBlock(iface,
2080 WINED3DSBT_INIT,
2081 (IWineD3DStateBlock **)&This->stateBlock,
2082 NULL);
2083 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2084 WARN("Failed to create stateblock\n");
2085 goto err_out;
2087 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2088 This->updateStateBlock = This->stateBlock;
2089 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2091 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2092 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2094 This->NumberOfPalettes = 1;
2095 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2096 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2097 ERR("Out of memory!\n");
2098 goto err_out;
2100 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2101 if(!This->palettes[0]) {
2102 ERR("Out of memory!\n");
2103 goto err_out;
2105 for (i = 0; i < 256; ++i) {
2106 This->palettes[0][i].peRed = 0xFF;
2107 This->palettes[0][i].peGreen = 0xFF;
2108 This->palettes[0][i].peBlue = 0xFF;
2109 This->palettes[0][i].peFlags = 0xFF;
2111 This->currentPalette = 0;
2113 /* Initialize the texture unit mapping to a 1:1 mapping */
2114 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2115 if (state < GL_LIMITS(fragment_samplers)) {
2116 This->texUnitMap[state] = state;
2117 This->rev_tex_unit_map[state] = state;
2118 } else {
2119 This->texUnitMap[state] = -1;
2120 This->rev_tex_unit_map[state] = -1;
2124 /* Setup the implicit swapchain */
2125 TRACE("Creating implicit swapchain\n");
2126 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2127 if (FAILED(hr) || !swapchain) {
2128 WARN("Failed to create implicit swapchain\n");
2129 goto err_out;
2132 This->NumberOfSwapChains = 1;
2133 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2134 if(!This->swapchains) {
2135 ERR("Out of memory!\n");
2136 goto err_out;
2138 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2140 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2141 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2142 This->render_targets[0] = swapchain->backBuffer[0];
2143 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2145 else {
2146 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2147 This->render_targets[0] = swapchain->frontBuffer;
2148 This->lastActiveRenderTarget = swapchain->frontBuffer;
2150 IWineD3DSurface_AddRef(This->render_targets[0]);
2151 This->activeContext = swapchain->context[0];
2152 This->lastThread = GetCurrentThreadId();
2154 /* Depth Stencil support */
2155 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2156 if (NULL != This->stencilBufferTarget) {
2157 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2160 hr = This->shader_backend->shader_alloc_private(iface);
2161 if(FAILED(hr)) {
2162 TRACE("Shader private data couldn't be allocated\n");
2163 goto err_out;
2165 hr = This->frag_pipe->alloc_private(iface);
2166 if(FAILED(hr)) {
2167 TRACE("Fragment pipeline private data couldn't be allocated\n");
2168 goto err_out;
2170 hr = This->blitter->alloc_private(iface);
2171 if(FAILED(hr)) {
2172 TRACE("Blitter private data couldn't be allocated\n");
2173 goto err_out;
2176 /* Set up some starting GL setup */
2178 /* Setup all the devices defaults */
2179 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2180 create_dummy_textures(This);
2182 ENTER_GL();
2184 /* Initialize the current view state */
2185 This->view_ident = 1;
2186 This->contexts[0]->last_was_rhw = 0;
2187 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2188 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2190 switch(wined3d_settings.offscreen_rendering_mode) {
2191 case ORM_FBO:
2192 case ORM_PBUFFER:
2193 This->offscreenBuffer = GL_BACK;
2194 break;
2196 case ORM_BACKBUFFER:
2198 if(This->activeContext->aux_buffers > 0) {
2199 TRACE("Using auxilliary buffer for offscreen rendering\n");
2200 This->offscreenBuffer = GL_AUX0;
2201 } else {
2202 TRACE("Using back buffer for offscreen rendering\n");
2203 This->offscreenBuffer = GL_BACK;
2208 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2209 LEAVE_GL();
2211 /* Clear the screen */
2212 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2213 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2214 0x00, 1.0, 0);
2216 This->d3d_initialized = TRUE;
2218 if(wined3d_settings.logo) {
2219 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2221 This->highest_dirty_ps_const = 0;
2222 This->highest_dirty_vs_const = 0;
2223 return WINED3D_OK;
2225 err_out:
2226 HeapFree(GetProcessHeap(), 0, This->render_targets);
2227 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2228 HeapFree(GetProcessHeap(), 0, This->swapchains);
2229 This->NumberOfSwapChains = 0;
2230 if(This->palettes) {
2231 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2232 HeapFree(GetProcessHeap(), 0, This->palettes);
2234 This->NumberOfPalettes = 0;
2235 if(swapchain) {
2236 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2238 if(This->stateBlock) {
2239 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2240 This->stateBlock = NULL;
2242 if (This->blit_priv) {
2243 This->blitter->free_private(iface);
2245 if (This->fragment_priv) {
2246 This->frag_pipe->free_private(iface);
2248 if (This->shader_priv) {
2249 This->shader_backend->shader_free_private(iface);
2251 return hr;
2254 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2256 IWineD3DSwapChainImpl *swapchain = NULL;
2257 HRESULT hr;
2259 /* Setup the implicit swapchain */
2260 TRACE("Creating implicit swapchain\n");
2261 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2262 if (FAILED(hr) || !swapchain) {
2263 WARN("Failed to create implicit swapchain\n");
2264 goto err_out;
2267 This->NumberOfSwapChains = 1;
2268 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2269 if(!This->swapchains) {
2270 ERR("Out of memory!\n");
2271 goto err_out;
2273 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2274 return WINED3D_OK;
2276 err_out:
2277 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2278 return hr;
2281 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2283 int sampler;
2284 UINT i;
2285 TRACE("(%p)\n", This);
2287 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2289 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2290 * it was created. Thus make sure a context is active for the glDelete* calls
2292 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2294 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2296 TRACE("Deleting high order patches\n");
2297 for(i = 0; i < PATCHMAP_SIZE; i++) {
2298 struct list *e1, *e2;
2299 struct WineD3DRectPatch *patch;
2300 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2301 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2302 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2306 /* Delete the palette conversion shader if it is around */
2307 if(This->paletteConversionShader) {
2308 ENTER_GL();
2309 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2310 LEAVE_GL();
2311 This->paletteConversionShader = 0;
2314 /* Delete the pbuffer context if there is any */
2315 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2317 /* Delete the mouse cursor texture */
2318 if(This->cursorTexture) {
2319 ENTER_GL();
2320 glDeleteTextures(1, &This->cursorTexture);
2321 LEAVE_GL();
2322 This->cursorTexture = 0;
2325 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2326 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2328 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2329 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2332 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2333 * private data, it might contain opengl pointers
2335 if(This->depth_blt_texture) {
2336 glDeleteTextures(1, &This->depth_blt_texture);
2337 This->depth_blt_texture = 0;
2339 if (This->depth_blt_rb) {
2340 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2341 This->depth_blt_rb = 0;
2342 This->depth_blt_rb_w = 0;
2343 This->depth_blt_rb_h = 0;
2346 /* Release the update stateblock */
2347 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2348 if(This->updateStateBlock != This->stateBlock)
2349 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2351 This->updateStateBlock = NULL;
2353 { /* because were not doing proper internal refcounts releasing the primary state block
2354 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2355 to set this->stateBlock = NULL; first */
2356 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2357 This->stateBlock = NULL;
2359 /* Release the stateblock */
2360 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2361 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2365 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2366 This->blitter->free_private(iface);
2367 This->frag_pipe->free_private(iface);
2368 This->shader_backend->shader_free_private(iface);
2370 /* Release the buffers (with sanity checks)*/
2371 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2372 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2373 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2374 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2376 This->stencilBufferTarget = NULL;
2378 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2379 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2380 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2382 TRACE("Setting rendertarget to NULL\n");
2383 This->render_targets[0] = NULL;
2385 if (This->auto_depth_stencil_buffer) {
2386 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2387 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2389 This->auto_depth_stencil_buffer = NULL;
2392 for(i=0; i < This->NumberOfSwapChains; i++) {
2393 TRACE("Releasing the implicit swapchain %d\n", i);
2394 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2395 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2399 HeapFree(GetProcessHeap(), 0, This->swapchains);
2400 This->swapchains = NULL;
2401 This->NumberOfSwapChains = 0;
2403 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2404 HeapFree(GetProcessHeap(), 0, This->palettes);
2405 This->palettes = NULL;
2406 This->NumberOfPalettes = 0;
2408 HeapFree(GetProcessHeap(), 0, This->render_targets);
2409 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2410 This->render_targets = NULL;
2411 This->draw_buffers = NULL;
2413 This->d3d_initialized = FALSE;
2414 return WINED3D_OK;
2417 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2419 unsigned int i;
2421 for(i=0; i < This->NumberOfSwapChains; i++) {
2422 TRACE("Releasing the implicit swapchain %d\n", i);
2423 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2424 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2428 HeapFree(GetProcessHeap(), 0, This->swapchains);
2429 This->swapchains = NULL;
2430 This->NumberOfSwapChains = 0;
2431 return WINED3D_OK;
2434 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2435 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2436 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2438 * There is no way to deactivate thread safety once it is enabled.
2440 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2443 /*For now just store the flag(needed in case of ddraw) */
2444 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2446 return;
2449 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2450 const WINED3DDISPLAYMODE* pMode) {
2451 DEVMODEW devmode;
2452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2453 LONG ret;
2454 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2455 RECT clip_rc;
2457 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2459 /* Resize the screen even without a window:
2460 * The app could have unset it with SetCooperativeLevel, but not called
2461 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2462 * but we don't have any hwnd
2465 memset(&devmode, 0, sizeof(devmode));
2466 devmode.dmSize = sizeof(devmode);
2467 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2468 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2469 devmode.dmPelsWidth = pMode->Width;
2470 devmode.dmPelsHeight = pMode->Height;
2472 devmode.dmDisplayFrequency = pMode->RefreshRate;
2473 if (pMode->RefreshRate != 0) {
2474 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2477 /* Only change the mode if necessary */
2478 if( (This->ddraw_width == pMode->Width) &&
2479 (This->ddraw_height == pMode->Height) &&
2480 (This->ddraw_format == pMode->Format) &&
2481 (pMode->RefreshRate == 0) ) {
2482 return WINED3D_OK;
2485 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2486 if (ret != DISP_CHANGE_SUCCESSFUL) {
2487 if(devmode.dmDisplayFrequency != 0) {
2488 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2489 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2490 devmode.dmDisplayFrequency = 0;
2491 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2493 if(ret != DISP_CHANGE_SUCCESSFUL) {
2494 return WINED3DERR_NOTAVAILABLE;
2498 /* Store the new values */
2499 This->ddraw_width = pMode->Width;
2500 This->ddraw_height = pMode->Height;
2501 This->ddraw_format = pMode->Format;
2503 /* And finally clip mouse to our screen */
2504 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2505 ClipCursor(&clip_rc);
2507 return WINED3D_OK;
2510 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2511 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2512 *ppD3D= This->wineD3D;
2513 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2514 IWineD3D_AddRef(*ppD3D);
2515 return WINED3D_OK;
2518 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2521 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2522 (This->adapter->TextureRam/(1024*1024)),
2523 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2524 /* return simulated texture memory left */
2525 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2528 /*****
2529 * Get / Set Stream Source
2530 *****/
2531 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2533 IWineD3DVertexBuffer *oldSrc;
2535 if (StreamNumber >= MAX_STREAMS) {
2536 WARN("Stream out of range %d\n", StreamNumber);
2537 return WINED3DERR_INVALIDCALL;
2538 } else if(OffsetInBytes & 0x3) {
2539 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2540 return WINED3DERR_INVALIDCALL;
2543 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2544 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2546 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2548 if(oldSrc == pStreamData &&
2549 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2550 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2551 TRACE("Application is setting the old values over, nothing to do\n");
2552 return WINED3D_OK;
2555 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2556 if (pStreamData) {
2557 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2558 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2561 /* Handle recording of state blocks */
2562 if (This->isRecordingState) {
2563 TRACE("Recording... not performing anything\n");
2564 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2565 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2566 return WINED3D_OK;
2569 /* Need to do a getParent and pass the references up */
2570 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2571 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2572 so for now, just count internally */
2573 if (pStreamData != NULL) {
2574 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2575 InterlockedIncrement(&vbImpl->bindCount);
2576 IWineD3DVertexBuffer_AddRef(pStreamData);
2578 if (oldSrc != NULL) {
2579 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2580 IWineD3DVertexBuffer_Release(oldSrc);
2583 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2585 return WINED3D_OK;
2588 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2591 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2592 This->stateBlock->streamSource[StreamNumber],
2593 This->stateBlock->streamOffset[StreamNumber],
2594 This->stateBlock->streamStride[StreamNumber]);
2596 if (StreamNumber >= MAX_STREAMS) {
2597 WARN("Stream out of range %d\n", StreamNumber);
2598 return WINED3DERR_INVALIDCALL;
2600 *pStream = This->stateBlock->streamSource[StreamNumber];
2601 *pStride = This->stateBlock->streamStride[StreamNumber];
2602 if (pOffset) {
2603 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2606 if (*pStream != NULL) {
2607 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2609 return WINED3D_OK;
2612 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2614 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2615 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2617 /* Verify input at least in d3d9 this is invalid*/
2618 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2619 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2620 return WINED3DERR_INVALIDCALL;
2622 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2623 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2624 return WINED3DERR_INVALIDCALL;
2626 if( Divider == 0 ){
2627 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2628 return WINED3DERR_INVALIDCALL;
2631 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2632 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2634 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2635 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2637 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2638 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2639 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2642 return WINED3D_OK;
2645 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2648 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2649 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2651 TRACE("(%p) : returning %d\n", This, *Divider);
2653 return WINED3D_OK;
2656 /*****
2657 * Get / Set & Multiply Transform
2658 *****/
2659 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2662 /* Most of this routine, comments included copied from ddraw tree initially: */
2663 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2665 /* Handle recording of state blocks */
2666 if (This->isRecordingState) {
2667 TRACE("Recording... not performing anything\n");
2668 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2669 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2670 return WINED3D_OK;
2674 * If the new matrix is the same as the current one,
2675 * we cut off any further processing. this seems to be a reasonable
2676 * optimization because as was noticed, some apps (warcraft3 for example)
2677 * tend towards setting the same matrix repeatedly for some reason.
2679 * From here on we assume that the new matrix is different, wherever it matters.
2681 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2682 TRACE("The app is setting the same matrix over again\n");
2683 return WINED3D_OK;
2684 } else {
2685 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2689 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2690 where ViewMat = Camera space, WorldMat = world space.
2692 In OpenGL, camera and world space is combined into GL_MODELVIEW
2693 matrix. The Projection matrix stay projection matrix.
2696 /* Capture the times we can just ignore the change for now */
2697 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2698 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2699 /* Handled by the state manager */
2702 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2703 return WINED3D_OK;
2706 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2708 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2709 *pMatrix = This->stateBlock->transforms[State];
2710 return WINED3D_OK;
2713 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2714 const WINED3DMATRIX *mat = NULL;
2715 WINED3DMATRIX temp;
2717 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2718 * below means it will be recorded in a state block change, but it
2719 * works regardless where it is recorded.
2720 * If this is found to be wrong, change to StateBlock.
2722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2723 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2725 if (State < HIGHEST_TRANSFORMSTATE)
2727 mat = &This->updateStateBlock->transforms[State];
2728 } else {
2729 FIXME("Unhandled transform state!!\n");
2732 multiply_matrix(&temp, mat, pMatrix);
2734 /* Apply change via set transform - will reapply to eg. lights this way */
2735 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2738 /*****
2739 * Get / Set Light
2740 *****/
2741 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2742 you can reference any indexes you want as long as that number max are enabled at any
2743 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2744 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2745 but when recording, just build a chain pretty much of commands to be replayed. */
2747 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2748 float rho;
2749 PLIGHTINFOEL *object = NULL;
2750 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2751 struct list *e;
2753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2754 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2756 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2757 * the gl driver.
2759 if(!pLight) {
2760 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2761 return WINED3DERR_INVALIDCALL;
2764 switch(pLight->Type) {
2765 case WINED3DLIGHT_POINT:
2766 case WINED3DLIGHT_SPOT:
2767 case WINED3DLIGHT_PARALLELPOINT:
2768 case WINED3DLIGHT_GLSPOT:
2769 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2770 * most wanted
2772 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2773 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2774 return WINED3DERR_INVALIDCALL;
2776 break;
2778 case WINED3DLIGHT_DIRECTIONAL:
2779 /* Ignores attenuation */
2780 break;
2782 default:
2783 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2784 return WINED3DERR_INVALIDCALL;
2787 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2788 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2789 if(object->OriginalIndex == Index) break;
2790 object = NULL;
2793 if(!object) {
2794 TRACE("Adding new light\n");
2795 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2796 if(!object) {
2797 ERR("Out of memory error when allocating a light\n");
2798 return E_OUTOFMEMORY;
2800 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2801 object->glIndex = -1;
2802 object->OriginalIndex = Index;
2803 object->changed = TRUE;
2806 /* Initialize the object */
2807 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,
2808 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2809 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2810 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2811 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2812 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2813 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2815 /* Save away the information */
2816 object->OriginalParms = *pLight;
2818 switch (pLight->Type) {
2819 case WINED3DLIGHT_POINT:
2820 /* Position */
2821 object->lightPosn[0] = pLight->Position.x;
2822 object->lightPosn[1] = pLight->Position.y;
2823 object->lightPosn[2] = pLight->Position.z;
2824 object->lightPosn[3] = 1.0f;
2825 object->cutoff = 180.0f;
2826 /* FIXME: Range */
2827 break;
2829 case WINED3DLIGHT_DIRECTIONAL:
2830 /* Direction */
2831 object->lightPosn[0] = -pLight->Direction.x;
2832 object->lightPosn[1] = -pLight->Direction.y;
2833 object->lightPosn[2] = -pLight->Direction.z;
2834 object->lightPosn[3] = 0.0;
2835 object->exponent = 0.0f;
2836 object->cutoff = 180.0f;
2837 break;
2839 case WINED3DLIGHT_SPOT:
2840 /* Position */
2841 object->lightPosn[0] = pLight->Position.x;
2842 object->lightPosn[1] = pLight->Position.y;
2843 object->lightPosn[2] = pLight->Position.z;
2844 object->lightPosn[3] = 1.0;
2846 /* Direction */
2847 object->lightDirn[0] = pLight->Direction.x;
2848 object->lightDirn[1] = pLight->Direction.y;
2849 object->lightDirn[2] = pLight->Direction.z;
2850 object->lightDirn[3] = 1.0;
2853 * opengl-ish and d3d-ish spot lights use too different models for the
2854 * light "intensity" as a function of the angle towards the main light direction,
2855 * so we only can approximate very roughly.
2856 * however spot lights are rather rarely used in games (if ever used at all).
2857 * furthermore if still used, probably nobody pays attention to such details.
2859 if (pLight->Falloff == 0) {
2860 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2861 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2862 * will always be 1.0 for both of them, and we don't have to care for the
2863 * rest of the rather complex calculation
2865 object->exponent = 0;
2866 } else {
2867 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2868 if (rho < 0.0001) rho = 0.0001f;
2869 object->exponent = -0.3/log(cos(rho/2));
2871 if (object->exponent > 128.0) {
2872 object->exponent = 128.0;
2874 object->cutoff = pLight->Phi*90/M_PI;
2876 /* FIXME: Range */
2877 break;
2879 default:
2880 FIXME("Unrecognized light type %d\n", pLight->Type);
2883 /* Update the live definitions if the light is currently assigned a glIndex */
2884 if (object->glIndex != -1 && !This->isRecordingState) {
2885 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2887 return WINED3D_OK;
2890 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2891 PLIGHTINFOEL *lightInfo = NULL;
2892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2893 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2894 struct list *e;
2895 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2897 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2898 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2899 if(lightInfo->OriginalIndex == Index) break;
2900 lightInfo = NULL;
2903 if (lightInfo == NULL) {
2904 TRACE("Light information requested but light not defined\n");
2905 return WINED3DERR_INVALIDCALL;
2908 *pLight = lightInfo->OriginalParms;
2909 return WINED3D_OK;
2912 /*****
2913 * Get / Set Light Enable
2914 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2915 *****/
2916 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2917 PLIGHTINFOEL *lightInfo = NULL;
2918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2919 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2920 struct list *e;
2921 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2923 /* Tests show true = 128...not clear why */
2924 Enable = Enable? 128: 0;
2926 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2927 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2928 if(lightInfo->OriginalIndex == Index) break;
2929 lightInfo = NULL;
2931 TRACE("Found light: %p\n", lightInfo);
2933 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2934 if (lightInfo == NULL) {
2936 TRACE("Light enabled requested but light not defined, so defining one!\n");
2937 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2939 /* Search for it again! Should be fairly quick as near head of list */
2940 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2941 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2942 if(lightInfo->OriginalIndex == Index) break;
2943 lightInfo = NULL;
2945 if (lightInfo == NULL) {
2946 FIXME("Adding default lights has failed dismally\n");
2947 return WINED3DERR_INVALIDCALL;
2951 lightInfo->enabledChanged = TRUE;
2952 if(!Enable) {
2953 if(lightInfo->glIndex != -1) {
2954 if(!This->isRecordingState) {
2955 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2958 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2959 lightInfo->glIndex = -1;
2960 } else {
2961 TRACE("Light already disabled, nothing to do\n");
2963 lightInfo->enabled = FALSE;
2964 } else {
2965 lightInfo->enabled = TRUE;
2966 if (lightInfo->glIndex != -1) {
2967 /* nop */
2968 TRACE("Nothing to do as light was enabled\n");
2969 } else {
2970 int i;
2971 /* Find a free gl light */
2972 for(i = 0; i < This->maxConcurrentLights; i++) {
2973 if(This->updateStateBlock->activeLights[i] == NULL) {
2974 This->updateStateBlock->activeLights[i] = lightInfo;
2975 lightInfo->glIndex = i;
2976 break;
2979 if(lightInfo->glIndex == -1) {
2980 /* Our tests show that Windows returns D3D_OK in this situation, even with
2981 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2982 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2983 * as well for those lights.
2985 * TODO: Test how this affects rendering
2987 FIXME("Too many concurrently active lights\n");
2988 return WINED3D_OK;
2991 /* i == lightInfo->glIndex */
2992 if(!This->isRecordingState) {
2993 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2998 return WINED3D_OK;
3001 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3003 PLIGHTINFOEL *lightInfo = NULL;
3004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3005 struct list *e;
3006 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3007 TRACE("(%p) : for idx(%d)\n", This, Index);
3009 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3010 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3011 if(lightInfo->OriginalIndex == Index) break;
3012 lightInfo = NULL;
3015 if (lightInfo == NULL) {
3016 TRACE("Light enabled state requested but light not defined\n");
3017 return WINED3DERR_INVALIDCALL;
3019 /* true is 128 according to SetLightEnable */
3020 *pEnable = lightInfo->enabled ? 128 : 0;
3021 return WINED3D_OK;
3024 /*****
3025 * Get / Set Clip Planes
3026 *****/
3027 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3028 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3029 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3031 /* Validate Index */
3032 if (Index >= GL_LIMITS(clipplanes)) {
3033 TRACE("Application has requested clipplane this device doesn't support\n");
3034 return WINED3DERR_INVALIDCALL;
3037 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3039 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3040 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3041 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3042 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3043 TRACE("Application is setting old values over, nothing to do\n");
3044 return WINED3D_OK;
3047 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3048 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3049 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3050 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3052 /* Handle recording of state blocks */
3053 if (This->isRecordingState) {
3054 TRACE("Recording... not performing anything\n");
3055 return WINED3D_OK;
3058 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3060 return WINED3D_OK;
3063 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3065 TRACE("(%p) : for idx %d\n", This, Index);
3067 /* Validate Index */
3068 if (Index >= GL_LIMITS(clipplanes)) {
3069 TRACE("Application has requested clipplane this device doesn't support\n");
3070 return WINED3DERR_INVALIDCALL;
3073 pPlane[0] = This->stateBlock->clipplane[Index][0];
3074 pPlane[1] = This->stateBlock->clipplane[Index][1];
3075 pPlane[2] = This->stateBlock->clipplane[Index][2];
3076 pPlane[3] = This->stateBlock->clipplane[Index][3];
3077 return WINED3D_OK;
3080 /*****
3081 * Get / Set Clip Plane Status
3082 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3083 *****/
3084 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3086 FIXME("(%p) : stub\n", This);
3087 if (NULL == pClipStatus) {
3088 return WINED3DERR_INVALIDCALL;
3090 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3091 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3092 return WINED3D_OK;
3095 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3097 FIXME("(%p) : stub\n", This);
3098 if (NULL == pClipStatus) {
3099 return WINED3DERR_INVALIDCALL;
3101 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3102 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3103 return WINED3D_OK;
3106 /*****
3107 * Get / Set Material
3108 *****/
3109 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3112 This->updateStateBlock->changed.material = TRUE;
3113 This->updateStateBlock->material = *pMaterial;
3115 /* Handle recording of state blocks */
3116 if (This->isRecordingState) {
3117 TRACE("Recording... not performing anything\n");
3118 return WINED3D_OK;
3121 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3122 return WINED3D_OK;
3125 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3127 *pMaterial = This->updateStateBlock->material;
3128 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3129 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3130 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3131 pMaterial->Ambient.b, pMaterial->Ambient.a);
3132 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3133 pMaterial->Specular.b, pMaterial->Specular.a);
3134 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3135 pMaterial->Emissive.b, pMaterial->Emissive.a);
3136 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3138 return WINED3D_OK;
3141 /*****
3142 * Get / Set Indices
3143 *****/
3144 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3146 IWineD3DIndexBuffer *oldIdxs;
3148 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3149 oldIdxs = This->updateStateBlock->pIndexData;
3151 This->updateStateBlock->changed.indices = TRUE;
3152 This->updateStateBlock->pIndexData = pIndexData;
3154 /* Handle recording of state blocks */
3155 if (This->isRecordingState) {
3156 TRACE("Recording... not performing anything\n");
3157 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3158 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3159 return WINED3D_OK;
3162 if(oldIdxs != pIndexData) {
3163 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3164 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3165 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3167 return WINED3D_OK;
3170 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3173 *ppIndexData = This->stateBlock->pIndexData;
3175 /* up ref count on ppindexdata */
3176 if (*ppIndexData) {
3177 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3178 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3179 }else{
3180 TRACE("(%p) No index data set\n", This);
3182 TRACE("Returning %p\n", *ppIndexData);
3184 return WINED3D_OK;
3187 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3188 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3190 TRACE("(%p)->(%d)\n", This, BaseIndex);
3192 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3193 TRACE("Application is setting the old value over, nothing to do\n");
3194 return WINED3D_OK;
3197 This->updateStateBlock->baseVertexIndex = BaseIndex;
3199 if (This->isRecordingState) {
3200 TRACE("Recording... not performing anything\n");
3201 return WINED3D_OK;
3203 /* The base vertex index affects the stream sources */
3204 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3205 return WINED3D_OK;
3208 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3210 TRACE("(%p) : base_index %p\n", This, base_index);
3212 *base_index = This->stateBlock->baseVertexIndex;
3214 TRACE("Returning %u\n", *base_index);
3216 return WINED3D_OK;
3219 /*****
3220 * Get / Set Viewports
3221 *****/
3222 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3225 TRACE("(%p)\n", This);
3226 This->updateStateBlock->changed.viewport = TRUE;
3227 This->updateStateBlock->viewport = *pViewport;
3229 /* Handle recording of state blocks */
3230 if (This->isRecordingState) {
3231 TRACE("Recording... not performing anything\n");
3232 return WINED3D_OK;
3235 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3236 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3238 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3239 return WINED3D_OK;
3243 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3245 TRACE("(%p)\n", This);
3246 *pViewport = This->stateBlock->viewport;
3247 return WINED3D_OK;
3250 /*****
3251 * Get / Set Render States
3252 * TODO: Verify against dx9 definitions
3253 *****/
3254 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3257 DWORD oldValue = This->stateBlock->renderState[State];
3259 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3261 This->updateStateBlock->changed.renderState[State] = TRUE;
3262 This->updateStateBlock->renderState[State] = Value;
3264 /* Handle recording of state blocks */
3265 if (This->isRecordingState) {
3266 TRACE("Recording... not performing anything\n");
3267 return WINED3D_OK;
3270 /* Compared here and not before the assignment to allow proper stateblock recording */
3271 if(Value == oldValue) {
3272 TRACE("Application is setting the old value over, nothing to do\n");
3273 } else {
3274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3277 return WINED3D_OK;
3280 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3282 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3283 *pValue = This->stateBlock->renderState[State];
3284 return WINED3D_OK;
3287 /*****
3288 * Get / Set Sampler States
3289 * TODO: Verify against dx9 definitions
3290 *****/
3292 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3294 DWORD oldValue;
3296 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3297 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3299 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3300 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3303 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3304 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3305 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3308 * SetSampler is designed to allow for more than the standard up to 8 textures
3309 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3310 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3312 * http://developer.nvidia.com/object/General_FAQ.html#t6
3314 * There are two new settings for GForce
3315 * the sampler one:
3316 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3317 * and the texture one:
3318 * GL_MAX_TEXTURE_COORDS_ARB.
3319 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3320 ******************/
3322 oldValue = This->stateBlock->samplerState[Sampler][Type];
3323 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3324 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3326 /* Handle recording of state blocks */
3327 if (This->isRecordingState) {
3328 TRACE("Recording... not performing anything\n");
3329 return WINED3D_OK;
3332 if(oldValue == Value) {
3333 TRACE("Application is setting the old value over, nothing to do\n");
3334 return WINED3D_OK;
3337 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3339 return WINED3D_OK;
3342 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3345 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3346 This, Sampler, debug_d3dsamplerstate(Type), Type);
3348 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3349 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3352 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3353 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3354 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3356 *Value = This->stateBlock->samplerState[Sampler][Type];
3357 TRACE("(%p) : Returning %#x\n", This, *Value);
3359 return WINED3D_OK;
3362 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3365 This->updateStateBlock->changed.scissorRect = TRUE;
3366 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3367 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3368 return WINED3D_OK;
3370 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3372 if(This->isRecordingState) {
3373 TRACE("Recording... not performing anything\n");
3374 return WINED3D_OK;
3377 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3379 return WINED3D_OK;
3382 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3385 *pRect = This->updateStateBlock->scissorRect;
3386 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3387 return WINED3D_OK;
3390 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3392 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3394 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3396 This->updateStateBlock->vertexDecl = pDecl;
3397 This->updateStateBlock->changed.vertexDecl = TRUE;
3399 if (This->isRecordingState) {
3400 TRACE("Recording... not performing anything\n");
3401 return WINED3D_OK;
3402 } else if(pDecl == oldDecl) {
3403 /* Checked after the assignment to allow proper stateblock recording */
3404 TRACE("Application is setting the old declaration over, nothing to do\n");
3405 return WINED3D_OK;
3408 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3409 return WINED3D_OK;
3412 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3415 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3417 *ppDecl = This->stateBlock->vertexDecl;
3418 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3419 return WINED3D_OK;
3422 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3424 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3426 This->updateStateBlock->vertexShader = pShader;
3427 This->updateStateBlock->changed.vertexShader = TRUE;
3429 if (This->isRecordingState) {
3430 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3431 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3432 TRACE("Recording... not performing anything\n");
3433 return WINED3D_OK;
3434 } else if(oldShader == pShader) {
3435 /* Checked here to allow proper stateblock recording */
3436 TRACE("App is setting the old shader over, nothing to do\n");
3437 return WINED3D_OK;
3440 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3441 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3442 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3444 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3446 return WINED3D_OK;
3449 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3452 if (NULL == ppShader) {
3453 return WINED3DERR_INVALIDCALL;
3455 *ppShader = This->stateBlock->vertexShader;
3456 if( NULL != *ppShader)
3457 IWineD3DVertexShader_AddRef(*ppShader);
3459 TRACE("(%p) : returning %p\n", This, *ppShader);
3460 return WINED3D_OK;
3463 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3464 IWineD3DDevice *iface,
3465 UINT start,
3466 CONST BOOL *srcData,
3467 UINT count) {
3469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3470 int i, cnt = min(count, MAX_CONST_B - start);
3472 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3473 iface, srcData, start, count);
3475 if (srcData == NULL || cnt < 0)
3476 return WINED3DERR_INVALIDCALL;
3478 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3479 for (i = 0; i < cnt; i++)
3480 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3482 for (i = start; i < cnt + start; ++i) {
3483 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3486 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3488 return WINED3D_OK;
3491 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3492 IWineD3DDevice *iface,
3493 UINT start,
3494 BOOL *dstData,
3495 UINT count) {
3497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3498 int cnt = min(count, MAX_CONST_B - start);
3500 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3501 iface, dstData, start, count);
3503 if (dstData == NULL || cnt < 0)
3504 return WINED3DERR_INVALIDCALL;
3506 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3507 return WINED3D_OK;
3510 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3511 IWineD3DDevice *iface,
3512 UINT start,
3513 CONST int *srcData,
3514 UINT count) {
3516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3517 int i, cnt = min(count, MAX_CONST_I - start);
3519 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3520 iface, srcData, start, count);
3522 if (srcData == NULL || cnt < 0)
3523 return WINED3DERR_INVALIDCALL;
3525 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3526 for (i = 0; i < cnt; i++)
3527 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3528 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3530 for (i = start; i < cnt + start; ++i) {
3531 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3534 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3536 return WINED3D_OK;
3539 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3540 IWineD3DDevice *iface,
3541 UINT start,
3542 int *dstData,
3543 UINT count) {
3545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3546 int cnt = min(count, MAX_CONST_I - start);
3548 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3549 iface, dstData, start, count);
3551 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3552 return WINED3DERR_INVALIDCALL;
3554 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3555 return WINED3D_OK;
3558 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3559 IWineD3DDevice *iface,
3560 UINT start,
3561 CONST float *srcData,
3562 UINT count) {
3564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3565 UINT i;
3567 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3568 iface, srcData, start, count);
3570 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3571 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3572 return WINED3DERR_INVALIDCALL;
3574 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3575 if(TRACE_ON(d3d)) {
3576 for (i = 0; i < count; i++)
3577 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3578 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3581 if (!This->isRecordingState)
3583 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3584 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3587 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3588 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3590 return WINED3D_OK;
3593 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3594 IWineD3DDevice *iface,
3595 UINT start,
3596 float *dstData,
3597 UINT count) {
3599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3600 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3602 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3603 iface, dstData, start, count);
3605 if (dstData == NULL || cnt < 0)
3606 return WINED3DERR_INVALIDCALL;
3608 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3609 return WINED3D_OK;
3612 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3613 DWORD i;
3614 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3615 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3619 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3620 int i = This->rev_tex_unit_map[unit];
3621 int j = This->texUnitMap[stage];
3623 This->texUnitMap[stage] = unit;
3624 if (i != -1 && i != stage) {
3625 This->texUnitMap[i] = -1;
3628 This->rev_tex_unit_map[unit] = stage;
3629 if (j != -1 && j != unit) {
3630 This->rev_tex_unit_map[j] = -1;
3634 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3635 int i;
3637 for (i = 0; i < MAX_TEXTURES; ++i) {
3638 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3639 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3640 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3641 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3642 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3643 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3644 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3645 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3647 if (color_op == WINED3DTOP_DISABLE) {
3648 /* Not used, and disable higher stages */
3649 while (i < MAX_TEXTURES) {
3650 This->fixed_function_usage_map[i] = FALSE;
3651 ++i;
3653 break;
3656 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3657 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3658 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3659 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3660 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3661 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3662 This->fixed_function_usage_map[i] = TRUE;
3663 } else {
3664 This->fixed_function_usage_map[i] = FALSE;
3667 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3668 This->fixed_function_usage_map[i+1] = TRUE;
3673 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3674 int i, tex;
3676 device_update_fixed_function_usage_map(This);
3678 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3679 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3680 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3681 if (!This->fixed_function_usage_map[i]) continue;
3683 if (This->texUnitMap[i] != i) {
3684 device_map_stage(This, i, i);
3685 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3686 markTextureStagesDirty(This, i);
3689 return;
3692 /* Now work out the mapping */
3693 tex = 0;
3694 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3695 if (!This->fixed_function_usage_map[i]) continue;
3697 if (This->texUnitMap[i] != tex) {
3698 device_map_stage(This, i, tex);
3699 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3700 markTextureStagesDirty(This, i);
3703 ++tex;
3707 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3708 const DWORD *sampler_tokens =
3709 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3710 int i;
3712 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3713 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3714 device_map_stage(This, i, i);
3715 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3716 if (i < MAX_TEXTURES) {
3717 markTextureStagesDirty(This, i);
3723 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3724 const DWORD *vshader_sampler_tokens, int unit)
3726 int current_mapping = This->rev_tex_unit_map[unit];
3728 if (current_mapping == -1) {
3729 /* Not currently used */
3730 return TRUE;
3733 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3734 /* Used by a fragment sampler */
3736 if (!pshader_sampler_tokens) {
3737 /* No pixel shader, check fixed function */
3738 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3741 /* Pixel shader, check the shader's sampler map */
3742 return !pshader_sampler_tokens[current_mapping];
3745 /* Used by a vertex sampler */
3746 return !vshader_sampler_tokens[current_mapping];
3749 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3750 const DWORD *vshader_sampler_tokens =
3751 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3752 const DWORD *pshader_sampler_tokens = NULL;
3753 int start = GL_LIMITS(combined_samplers) - 1;
3754 int i;
3756 if (ps) {
3757 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3759 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3760 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3761 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3764 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3765 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3766 if (vshader_sampler_tokens[i]) {
3767 if (This->texUnitMap[vsampler_idx] != -1) {
3768 /* Already mapped somewhere */
3769 continue;
3772 while (start >= 0) {
3773 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3774 device_map_stage(This, vsampler_idx, start);
3775 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3777 --start;
3778 break;
3781 --start;
3787 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3788 BOOL vs = use_vs(This);
3789 BOOL ps = use_ps(This);
3791 * Rules are:
3792 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3793 * that would be really messy and require shader recompilation
3794 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3795 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3797 if (ps) {
3798 device_map_psamplers(This);
3799 } else {
3800 device_map_fixed_function_samplers(This);
3803 if (vs) {
3804 device_map_vsamplers(This, ps);
3808 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3810 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3811 This->updateStateBlock->pixelShader = pShader;
3812 This->updateStateBlock->changed.pixelShader = TRUE;
3814 /* Handle recording of state blocks */
3815 if (This->isRecordingState) {
3816 TRACE("Recording... not performing anything\n");
3819 if (This->isRecordingState) {
3820 TRACE("Recording... not performing anything\n");
3821 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3822 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3823 return WINED3D_OK;
3826 if(pShader == oldShader) {
3827 TRACE("App is setting the old pixel shader over, nothing to do\n");
3828 return WINED3D_OK;
3831 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3832 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3834 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3835 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3837 return WINED3D_OK;
3840 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3843 if (NULL == ppShader) {
3844 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3845 return WINED3DERR_INVALIDCALL;
3848 *ppShader = This->stateBlock->pixelShader;
3849 if (NULL != *ppShader) {
3850 IWineD3DPixelShader_AddRef(*ppShader);
3852 TRACE("(%p) : returning %p\n", This, *ppShader);
3853 return WINED3D_OK;
3856 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3857 IWineD3DDevice *iface,
3858 UINT start,
3859 CONST BOOL *srcData,
3860 UINT count) {
3862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3863 int i, cnt = min(count, MAX_CONST_B - start);
3865 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3866 iface, srcData, start, count);
3868 if (srcData == NULL || cnt < 0)
3869 return WINED3DERR_INVALIDCALL;
3871 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3872 for (i = 0; i < cnt; i++)
3873 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3875 for (i = start; i < cnt + start; ++i) {
3876 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3879 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3881 return WINED3D_OK;
3884 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3885 IWineD3DDevice *iface,
3886 UINT start,
3887 BOOL *dstData,
3888 UINT count) {
3890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3891 int cnt = min(count, MAX_CONST_B - start);
3893 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3894 iface, dstData, start, count);
3896 if (dstData == NULL || cnt < 0)
3897 return WINED3DERR_INVALIDCALL;
3899 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3900 return WINED3D_OK;
3903 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3904 IWineD3DDevice *iface,
3905 UINT start,
3906 CONST int *srcData,
3907 UINT count) {
3909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3910 int i, cnt = min(count, MAX_CONST_I - start);
3912 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3913 iface, srcData, start, count);
3915 if (srcData == NULL || cnt < 0)
3916 return WINED3DERR_INVALIDCALL;
3918 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3919 for (i = 0; i < cnt; i++)
3920 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3921 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3923 for (i = start; i < cnt + start; ++i) {
3924 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3927 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3929 return WINED3D_OK;
3932 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3933 IWineD3DDevice *iface,
3934 UINT start,
3935 int *dstData,
3936 UINT count) {
3938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3939 int cnt = min(count, MAX_CONST_I - start);
3941 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3942 iface, dstData, start, count);
3944 if (dstData == NULL || cnt < 0)
3945 return WINED3DERR_INVALIDCALL;
3947 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3948 return WINED3D_OK;
3951 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3952 IWineD3DDevice *iface,
3953 UINT start,
3954 CONST float *srcData,
3955 UINT count) {
3957 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3958 UINT i;
3960 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3961 iface, srcData, start, count);
3963 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3964 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3965 return WINED3DERR_INVALIDCALL;
3967 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3968 if(TRACE_ON(d3d)) {
3969 for (i = 0; i < count; i++)
3970 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3971 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3974 if (!This->isRecordingState)
3976 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3977 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3980 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3981 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3983 return WINED3D_OK;
3986 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3987 IWineD3DDevice *iface,
3988 UINT start,
3989 float *dstData,
3990 UINT count) {
3992 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3993 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3995 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3996 iface, dstData, start, count);
3998 if (dstData == NULL || cnt < 0)
3999 return WINED3DERR_INVALIDCALL;
4001 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4002 return WINED3D_OK;
4005 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4006 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4007 const WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags)
4009 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4010 unsigned int i;
4011 DWORD DestFVF = dest->fvf;
4012 WINED3DVIEWPORT vp;
4013 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4014 BOOL doClip;
4015 DWORD numTextures;
4017 if (lpStrideData->u.s.normal.lpData) {
4018 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4021 if (lpStrideData->u.s.position.lpData == NULL) {
4022 ERR("Source has no position mask\n");
4023 return WINED3DERR_INVALIDCALL;
4026 /* We might access VBOs from this code, so hold the lock */
4027 ENTER_GL();
4029 if (dest->resource.allocatedMemory == NULL) {
4030 /* This may happen if we do direct locking into a vbo. Unlikely,
4031 * but theoretically possible(ddraw processvertices test)
4033 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4034 if(!dest->resource.allocatedMemory) {
4035 LEAVE_GL();
4036 ERR("Out of memory\n");
4037 return E_OUTOFMEMORY;
4039 if(dest->vbo) {
4040 const void *src;
4041 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4042 checkGLcall("glBindBufferARB");
4043 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4044 if(src) {
4045 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4047 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4048 checkGLcall("glUnmapBufferARB");
4052 /* Get a pointer into the destination vbo(create one if none exists) and
4053 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4055 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4056 dest->Flags |= VBFLAG_CREATEVBO;
4057 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4060 if(dest->vbo) {
4061 unsigned char extrabytes = 0;
4062 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4063 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4064 * this may write 4 extra bytes beyond the area that should be written
4066 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4067 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4068 if(!dest_conv_addr) {
4069 ERR("Out of memory\n");
4070 /* Continue without storing converted vertices */
4072 dest_conv = dest_conv_addr;
4075 /* Should I clip?
4076 * a) WINED3DRS_CLIPPING is enabled
4077 * b) WINED3DVOP_CLIP is passed
4079 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4080 static BOOL warned = FALSE;
4082 * The clipping code is not quite correct. Some things need
4083 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4084 * so disable clipping for now.
4085 * (The graphics in Half-Life are broken, and my processvertices
4086 * test crashes with IDirect3DDevice3)
4087 doClip = TRUE;
4089 doClip = FALSE;
4090 if(!warned) {
4091 warned = TRUE;
4092 FIXME("Clipping is broken and disabled for now\n");
4094 } else doClip = FALSE;
4095 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4097 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4098 WINED3DTS_VIEW,
4099 &view_mat);
4100 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4101 WINED3DTS_PROJECTION,
4102 &proj_mat);
4103 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4104 WINED3DTS_WORLDMATRIX(0),
4105 &world_mat);
4107 TRACE("View mat:\n");
4108 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);
4109 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);
4110 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);
4111 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);
4113 TRACE("Proj mat:\n");
4114 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);
4115 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);
4116 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);
4117 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);
4119 TRACE("World mat:\n");
4120 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);
4121 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);
4122 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);
4123 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);
4125 /* Get the viewport */
4126 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4127 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4128 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4130 multiply_matrix(&mat,&view_mat,&world_mat);
4131 multiply_matrix(&mat,&proj_mat,&mat);
4133 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4135 for (i = 0; i < dwCount; i+= 1) {
4136 unsigned int tex_index;
4138 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4139 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4140 /* The position first */
4141 const float *p =
4142 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4143 float x, y, z, rhw;
4144 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4146 /* Multiplication with world, view and projection matrix */
4147 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);
4148 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);
4149 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);
4150 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);
4152 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4154 /* WARNING: The following things are taken from d3d7 and were not yet checked
4155 * against d3d8 or d3d9!
4158 /* Clipping conditions: From msdn
4160 * A vertex is clipped if it does not match the following requirements
4161 * -rhw < x <= rhw
4162 * -rhw < y <= rhw
4163 * 0 < z <= rhw
4164 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4166 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4167 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4171 if( !doClip ||
4172 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4173 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4174 ( rhw > eps ) ) ) {
4176 /* "Normal" viewport transformation (not clipped)
4177 * 1) The values are divided by rhw
4178 * 2) The y axis is negative, so multiply it with -1
4179 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4180 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4181 * 4) Multiply x with Width/2 and add Width/2
4182 * 5) The same for the height
4183 * 6) Add the viewpoint X and Y to the 2D coordinates and
4184 * The minimum Z value to z
4185 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4187 * Well, basically it's simply a linear transformation into viewport
4188 * coordinates
4191 x /= rhw;
4192 y /= rhw;
4193 z /= rhw;
4195 y *= -1;
4197 x *= vp.Width / 2;
4198 y *= vp.Height / 2;
4199 z *= vp.MaxZ - vp.MinZ;
4201 x += vp.Width / 2 + vp.X;
4202 y += vp.Height / 2 + vp.Y;
4203 z += vp.MinZ;
4205 rhw = 1 / rhw;
4206 } else {
4207 /* That vertex got clipped
4208 * Contrary to OpenGL it is not dropped completely, it just
4209 * undergoes a different calculation.
4211 TRACE("Vertex got clipped\n");
4212 x += rhw;
4213 y += rhw;
4215 x /= 2;
4216 y /= 2;
4218 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4219 * outside of the main vertex buffer memory. That needs some more
4220 * investigation...
4224 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4227 ( (float *) dest_ptr)[0] = x;
4228 ( (float *) dest_ptr)[1] = y;
4229 ( (float *) dest_ptr)[2] = z;
4230 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4232 dest_ptr += 3 * sizeof(float);
4234 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4235 dest_ptr += sizeof(float);
4238 if(dest_conv) {
4239 float w = 1 / rhw;
4240 ( (float *) dest_conv)[0] = x * w;
4241 ( (float *) dest_conv)[1] = y * w;
4242 ( (float *) dest_conv)[2] = z * w;
4243 ( (float *) dest_conv)[3] = w;
4245 dest_conv += 3 * sizeof(float);
4247 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4248 dest_conv += sizeof(float);
4252 if (DestFVF & WINED3DFVF_PSIZE) {
4253 dest_ptr += sizeof(DWORD);
4254 if(dest_conv) dest_conv += sizeof(DWORD);
4256 if (DestFVF & WINED3DFVF_NORMAL) {
4257 const float *normal =
4258 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4259 /* AFAIK this should go into the lighting information */
4260 FIXME("Didn't expect the destination to have a normal\n");
4261 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4262 if(dest_conv) {
4263 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4267 if (DestFVF & WINED3DFVF_DIFFUSE) {
4268 const DWORD *color_d =
4269 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4270 if(!color_d) {
4271 static BOOL warned = FALSE;
4273 if(!warned) {
4274 ERR("No diffuse color in source, but destination has one\n");
4275 warned = TRUE;
4278 *( (DWORD *) dest_ptr) = 0xffffffff;
4279 dest_ptr += sizeof(DWORD);
4281 if(dest_conv) {
4282 *( (DWORD *) dest_conv) = 0xffffffff;
4283 dest_conv += sizeof(DWORD);
4286 else {
4287 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4288 if(dest_conv) {
4289 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4290 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4291 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4292 dest_conv += sizeof(DWORD);
4297 if (DestFVF & WINED3DFVF_SPECULAR) {
4298 /* What's the color value in the feedback buffer? */
4299 const DWORD *color_s =
4300 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4301 if(!color_s) {
4302 static BOOL warned = FALSE;
4304 if(!warned) {
4305 ERR("No specular color in source, but destination has one\n");
4306 warned = TRUE;
4309 *( (DWORD *) dest_ptr) = 0xFF000000;
4310 dest_ptr += sizeof(DWORD);
4312 if(dest_conv) {
4313 *( (DWORD *) dest_conv) = 0xFF000000;
4314 dest_conv += sizeof(DWORD);
4317 else {
4318 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4319 if(dest_conv) {
4320 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4321 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4322 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4323 dest_conv += sizeof(DWORD);
4328 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4329 const float *tex_coord =
4330 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4331 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4332 if(!tex_coord) {
4333 ERR("No source texture, but destination requests one\n");
4334 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4335 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4337 else {
4338 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4339 if(dest_conv) {
4340 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4346 if(dest_conv) {
4347 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4348 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4349 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4350 dwCount * get_flexible_vertex_size(DestFVF),
4351 dest_conv_addr));
4352 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4353 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4356 LEAVE_GL();
4358 return WINED3D_OK;
4360 #undef copy_and_next
4362 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4364 WineDirect3DVertexStridedData strided;
4365 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4366 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4368 if(pVertexDecl) {
4369 ERR("Output vertex declaration not implemented yet\n");
4372 /* Need any context to write to the vbo. */
4373 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4375 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4376 * control the streamIsUP flag, thus restore it afterwards.
4378 This->stateBlock->streamIsUP = FALSE;
4379 memset(&strided, 0, sizeof(strided));
4380 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4381 This->stateBlock->streamIsUP = streamWasUP;
4383 if(vbo || SrcStartIndex) {
4384 unsigned int i;
4385 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4386 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4388 * Also get the start index in, but only loop over all elements if there's something to add at all.
4390 #define FIXSRC(type) \
4391 if(strided.u.s.type.VBO) { \
4392 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4393 strided.u.s.type.VBO = 0; \
4394 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4395 ENTER_GL(); \
4396 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4397 vb->vbo = 0; \
4398 LEAVE_GL(); \
4400 if(strided.u.s.type.lpData) { \
4401 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4403 FIXSRC(position);
4404 FIXSRC(blendWeights);
4405 FIXSRC(blendMatrixIndices);
4406 FIXSRC(normal);
4407 FIXSRC(pSize);
4408 FIXSRC(diffuse);
4409 FIXSRC(specular);
4410 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4411 FIXSRC(texCoords[i]);
4413 FIXSRC(position2);
4414 FIXSRC(normal2);
4415 FIXSRC(tangent);
4416 FIXSRC(binormal);
4417 FIXSRC(tessFactor);
4418 FIXSRC(fog);
4419 FIXSRC(depth);
4420 FIXSRC(sample);
4421 #undef FIXSRC
4424 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4427 /*****
4428 * Get / Set Texture Stage States
4429 * TODO: Verify against dx9 definitions
4430 *****/
4431 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4433 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4435 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4437 if (Stage >= MAX_TEXTURES) {
4438 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4439 return WINED3D_OK;
4442 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4443 This->updateStateBlock->textureState[Stage][Type] = Value;
4445 if (This->isRecordingState) {
4446 TRACE("Recording... not performing anything\n");
4447 return WINED3D_OK;
4450 /* Checked after the assignments to allow proper stateblock recording */
4451 if(oldValue == Value) {
4452 TRACE("App is setting the old value over, nothing to do\n");
4453 return WINED3D_OK;
4456 if(Stage > This->stateBlock->lowest_disabled_stage &&
4457 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4458 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4459 * Changes in other states are important on disabled stages too
4461 return WINED3D_OK;
4464 if(Type == WINED3DTSS_COLOROP) {
4465 int i;
4467 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4468 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4469 * they have to be disabled
4471 * The current stage is dirtified below.
4473 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4474 TRACE("Additionally dirtifying stage %d\n", i);
4475 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4477 This->stateBlock->lowest_disabled_stage = Stage;
4478 TRACE("New lowest disabled: %d\n", Stage);
4479 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4480 /* Previously disabled stage enabled. Stages above it may need enabling
4481 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4482 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4484 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4487 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4488 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4489 break;
4491 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4492 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4494 This->stateBlock->lowest_disabled_stage = i;
4495 TRACE("New lowest disabled: %d\n", i);
4499 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4501 return WINED3D_OK;
4504 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4506 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4507 *pValue = This->updateStateBlock->textureState[Stage][Type];
4508 return WINED3D_OK;
4511 /*****
4512 * Get / Set Texture
4513 *****/
4514 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4516 IWineD3DBaseTexture *oldTexture;
4518 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4520 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4521 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4524 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4525 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4526 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4529 oldTexture = This->updateStateBlock->textures[Stage];
4531 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4532 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4534 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4535 return WINED3DERR_INVALIDCALL;
4538 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4539 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4541 This->updateStateBlock->changed.textures[Stage] = TRUE;
4542 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4543 This->updateStateBlock->textures[Stage] = pTexture;
4545 /* Handle recording of state blocks */
4546 if (This->isRecordingState) {
4547 TRACE("Recording... not performing anything\n");
4548 return WINED3D_OK;
4551 if(oldTexture == pTexture) {
4552 TRACE("App is setting the same texture again, nothing to do\n");
4553 return WINED3D_OK;
4556 /** NOTE: MSDN says that setTexture increases the reference count,
4557 * and that the application must set the texture back to null (or have a leaky application),
4558 * This means we should pass the refcount up to the parent
4559 *******************************/
4560 if (NULL != This->updateStateBlock->textures[Stage]) {
4561 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4562 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4564 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4565 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4566 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4567 * so the COLOROP and ALPHAOP have to be dirtified.
4569 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4570 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4572 if(bindCount == 1) {
4573 new->baseTexture.sampler = Stage;
4575 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4579 if (NULL != oldTexture) {
4580 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4581 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4583 IWineD3DBaseTexture_Release(oldTexture);
4584 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4585 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4586 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4589 if(bindCount && old->baseTexture.sampler == Stage) {
4590 int i;
4591 /* Have to do a search for the other sampler(s) where the texture is bound to
4592 * Shouldn't happen as long as apps bind a texture only to one stage
4594 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4595 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4596 if(This->updateStateBlock->textures[i] == oldTexture) {
4597 old->baseTexture.sampler = i;
4598 break;
4604 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4606 return WINED3D_OK;
4609 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4612 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4614 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4615 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4618 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4619 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4620 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4623 *ppTexture=This->stateBlock->textures[Stage];
4624 if (*ppTexture)
4625 IWineD3DBaseTexture_AddRef(*ppTexture);
4627 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4629 return WINED3D_OK;
4632 /*****
4633 * Get Back Buffer
4634 *****/
4635 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4636 IWineD3DSurface **ppBackBuffer) {
4637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4638 IWineD3DSwapChain *swapChain;
4639 HRESULT hr;
4641 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4643 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4644 if (hr == WINED3D_OK) {
4645 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4646 IWineD3DSwapChain_Release(swapChain);
4647 } else {
4648 *ppBackBuffer = NULL;
4650 return hr;
4653 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4655 WARN("(%p) : stub, calling idirect3d for now\n", This);
4656 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4659 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4661 IWineD3DSwapChain *swapChain;
4662 HRESULT hr;
4664 if(iSwapChain > 0) {
4665 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4666 if (hr == WINED3D_OK) {
4667 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4668 IWineD3DSwapChain_Release(swapChain);
4669 } else {
4670 FIXME("(%p) Error getting display mode\n", This);
4672 } else {
4673 /* Don't read the real display mode,
4674 but return the stored mode instead. X11 can't change the color
4675 depth, and some apps are pretty angry if they SetDisplayMode from
4676 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4678 Also don't relay to the swapchain because with ddraw it's possible
4679 that there isn't a swapchain at all */
4680 pMode->Width = This->ddraw_width;
4681 pMode->Height = This->ddraw_height;
4682 pMode->Format = This->ddraw_format;
4683 pMode->RefreshRate = 0;
4684 hr = WINED3D_OK;
4687 return hr;
4690 /*****
4691 * Stateblock related functions
4692 *****/
4694 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4695 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4696 IWineD3DStateBlockImpl *object;
4697 HRESULT temp_result;
4698 int i;
4700 TRACE("(%p)\n", This);
4702 if (This->isRecordingState) {
4703 return WINED3DERR_INVALIDCALL;
4706 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4707 if (NULL == object ) {
4708 FIXME("(%p)Error allocating memory for stateblock\n", This);
4709 return E_OUTOFMEMORY;
4711 TRACE("(%p) created object %p\n", This, object);
4712 object->wineD3DDevice= This;
4713 /** FIXME: object->parent = parent; **/
4714 object->parent = NULL;
4715 object->blockType = WINED3DSBT_RECORDED;
4716 object->ref = 1;
4717 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4719 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4720 list_init(&object->lightMap[i]);
4723 temp_result = allocate_shader_constants(object);
4724 if (WINED3D_OK != temp_result)
4725 return temp_result;
4727 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4728 This->updateStateBlock = object;
4729 This->isRecordingState = TRUE;
4731 TRACE("(%p) recording stateblock %p\n",This , object);
4732 return WINED3D_OK;
4735 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4737 unsigned int i, j;
4738 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4740 if (!This->isRecordingState) {
4741 FIXME("(%p) not recording! returning error\n", This);
4742 *ppStateBlock = NULL;
4743 return WINED3DERR_INVALIDCALL;
4746 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4747 if(object->changed.renderState[i]) {
4748 object->contained_render_states[object->num_contained_render_states] = i;
4749 object->num_contained_render_states++;
4752 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4753 if(object->changed.transform[i]) {
4754 object->contained_transform_states[object->num_contained_transform_states] = i;
4755 object->num_contained_transform_states++;
4758 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4759 if(object->changed.vertexShaderConstantsF[i]) {
4760 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4761 object->num_contained_vs_consts_f++;
4764 for(i = 0; i < MAX_CONST_I; i++) {
4765 if (object->changed.vertexShaderConstantsI & (1 << i))
4767 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4768 object->num_contained_vs_consts_i++;
4771 for(i = 0; i < MAX_CONST_B; i++) {
4772 if (object->changed.vertexShaderConstantsB & (1 << i))
4774 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4775 object->num_contained_vs_consts_b++;
4778 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4780 if (object->changed.pixelShaderConstantsF[i])
4782 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4783 ++object->num_contained_ps_consts_f;
4786 for(i = 0; i < MAX_CONST_I; i++) {
4787 if (object->changed.pixelShaderConstantsI & (1 << i))
4789 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4790 object->num_contained_ps_consts_i++;
4793 for(i = 0; i < MAX_CONST_B; i++) {
4794 if (object->changed.pixelShaderConstantsB & (1 << i))
4796 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4797 object->num_contained_ps_consts_b++;
4800 for(i = 0; i < MAX_TEXTURES; i++) {
4801 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4802 if(object->changed.textureState[i][j]) {
4803 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4804 object->contained_tss_states[object->num_contained_tss_states].state = j;
4805 object->num_contained_tss_states++;
4809 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4810 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4811 if(object->changed.samplerState[i][j]) {
4812 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4813 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4814 object->num_contained_sampler_states++;
4819 *ppStateBlock = (IWineD3DStateBlock*) object;
4820 This->isRecordingState = FALSE;
4821 This->updateStateBlock = This->stateBlock;
4822 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4823 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4824 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4825 return WINED3D_OK;
4828 /*****
4829 * Scene related functions
4830 *****/
4831 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4832 /* At the moment we have no need for any functionality at the beginning
4833 of a scene */
4834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4835 TRACE("(%p)\n", This);
4837 if(This->inScene) {
4838 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4839 return WINED3DERR_INVALIDCALL;
4841 This->inScene = TRUE;
4842 return WINED3D_OK;
4845 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4847 TRACE("(%p)\n", This);
4849 if(!This->inScene) {
4850 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4851 return WINED3DERR_INVALIDCALL;
4854 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4855 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4856 glFlush();
4857 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4858 * fails
4861 This->inScene = FALSE;
4862 return WINED3D_OK;
4865 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4866 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4867 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4869 IWineD3DSwapChain *swapChain = NULL;
4870 int i;
4871 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4873 TRACE("(%p) Presenting the frame\n", This);
4875 for(i = 0 ; i < swapchains ; i ++) {
4877 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4878 TRACE("presentinng chain %d, %p\n", i, swapChain);
4879 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4880 IWineD3DSwapChain_Release(swapChain);
4883 return WINED3D_OK;
4886 /* Not called from the VTable (internal subroutine) */
4887 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4888 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4889 float Z, DWORD Stencil) {
4890 GLbitfield glMask = 0;
4891 unsigned int i;
4892 WINED3DRECT curRect;
4893 RECT vp_rect;
4894 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4895 UINT drawable_width, drawable_height;
4896 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4897 IWineD3DSwapChainImpl *swapchain = NULL;
4899 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4900 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4901 * for the cleared parts, and the untouched parts.
4903 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4904 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4905 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4906 * checking all this if the dest surface is in the drawable anyway.
4908 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4909 while(1) {
4910 if(vp->X != 0 || vp->Y != 0 ||
4911 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4912 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4913 break;
4915 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4916 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4917 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4918 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4919 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4920 break;
4922 if(Count > 0 && pRects && (
4923 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4924 pRects[0].x2 < target->currentDesc.Width ||
4925 pRects[0].y2 < target->currentDesc.Height)) {
4926 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4927 break;
4929 break;
4933 target->get_drawable_size(target, &drawable_width, &drawable_height);
4935 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4936 ENTER_GL();
4938 /* Only set the values up once, as they are not changing */
4939 if (Flags & WINED3DCLEAR_STENCIL) {
4940 glClearStencil(Stencil);
4941 checkGLcall("glClearStencil");
4942 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4943 glStencilMask(0xFFFFFFFF);
4946 if (Flags & WINED3DCLEAR_ZBUFFER) {
4947 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4948 glDepthMask(GL_TRUE);
4949 glClearDepth(Z);
4950 checkGLcall("glClearDepth");
4951 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4952 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4954 if (vp->X != 0 || vp->Y != 0 ||
4955 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4956 surface_load_ds_location(This->stencilBufferTarget, location);
4958 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4959 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4960 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4961 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4962 surface_load_ds_location(This->stencilBufferTarget, location);
4964 else if (Count > 0 && pRects && (
4965 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4966 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4967 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4968 surface_load_ds_location(This->stencilBufferTarget, location);
4972 if (Flags & WINED3DCLEAR_TARGET) {
4973 TRACE("Clearing screen with glClear to color %x\n", Color);
4974 glClearColor(D3DCOLOR_R(Color),
4975 D3DCOLOR_G(Color),
4976 D3DCOLOR_B(Color),
4977 D3DCOLOR_A(Color));
4978 checkGLcall("glClearColor");
4980 /* Clear ALL colors! */
4981 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4982 glMask = glMask | GL_COLOR_BUFFER_BIT;
4985 vp_rect.left = vp->X;
4986 vp_rect.top = vp->Y;
4987 vp_rect.right = vp->X + vp->Width;
4988 vp_rect.bottom = vp->Y + vp->Height;
4989 if (!(Count > 0 && pRects)) {
4990 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4991 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4993 if(This->render_offscreen) {
4994 glScissor(vp_rect.left, vp_rect.top,
4995 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4996 } else {
4997 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4998 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5000 checkGLcall("glScissor");
5001 glClear(glMask);
5002 checkGLcall("glClear");
5003 } else {
5004 /* Now process each rect in turn */
5005 for (i = 0; i < Count; i++) {
5006 /* Note gl uses lower left, width/height */
5007 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5008 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5009 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5011 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5012 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5013 curRect.x1, (target->currentDesc.Height - curRect.y2),
5014 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5016 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5017 * The rectangle is not cleared, no error is returned, but further rectanlges are
5018 * still cleared if they are valid
5020 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5021 TRACE("Rectangle with negative dimensions, ignoring\n");
5022 continue;
5025 if(This->render_offscreen) {
5026 glScissor(curRect.x1, curRect.y1,
5027 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5028 } else {
5029 glScissor(curRect.x1, drawable_height - curRect.y2,
5030 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5032 checkGLcall("glScissor");
5034 glClear(glMask);
5035 checkGLcall("glClear");
5039 /* Restore the old values (why..?) */
5040 if (Flags & WINED3DCLEAR_STENCIL) {
5041 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5043 if (Flags & WINED3DCLEAR_TARGET) {
5044 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5045 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5046 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5047 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5048 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5050 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5051 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5053 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5055 if (Flags & WINED3DCLEAR_ZBUFFER) {
5056 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5057 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5058 surface_modify_ds_location(This->stencilBufferTarget, location);
5061 LEAVE_GL();
5063 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5064 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5065 glFlush();
5067 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5070 return WINED3D_OK;
5073 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5074 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5076 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5078 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5079 Count, pRects, Flags, Color, Z, Stencil);
5081 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5082 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5083 /* TODO: What about depth stencil buffers without stencil bits? */
5084 return WINED3DERR_INVALIDCALL;
5087 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5090 /*****
5091 * Drawing functions
5092 *****/
5093 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5094 UINT PrimitiveCount) {
5096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5098 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5099 debug_d3dprimitivetype(PrimitiveType),
5100 StartVertex, PrimitiveCount);
5102 if(!This->stateBlock->vertexDecl) {
5103 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5104 return WINED3DERR_INVALIDCALL;
5107 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5108 if(This->stateBlock->streamIsUP) {
5109 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5110 This->stateBlock->streamIsUP = FALSE;
5113 if(This->stateBlock->loadBaseVertexIndex != 0) {
5114 This->stateBlock->loadBaseVertexIndex = 0;
5115 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5117 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5118 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5119 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5120 return WINED3D_OK;
5123 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5124 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5125 WINED3DPRIMITIVETYPE PrimitiveType,
5126 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5129 UINT idxStride = 2;
5130 IWineD3DIndexBuffer *pIB;
5131 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5132 GLuint vbo;
5134 pIB = This->stateBlock->pIndexData;
5135 if (!pIB) {
5136 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5137 * without an index buffer set. (The first time at least...)
5138 * D3D8 simply dies, but I doubt it can do much harm to return
5139 * D3DERR_INVALIDCALL there as well. */
5140 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5141 return WINED3DERR_INVALIDCALL;
5144 if(!This->stateBlock->vertexDecl) {
5145 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5146 return WINED3DERR_INVALIDCALL;
5149 if(This->stateBlock->streamIsUP) {
5150 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5151 This->stateBlock->streamIsUP = FALSE;
5153 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5155 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5156 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5157 minIndex, NumVertices, startIndex, primCount);
5159 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5160 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5161 idxStride = 2;
5162 } else {
5163 idxStride = 4;
5166 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5167 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5168 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5171 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5172 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5174 return WINED3D_OK;
5177 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5178 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5179 UINT VertexStreamZeroStride) {
5180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5181 IWineD3DVertexBuffer *vb;
5183 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5184 debug_d3dprimitivetype(PrimitiveType),
5185 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5187 if(!This->stateBlock->vertexDecl) {
5188 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5189 return WINED3DERR_INVALIDCALL;
5192 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5193 vb = This->stateBlock->streamSource[0];
5194 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5195 if(vb) IWineD3DVertexBuffer_Release(vb);
5196 This->stateBlock->streamOffset[0] = 0;
5197 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5198 This->stateBlock->streamIsUP = TRUE;
5199 This->stateBlock->loadBaseVertexIndex = 0;
5201 /* TODO: Only mark dirty if drawing from a different UP address */
5202 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5204 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5205 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5207 /* MSDN specifies stream zero settings must be set to NULL */
5208 This->stateBlock->streamStride[0] = 0;
5209 This->stateBlock->streamSource[0] = NULL;
5211 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5212 * the new stream sources or use UP drawing again
5214 return WINED3D_OK;
5217 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5218 UINT MinVertexIndex, UINT NumVertices,
5219 UINT PrimitiveCount, CONST void* pIndexData,
5220 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5221 UINT VertexStreamZeroStride) {
5222 int idxStride;
5223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5224 IWineD3DVertexBuffer *vb;
5225 IWineD3DIndexBuffer *ib;
5227 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5228 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5229 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5230 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5232 if(!This->stateBlock->vertexDecl) {
5233 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5234 return WINED3DERR_INVALIDCALL;
5237 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5238 idxStride = 2;
5239 } else {
5240 idxStride = 4;
5243 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5244 vb = This->stateBlock->streamSource[0];
5245 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5246 if(vb) IWineD3DVertexBuffer_Release(vb);
5247 This->stateBlock->streamIsUP = TRUE;
5248 This->stateBlock->streamOffset[0] = 0;
5249 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5251 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5252 This->stateBlock->baseVertexIndex = 0;
5253 This->stateBlock->loadBaseVertexIndex = 0;
5254 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5255 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5256 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5258 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5260 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5261 This->stateBlock->streamSource[0] = NULL;
5262 This->stateBlock->streamStride[0] = 0;
5263 ib = This->stateBlock->pIndexData;
5264 if(ib) {
5265 IWineD3DIndexBuffer_Release(ib);
5266 This->stateBlock->pIndexData = NULL;
5268 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5269 * SetStreamSource to specify a vertex buffer
5272 return WINED3D_OK;
5275 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5276 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5277 const WineDirect3DVertexStridedData *DrawPrimStrideData)
5279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5281 /* Mark the state dirty until we have nicer tracking
5282 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5283 * that value.
5285 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5286 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5287 This->stateBlock->baseVertexIndex = 0;
5288 This->up_strided = DrawPrimStrideData;
5289 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5290 This->up_strided = NULL;
5291 return WINED3D_OK;
5294 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5295 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5296 const WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, const void *pIndexData,
5297 WINED3DFORMAT IndexDataFormat)
5299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5300 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5302 /* Mark the state dirty until we have nicer tracking
5303 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5304 * that value.
5306 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5307 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5308 This->stateBlock->streamIsUP = TRUE;
5309 This->stateBlock->baseVertexIndex = 0;
5310 This->up_strided = DrawPrimStrideData;
5311 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5312 This->up_strided = NULL;
5313 return WINED3D_OK;
5316 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5317 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5318 * not callable by the app directly no parameter validation checks are needed here.
5320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5321 WINED3DLOCKED_BOX src;
5322 WINED3DLOCKED_BOX dst;
5323 HRESULT hr;
5324 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5326 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5327 * dirtification to improve loading performance.
5329 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5330 if(FAILED(hr)) return hr;
5331 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5332 if(FAILED(hr)) {
5333 IWineD3DVolume_UnlockBox(pSourceVolume);
5334 return hr;
5337 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5339 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5340 if(FAILED(hr)) {
5341 IWineD3DVolume_UnlockBox(pSourceVolume);
5342 } else {
5343 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5345 return hr;
5348 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5349 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5351 HRESULT hr = WINED3D_OK;
5352 WINED3DRESOURCETYPE sourceType;
5353 WINED3DRESOURCETYPE destinationType;
5354 int i ,levels;
5356 /* TODO: think about moving the code into IWineD3DBaseTexture */
5358 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5360 /* verify that the source and destination textures aren't NULL */
5361 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5362 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5363 This, pSourceTexture, pDestinationTexture);
5364 hr = WINED3DERR_INVALIDCALL;
5367 if (pSourceTexture == pDestinationTexture) {
5368 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5369 This, pSourceTexture, pDestinationTexture);
5370 hr = WINED3DERR_INVALIDCALL;
5372 /* Verify that the source and destination textures are the same type */
5373 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5374 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5376 if (sourceType != destinationType) {
5377 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5378 This);
5379 hr = WINED3DERR_INVALIDCALL;
5382 /* check that both textures have the identical numbers of levels */
5383 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5384 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5385 hr = WINED3DERR_INVALIDCALL;
5388 if (WINED3D_OK == hr) {
5390 /* Make sure that the destination texture is loaded */
5391 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5393 /* Update every surface level of the texture */
5394 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5396 switch (sourceType) {
5397 case WINED3DRTYPE_TEXTURE:
5399 IWineD3DSurface *srcSurface;
5400 IWineD3DSurface *destSurface;
5402 for (i = 0 ; i < levels ; ++i) {
5403 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5404 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5405 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5406 IWineD3DSurface_Release(srcSurface);
5407 IWineD3DSurface_Release(destSurface);
5408 if (WINED3D_OK != hr) {
5409 WARN("(%p) : Call to update surface failed\n", This);
5410 return hr;
5414 break;
5415 case WINED3DRTYPE_CUBETEXTURE:
5417 IWineD3DSurface *srcSurface;
5418 IWineD3DSurface *destSurface;
5419 WINED3DCUBEMAP_FACES faceType;
5421 for (i = 0 ; i < levels ; ++i) {
5422 /* Update each cube face */
5423 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5424 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5425 if (WINED3D_OK != hr) {
5426 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5427 } else {
5428 TRACE("Got srcSurface %p\n", srcSurface);
5430 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5431 if (WINED3D_OK != hr) {
5432 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5433 } else {
5434 TRACE("Got desrSurface %p\n", destSurface);
5436 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5437 IWineD3DSurface_Release(srcSurface);
5438 IWineD3DSurface_Release(destSurface);
5439 if (WINED3D_OK != hr) {
5440 WARN("(%p) : Call to update surface failed\n", This);
5441 return hr;
5446 break;
5448 case WINED3DRTYPE_VOLUMETEXTURE:
5450 IWineD3DVolume *srcVolume = NULL;
5451 IWineD3DVolume *destVolume = NULL;
5453 for (i = 0 ; i < levels ; ++i) {
5454 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5455 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5456 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5457 IWineD3DVolume_Release(srcVolume);
5458 IWineD3DVolume_Release(destVolume);
5459 if (WINED3D_OK != hr) {
5460 WARN("(%p) : Call to update volume failed\n", This);
5461 return hr;
5465 break;
5467 default:
5468 FIXME("(%p) : Unsupported source and destination type\n", This);
5469 hr = WINED3DERR_INVALIDCALL;
5473 return hr;
5476 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5477 IWineD3DSwapChain *swapChain;
5478 HRESULT hr;
5479 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5480 if(hr == WINED3D_OK) {
5481 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5482 IWineD3DSwapChain_Release(swapChain);
5484 return hr;
5487 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5489 IWineD3DBaseTextureImpl *texture;
5490 const struct GlPixelFormatDesc *gl_info;
5491 DWORD i;
5493 TRACE("(%p) : %p\n", This, pNumPasses);
5495 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5496 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5497 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5498 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5500 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5501 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5502 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5505 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5506 if(!texture) continue;
5507 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5508 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5510 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5511 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5512 return E_FAIL;
5514 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5515 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5516 return E_FAIL;
5518 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5519 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5520 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5521 return E_FAIL;
5525 /* return a sensible default */
5526 *pNumPasses = 1;
5528 TRACE("returning D3D_OK\n");
5529 return WINED3D_OK;
5532 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5534 int i;
5536 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5537 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5538 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5539 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5544 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5546 int j;
5547 UINT NewSize;
5548 PALETTEENTRY **palettes;
5550 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5552 if (PaletteNumber >= MAX_PALETTES) {
5553 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5554 return WINED3DERR_INVALIDCALL;
5557 if (PaletteNumber >= This->NumberOfPalettes) {
5558 NewSize = This->NumberOfPalettes;
5559 do {
5560 NewSize *= 2;
5561 } while(PaletteNumber >= NewSize);
5562 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5563 if (!palettes) {
5564 ERR("Out of memory!\n");
5565 return E_OUTOFMEMORY;
5567 This->palettes = palettes;
5568 This->NumberOfPalettes = NewSize;
5571 if (!This->palettes[PaletteNumber]) {
5572 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5573 if (!This->palettes[PaletteNumber]) {
5574 ERR("Out of memory!\n");
5575 return E_OUTOFMEMORY;
5579 for (j = 0; j < 256; ++j) {
5580 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5581 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5582 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5583 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5585 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5586 TRACE("(%p) : returning\n", This);
5587 return WINED3D_OK;
5590 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5592 int j;
5593 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5594 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5595 /* What happens in such situation isn't documented; Native seems to silently abort
5596 on such conditions. Return Invalid Call. */
5597 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5598 return WINED3DERR_INVALIDCALL;
5600 for (j = 0; j < 256; ++j) {
5601 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5602 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5603 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5604 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5606 TRACE("(%p) : returning\n", This);
5607 return WINED3D_OK;
5610 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5612 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5613 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5614 (tested with reference rasterizer). Return Invalid Call. */
5615 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5616 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5617 return WINED3DERR_INVALIDCALL;
5619 /*TODO: stateblocks */
5620 if (This->currentPalette != PaletteNumber) {
5621 This->currentPalette = PaletteNumber;
5622 dirtify_p8_texture_samplers(This);
5624 TRACE("(%p) : returning\n", This);
5625 return WINED3D_OK;
5628 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5630 if (PaletteNumber == NULL) {
5631 WARN("(%p) : returning Invalid Call\n", This);
5632 return WINED3DERR_INVALIDCALL;
5634 /*TODO: stateblocks */
5635 *PaletteNumber = This->currentPalette;
5636 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5637 return WINED3D_OK;
5640 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5642 static BOOL warned;
5643 if (!warned)
5645 FIXME("(%p) : stub\n", This);
5646 warned = TRUE;
5649 This->softwareVertexProcessing = bSoftware;
5650 return WINED3D_OK;
5654 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5656 static BOOL warned;
5657 if (!warned)
5659 FIXME("(%p) : stub\n", This);
5660 warned = TRUE;
5662 return This->softwareVertexProcessing;
5666 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5668 IWineD3DSwapChain *swapChain;
5669 HRESULT hr;
5671 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5673 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5674 if(hr == WINED3D_OK){
5675 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5676 IWineD3DSwapChain_Release(swapChain);
5677 }else{
5678 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5680 return hr;
5684 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5686 static BOOL warned;
5687 if(nSegments != 0.0f) {
5688 if (!warned)
5690 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5691 warned = TRUE;
5694 return WINED3D_OK;
5697 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5699 static BOOL warned;
5700 if (!warned)
5702 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5703 warned = TRUE;
5705 return 0.0f;
5708 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5710 /** TODO: remove casts to IWineD3DSurfaceImpl
5711 * NOTE: move code to surface to accomplish this
5712 ****************************************/
5713 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5714 int srcWidth, srcHeight;
5715 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5716 WINED3DFORMAT destFormat, srcFormat;
5717 UINT destSize;
5718 int srcLeft, destLeft, destTop;
5719 WINED3DPOOL srcPool, destPool;
5720 int offset = 0;
5721 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5722 glDescriptor *glDescription = NULL;
5723 GLenum dummy;
5724 int sampler;
5725 int bpp;
5726 CONVERT_TYPES convert = NO_CONVERSION;
5728 WINED3DSURFACE_DESC winedesc;
5730 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5731 memset(&winedesc, 0, sizeof(winedesc));
5732 winedesc.Width = &srcSurfaceWidth;
5733 winedesc.Height = &srcSurfaceHeight;
5734 winedesc.Pool = &srcPool;
5735 winedesc.Format = &srcFormat;
5737 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5739 winedesc.Width = &destSurfaceWidth;
5740 winedesc.Height = &destSurfaceHeight;
5741 winedesc.Pool = &destPool;
5742 winedesc.Format = &destFormat;
5743 winedesc.Size = &destSize;
5745 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5747 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5748 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5749 return WINED3DERR_INVALIDCALL;
5752 /* This call loads the opengl surface directly, instead of copying the surface to the
5753 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5754 * copy in sysmem and use regular surface loading.
5756 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5757 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5758 if(convert != NO_CONVERSION) {
5759 return IWineD3DSurface_BltFast(pDestinationSurface,
5760 pDestPoint ? pDestPoint->x : 0,
5761 pDestPoint ? pDestPoint->y : 0,
5762 pSourceSurface, pSourceRect, 0);
5765 if (destFormat == WINED3DFMT_UNKNOWN) {
5766 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5767 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5769 /* Get the update surface description */
5770 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5773 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5775 ENTER_GL();
5776 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5777 checkGLcall("glActiveTextureARB");
5778 LEAVE_GL();
5780 /* Make sure the surface is loaded and up to date */
5781 IWineD3DSurface_PreLoad(pDestinationSurface);
5782 IWineD3DSurface_BindTexture(pDestinationSurface);
5784 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5786 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5787 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5788 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5789 srcLeft = pSourceRect ? pSourceRect->left : 0;
5790 destLeft = pDestPoint ? pDestPoint->x : 0;
5791 destTop = pDestPoint ? pDestPoint->y : 0;
5794 /* This function doesn't support compressed textures
5795 the pitch is just bytesPerPixel * width */
5796 if(srcWidth != srcSurfaceWidth || srcLeft ){
5797 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5798 offset += srcLeft * pSrcSurface->bytesPerPixel;
5799 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5801 /* TODO DXT formats */
5803 if(pSourceRect != NULL && pSourceRect->top != 0){
5804 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5806 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5807 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat,
5808 glDescription->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5810 /* Sanity check */
5811 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5813 /* need to lock the surface to get the data */
5814 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5817 ENTER_GL();
5819 /* TODO: Cube and volume support */
5820 if(rowoffset != 0){
5821 /* not a whole row so we have to do it a line at a time */
5822 int j;
5824 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5825 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5827 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5829 glTexSubImage2D(glDescription->target
5830 ,glDescription->level
5831 ,destLeft
5833 ,srcWidth
5835 ,glDescription->glFormat
5836 ,glDescription->glType
5837 ,data /* could be quicker using */
5839 data += rowoffset;
5842 } else { /* Full width, so just write out the whole texture */
5843 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5845 if (WINED3DFMT_DXT1 == destFormat ||
5846 WINED3DFMT_DXT2 == destFormat ||
5847 WINED3DFMT_DXT3 == destFormat ||
5848 WINED3DFMT_DXT4 == destFormat ||
5849 WINED3DFMT_DXT5 == destFormat) {
5850 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5851 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5852 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5853 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5854 } if (destFormat != srcFormat) {
5855 FIXME("Updating mixed format compressed texture is not curretly support\n");
5856 } else {
5857 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
5858 glDescription->glFormatInternal, srcWidth, srcHeight, 0, destSize, data));
5860 } else {
5861 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5865 } else {
5866 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
5867 srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, data);
5870 checkGLcall("glTexSubImage2D");
5872 LEAVE_GL();
5874 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5875 sampler = This->rev_tex_unit_map[0];
5876 if (sampler != -1) {
5877 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5880 return WINED3D_OK;
5883 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5885 struct WineD3DRectPatch *patch;
5886 unsigned int i;
5887 struct list *e;
5888 BOOL found;
5889 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5891 if(!(Handle || pRectPatchInfo)) {
5892 /* TODO: Write a test for the return value, thus the FIXME */
5893 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5894 return WINED3DERR_INVALIDCALL;
5897 if(Handle) {
5898 i = PATCHMAP_HASHFUNC(Handle);
5899 found = FALSE;
5900 LIST_FOR_EACH(e, &This->patches[i]) {
5901 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5902 if(patch->Handle == Handle) {
5903 found = TRUE;
5904 break;
5908 if(!found) {
5909 TRACE("Patch does not exist. Creating a new one\n");
5910 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5911 patch->Handle = Handle;
5912 list_add_head(&This->patches[i], &patch->entry);
5913 } else {
5914 TRACE("Found existing patch %p\n", patch);
5916 } else {
5917 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5918 * attributes we have to tesselate, read back, and draw. This needs a patch
5919 * management structure instance. Create one.
5921 * A possible improvement is to check if a vertex shader is used, and if not directly
5922 * draw the patch.
5924 FIXME("Drawing an uncached patch. This is slow\n");
5925 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5928 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5929 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5930 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5931 HRESULT hr;
5932 TRACE("Tesselation density or patch info changed, retesselating\n");
5934 if(pRectPatchInfo) {
5935 patch->RectPatchInfo = *pRectPatchInfo;
5937 patch->numSegs[0] = pNumSegs[0];
5938 patch->numSegs[1] = pNumSegs[1];
5939 patch->numSegs[2] = pNumSegs[2];
5940 patch->numSegs[3] = pNumSegs[3];
5942 hr = tesselate_rectpatch(This, patch);
5943 if(FAILED(hr)) {
5944 WARN("Patch tesselation failed\n");
5946 /* Do not release the handle to store the params of the patch */
5947 if(!Handle) {
5948 HeapFree(GetProcessHeap(), 0, patch);
5950 return hr;
5954 This->currentPatch = patch;
5955 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5956 This->currentPatch = NULL;
5958 /* Destroy uncached patches */
5959 if(!Handle) {
5960 HeapFree(GetProcessHeap(), 0, patch->mem);
5961 HeapFree(GetProcessHeap(), 0, patch);
5963 return WINED3D_OK;
5966 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5968 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5969 FIXME("(%p) : Stub\n", This);
5970 return WINED3D_OK;
5973 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5975 int i;
5976 struct WineD3DRectPatch *patch;
5977 struct list *e;
5978 TRACE("(%p) Handle(%d)\n", This, Handle);
5980 i = PATCHMAP_HASHFUNC(Handle);
5981 LIST_FOR_EACH(e, &This->patches[i]) {
5982 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5983 if(patch->Handle == Handle) {
5984 TRACE("Deleting patch %p\n", patch);
5985 list_remove(&patch->entry);
5986 HeapFree(GetProcessHeap(), 0, patch->mem);
5987 HeapFree(GetProcessHeap(), 0, patch);
5988 return WINED3D_OK;
5992 /* TODO: Write a test for the return value */
5993 FIXME("Attempt to destroy nonexistent patch\n");
5994 return WINED3DERR_INVALIDCALL;
5997 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5998 HRESULT hr;
5999 IWineD3DSwapChain *swapchain;
6001 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6002 if (SUCCEEDED(hr)) {
6003 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6004 return swapchain;
6007 return NULL;
6010 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6012 IWineD3DSwapChain *swapchain;
6014 swapchain = get_swapchain(surface);
6015 if (swapchain) {
6016 GLenum buffer;
6018 TRACE("Surface %p is onscreen\n", surface);
6020 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6021 ENTER_GL();
6022 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6023 buffer = surface_get_gl_buffer(surface, swapchain);
6024 glDrawBuffer(buffer);
6025 checkGLcall("glDrawBuffer()");
6026 } else {
6027 TRACE("Surface %p is offscreen\n", surface);
6029 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6030 ENTER_GL();
6031 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6032 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6033 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6034 checkGLcall("glFramebufferRenderbufferEXT");
6037 if (rect) {
6038 glEnable(GL_SCISSOR_TEST);
6039 if(!swapchain) {
6040 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6041 } else {
6042 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6043 rect->x2 - rect->x1, rect->y2 - rect->y1);
6045 checkGLcall("glScissor");
6046 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6047 } else {
6048 glDisable(GL_SCISSOR_TEST);
6050 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6052 glDisable(GL_BLEND);
6053 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6055 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6056 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6058 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6059 glClear(GL_COLOR_BUFFER_BIT);
6060 checkGLcall("glClear");
6062 if (This->activeContext->current_fbo) {
6063 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6064 } else {
6065 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6066 checkGLcall("glBindFramebuffer()");
6069 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6070 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6071 glDrawBuffer(GL_BACK);
6072 checkGLcall("glDrawBuffer()");
6075 LEAVE_GL();
6078 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6079 unsigned int r, g, b, a;
6080 DWORD ret;
6082 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6083 destfmt == WINED3DFMT_R8G8B8)
6084 return color;
6086 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6088 a = (color & 0xff000000) >> 24;
6089 r = (color & 0x00ff0000) >> 16;
6090 g = (color & 0x0000ff00) >> 8;
6091 b = (color & 0x000000ff) >> 0;
6093 switch(destfmt)
6095 case WINED3DFMT_R5G6B5:
6096 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6097 r = (r * 32) / 256;
6098 g = (g * 64) / 256;
6099 b = (b * 32) / 256;
6100 ret = r << 11;
6101 ret |= g << 5;
6102 ret |= b;
6103 TRACE("Returning %08x\n", ret);
6104 return ret;
6106 case WINED3DFMT_X1R5G5B5:
6107 case WINED3DFMT_A1R5G5B5:
6108 a = (a * 2) / 256;
6109 r = (r * 32) / 256;
6110 g = (g * 32) / 256;
6111 b = (b * 32) / 256;
6112 ret = a << 15;
6113 ret |= r << 10;
6114 ret |= g << 5;
6115 ret |= b << 0;
6116 TRACE("Returning %08x\n", ret);
6117 return ret;
6119 case WINED3DFMT_A8:
6120 TRACE("Returning %08x\n", a);
6121 return a;
6123 case WINED3DFMT_X4R4G4B4:
6124 case WINED3DFMT_A4R4G4B4:
6125 a = (a * 16) / 256;
6126 r = (r * 16) / 256;
6127 g = (g * 16) / 256;
6128 b = (b * 16) / 256;
6129 ret = a << 12;
6130 ret |= r << 8;
6131 ret |= g << 4;
6132 ret |= b << 0;
6133 TRACE("Returning %08x\n", ret);
6134 return ret;
6136 case WINED3DFMT_R3G3B2:
6137 r = (r * 8) / 256;
6138 g = (g * 8) / 256;
6139 b = (b * 4) / 256;
6140 ret = r << 5;
6141 ret |= g << 2;
6142 ret |= b << 0;
6143 TRACE("Returning %08x\n", ret);
6144 return ret;
6146 case WINED3DFMT_X8B8G8R8:
6147 case WINED3DFMT_A8B8G8R8:
6148 ret = a << 24;
6149 ret |= b << 16;
6150 ret |= g << 8;
6151 ret |= r << 0;
6152 TRACE("Returning %08x\n", ret);
6153 return ret;
6155 case WINED3DFMT_A2R10G10B10:
6156 a = (a * 4) / 256;
6157 r = (r * 1024) / 256;
6158 g = (g * 1024) / 256;
6159 b = (b * 1024) / 256;
6160 ret = a << 30;
6161 ret |= r << 20;
6162 ret |= g << 10;
6163 ret |= b << 0;
6164 TRACE("Returning %08x\n", ret);
6165 return ret;
6167 case WINED3DFMT_A2B10G10R10:
6168 a = (a * 4) / 256;
6169 r = (r * 1024) / 256;
6170 g = (g * 1024) / 256;
6171 b = (b * 1024) / 256;
6172 ret = a << 30;
6173 ret |= b << 20;
6174 ret |= g << 10;
6175 ret |= r << 0;
6176 TRACE("Returning %08x\n", ret);
6177 return ret;
6179 default:
6180 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6181 return 0;
6185 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6187 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6188 WINEDDBLTFX BltFx;
6189 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6191 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6192 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6193 return WINED3DERR_INVALIDCALL;
6196 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6197 color_fill_fbo(iface, pSurface, pRect, color);
6198 return WINED3D_OK;
6199 } else {
6200 /* Just forward this to the DirectDraw blitting engine */
6201 memset(&BltFx, 0, sizeof(BltFx));
6202 BltFx.dwSize = sizeof(BltFx);
6203 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6204 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6205 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6209 /* rendertarget and depth stencil functions */
6210 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6213 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6214 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6215 return WINED3DERR_INVALIDCALL;
6218 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6219 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6220 /* Note inc ref on returned surface */
6221 if(*ppRenderTarget != NULL)
6222 IWineD3DSurface_AddRef(*ppRenderTarget);
6223 return WINED3D_OK;
6226 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6228 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6229 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6230 IWineD3DSwapChainImpl *Swapchain;
6231 HRESULT hr;
6233 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6235 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6236 if(hr != WINED3D_OK) {
6237 ERR("Can't get the swapchain\n");
6238 return hr;
6241 /* Make sure to release the swapchain */
6242 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6244 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6245 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6246 return WINED3DERR_INVALIDCALL;
6248 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6249 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6250 return WINED3DERR_INVALIDCALL;
6253 if(Swapchain->frontBuffer != Front) {
6254 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6256 if(Swapchain->frontBuffer)
6257 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6258 Swapchain->frontBuffer = Front;
6260 if(Swapchain->frontBuffer) {
6261 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6265 if(Back && !Swapchain->backBuffer) {
6266 /* We need memory for the back buffer array - only one back buffer this way */
6267 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6268 if(!Swapchain->backBuffer) {
6269 ERR("Out of memory\n");
6270 return E_OUTOFMEMORY;
6274 if(Swapchain->backBuffer[0] != Back) {
6275 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6277 /* What to do about the context here in the case of multithreading? Not sure.
6278 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6280 ENTER_GL();
6281 if(!Swapchain->backBuffer[0]) {
6282 /* GL was told to draw to the front buffer at creation,
6283 * undo that
6285 glDrawBuffer(GL_BACK);
6286 checkGLcall("glDrawBuffer(GL_BACK)");
6287 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6288 Swapchain->presentParms.BackBufferCount = 1;
6289 } else if (!Back) {
6290 /* That makes problems - disable for now */
6291 /* glDrawBuffer(GL_FRONT); */
6292 checkGLcall("glDrawBuffer(GL_FRONT)");
6293 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6294 Swapchain->presentParms.BackBufferCount = 0;
6296 LEAVE_GL();
6298 if(Swapchain->backBuffer[0])
6299 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6300 Swapchain->backBuffer[0] = Back;
6302 if(Swapchain->backBuffer[0]) {
6303 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6304 } else {
6305 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6306 Swapchain->backBuffer = NULL;
6311 return WINED3D_OK;
6314 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6316 *ppZStencilSurface = This->stencilBufferTarget;
6317 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6319 if(*ppZStencilSurface != NULL) {
6320 /* Note inc ref on returned surface */
6321 IWineD3DSurface_AddRef(*ppZStencilSurface);
6322 return WINED3D_OK;
6323 } else {
6324 return WINED3DERR_NOTFOUND;
6328 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6329 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6332 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6333 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6334 GLenum gl_filter;
6335 POINT offset = {0, 0};
6337 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6338 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6339 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6340 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6342 switch (filter) {
6343 case WINED3DTEXF_LINEAR:
6344 gl_filter = GL_LINEAR;
6345 break;
6347 default:
6348 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6349 case WINED3DTEXF_NONE:
6350 case WINED3DTEXF_POINT:
6351 gl_filter = GL_NEAREST;
6352 break;
6355 /* Attach src surface to src fbo */
6356 src_swapchain = get_swapchain(src_surface);
6357 if (src_swapchain) {
6358 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6360 TRACE("Source surface %p is onscreen\n", src_surface);
6361 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6362 /* Make sure the drawable is up to date. In the offscreen case
6363 * attach_surface_fbo() implicitly takes care of this. */
6364 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6366 if(buffer == GL_FRONT) {
6367 RECT windowsize;
6368 UINT h;
6369 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6370 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6371 h = windowsize.bottom - windowsize.top;
6372 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6373 src_rect->y1 = offset.y + h - src_rect->y1;
6374 src_rect->y2 = offset.y + h - src_rect->y2;
6375 } else {
6376 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6377 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6380 ENTER_GL();
6381 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6382 glReadBuffer(buffer);
6383 checkGLcall("glReadBuffer()");
6384 } else {
6385 TRACE("Source surface %p is offscreen\n", src_surface);
6386 ENTER_GL();
6387 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6388 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6389 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6390 checkGLcall("glReadBuffer()");
6391 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6392 checkGLcall("glFramebufferRenderbufferEXT");
6394 LEAVE_GL();
6396 /* Attach dst surface to dst fbo */
6397 dst_swapchain = get_swapchain(dst_surface);
6398 if (dst_swapchain) {
6399 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6401 TRACE("Destination surface %p is onscreen\n", dst_surface);
6402 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6403 /* Make sure the drawable is up to date. In the offscreen case
6404 * attach_surface_fbo() implicitly takes care of this. */
6405 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6407 if(buffer == GL_FRONT) {
6408 RECT windowsize;
6409 UINT h;
6410 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6411 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6412 h = windowsize.bottom - windowsize.top;
6413 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6414 dst_rect->y1 = offset.y + h - dst_rect->y1;
6415 dst_rect->y2 = offset.y + h - dst_rect->y2;
6416 } else {
6417 /* Screen coords = window coords, surface height = window height */
6418 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6419 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6422 ENTER_GL();
6423 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6424 glDrawBuffer(buffer);
6425 checkGLcall("glDrawBuffer()");
6426 } else {
6427 TRACE("Destination surface %p is offscreen\n", dst_surface);
6429 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6430 if(!src_swapchain) {
6431 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6434 ENTER_GL();
6435 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6436 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6437 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6438 checkGLcall("glDrawBuffer()");
6439 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6440 checkGLcall("glFramebufferRenderbufferEXT");
6442 glDisable(GL_SCISSOR_TEST);
6443 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6445 if (flip) {
6446 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6447 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6448 checkGLcall("glBlitFramebuffer()");
6449 } else {
6450 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6451 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6452 checkGLcall("glBlitFramebuffer()");
6455 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6457 if (This->activeContext->current_fbo) {
6458 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6459 } else {
6460 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6461 checkGLcall("glBindFramebuffer()");
6464 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6465 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6466 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6467 glDrawBuffer(GL_BACK);
6468 checkGLcall("glDrawBuffer()");
6470 LEAVE_GL();
6473 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6474 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6475 WINED3DVIEWPORT viewport;
6477 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6479 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6480 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6481 This, RenderTargetIndex, GL_LIMITS(buffers));
6482 return WINED3DERR_INVALIDCALL;
6485 /* MSDN says that null disables the render target
6486 but a device must always be associated with a render target
6487 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6489 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6490 FIXME("Trying to set render target 0 to NULL\n");
6491 return WINED3DERR_INVALIDCALL;
6493 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6494 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);
6495 return WINED3DERR_INVALIDCALL;
6498 /* If we are trying to set what we already have, don't bother */
6499 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6500 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6501 return WINED3D_OK;
6503 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6504 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6505 This->render_targets[RenderTargetIndex] = pRenderTarget;
6507 /* Render target 0 is special */
6508 if(RenderTargetIndex == 0) {
6509 /* Finally, reset the viewport as the MSDN states. */
6510 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6511 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6512 viewport.X = 0;
6513 viewport.Y = 0;
6514 viewport.MaxZ = 1.0f;
6515 viewport.MinZ = 0.0f;
6516 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6517 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6518 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6520 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6522 return WINED3D_OK;
6525 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6527 HRESULT hr = WINED3D_OK;
6528 IWineD3DSurface *tmp;
6530 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6532 if (pNewZStencil == This->stencilBufferTarget) {
6533 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6534 } else {
6535 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6536 * depending on the renter target implementation being used.
6537 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6538 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6539 * stencil buffer and incur an extra memory overhead
6540 ******************************************************/
6542 if (This->stencilBufferTarget) {
6543 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6544 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6545 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6546 } else {
6547 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6548 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6549 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6553 tmp = This->stencilBufferTarget;
6554 This->stencilBufferTarget = pNewZStencil;
6555 /* should we be calling the parent or the wined3d surface? */
6556 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6557 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6558 hr = WINED3D_OK;
6560 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6561 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6562 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6563 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6564 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6568 return hr;
6571 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6572 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6574 /* TODO: the use of Impl is deprecated. */
6575 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6576 WINED3DLOCKED_RECT lockedRect;
6578 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6580 /* some basic validation checks */
6581 if(This->cursorTexture) {
6582 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6583 ENTER_GL();
6584 glDeleteTextures(1, &This->cursorTexture);
6585 LEAVE_GL();
6586 This->cursorTexture = 0;
6589 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6590 This->haveHardwareCursor = TRUE;
6591 else
6592 This->haveHardwareCursor = FALSE;
6594 if(pCursorBitmap) {
6595 WINED3DLOCKED_RECT rect;
6597 /* MSDN: Cursor must be A8R8G8B8 */
6598 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6599 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6600 return WINED3DERR_INVALIDCALL;
6603 /* MSDN: Cursor must be smaller than the display mode */
6604 if(pSur->currentDesc.Width > This->ddraw_width ||
6605 pSur->currentDesc.Height > This->ddraw_height) {
6606 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);
6607 return WINED3DERR_INVALIDCALL;
6610 if (!This->haveHardwareCursor) {
6611 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6613 /* Do not store the surface's pointer because the application may
6614 * release it after setting the cursor image. Windows doesn't
6615 * addref the set surface, so we can't do this either without
6616 * creating circular refcount dependencies. Copy out the gl texture
6617 * instead.
6619 This->cursorWidth = pSur->currentDesc.Width;
6620 This->cursorHeight = pSur->currentDesc.Height;
6621 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6623 const struct GlPixelFormatDesc *glDesc;
6624 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6625 char *mem, *bits = (char *)rect.pBits;
6626 GLint intfmt = glDesc->glInternal;
6627 GLint format = glDesc->glFormat;
6628 GLint type = glDesc->glType;
6629 INT height = This->cursorHeight;
6630 INT width = This->cursorWidth;
6631 INT bpp = tableEntry->bpp;
6632 INT i, sampler;
6634 /* Reformat the texture memory (pitch and width can be
6635 * different) */
6636 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6637 for(i = 0; i < height; i++)
6638 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6639 IWineD3DSurface_UnlockRect(pCursorBitmap);
6640 ENTER_GL();
6642 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6643 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6644 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6647 /* Make sure that a proper texture unit is selected */
6648 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6649 checkGLcall("glActiveTextureARB");
6650 sampler = This->rev_tex_unit_map[0];
6651 if (sampler != -1) {
6652 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6654 /* Create a new cursor texture */
6655 glGenTextures(1, &This->cursorTexture);
6656 checkGLcall("glGenTextures");
6657 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6658 checkGLcall("glBindTexture");
6659 /* Copy the bitmap memory into the cursor texture */
6660 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6661 HeapFree(GetProcessHeap(), 0, mem);
6662 checkGLcall("glTexImage2D");
6664 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6665 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6666 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6669 LEAVE_GL();
6671 else
6673 FIXME("A cursor texture was not returned.\n");
6674 This->cursorTexture = 0;
6677 else
6679 /* Draw a hardware cursor */
6680 ICONINFO cursorInfo;
6681 HCURSOR cursor;
6682 /* Create and clear maskBits because it is not needed for
6683 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6684 * chunks. */
6685 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6686 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6687 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6688 WINED3DLOCK_NO_DIRTY_UPDATE |
6689 WINED3DLOCK_READONLY
6691 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6692 pSur->currentDesc.Height);
6694 cursorInfo.fIcon = FALSE;
6695 cursorInfo.xHotspot = XHotSpot;
6696 cursorInfo.yHotspot = YHotSpot;
6697 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6698 pSur->currentDesc.Height, 1,
6699 1, &maskBits);
6700 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6701 pSur->currentDesc.Height, 1,
6702 32, lockedRect.pBits);
6703 IWineD3DSurface_UnlockRect(pCursorBitmap);
6704 /* Create our cursor and clean up. */
6705 cursor = CreateIconIndirect(&cursorInfo);
6706 SetCursor(cursor);
6707 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6708 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6709 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6710 This->hardwareCursor = cursor;
6711 HeapFree(GetProcessHeap(), 0, maskBits);
6715 This->xHotSpot = XHotSpot;
6716 This->yHotSpot = YHotSpot;
6717 return WINED3D_OK;
6720 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6722 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6724 This->xScreenSpace = XScreenSpace;
6725 This->yScreenSpace = YScreenSpace;
6727 return;
6731 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6733 BOOL oldVisible = This->bCursorVisible;
6734 POINT pt;
6736 TRACE("(%p) : visible(%d)\n", This, bShow);
6739 * When ShowCursor is first called it should make the cursor appear at the OS's last
6740 * known cursor position. Because of this, some applications just repetitively call
6741 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6743 GetCursorPos(&pt);
6744 This->xScreenSpace = pt.x;
6745 This->yScreenSpace = pt.y;
6747 if (This->haveHardwareCursor) {
6748 This->bCursorVisible = bShow;
6749 if (bShow)
6750 SetCursor(This->hardwareCursor);
6751 else
6752 SetCursor(NULL);
6754 else
6756 if (This->cursorTexture)
6757 This->bCursorVisible = bShow;
6760 return oldVisible;
6763 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6765 IWineD3DResourceImpl *resource;
6766 TRACE("(%p) : state (%u)\n", This, This->state);
6768 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6769 switch (This->state) {
6770 case WINED3D_OK:
6771 return WINED3D_OK;
6772 case WINED3DERR_DEVICELOST:
6774 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6775 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6776 return WINED3DERR_DEVICENOTRESET;
6778 return WINED3DERR_DEVICELOST;
6780 case WINED3DERR_DRIVERINTERNALERROR:
6781 return WINED3DERR_DRIVERINTERNALERROR;
6784 /* Unknown state */
6785 return WINED3DERR_DRIVERINTERNALERROR;
6789 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6791 /** FIXME: Resource tracking needs to be done,
6792 * The closes we can do to this is set the priorities of all managed textures low
6793 * and then reset them.
6794 ***********************************************************/
6795 FIXME("(%p) : stub\n", This);
6796 return WINED3D_OK;
6799 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6801 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6803 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6804 if(surface->Flags & SFLAG_DIBSECTION) {
6805 /* Release the DC */
6806 SelectObject(surface->hDC, surface->dib.holdbitmap);
6807 DeleteDC(surface->hDC);
6808 /* Release the DIB section */
6809 DeleteObject(surface->dib.DIBsection);
6810 surface->dib.bitmap_data = NULL;
6811 surface->resource.allocatedMemory = NULL;
6812 surface->Flags &= ~SFLAG_DIBSECTION;
6814 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6815 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6816 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6817 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6818 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6819 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6820 } else {
6821 surface->pow2Width = surface->pow2Height = 1;
6822 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6823 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6825 surface->glRect.left = 0;
6826 surface->glRect.top = 0;
6827 surface->glRect.right = surface->pow2Width;
6828 surface->glRect.bottom = surface->pow2Height;
6830 if(surface->glDescription.textureName) {
6831 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6832 ENTER_GL();
6833 glDeleteTextures(1, &surface->glDescription.textureName);
6834 LEAVE_GL();
6835 surface->glDescription.textureName = 0;
6836 surface->Flags &= ~SFLAG_CLIENT;
6838 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6839 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6840 surface->Flags |= SFLAG_NONPOW2;
6841 } else {
6842 surface->Flags &= ~SFLAG_NONPOW2;
6844 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6845 surface->resource.allocatedMemory = NULL;
6846 surface->resource.heapMemory = NULL;
6847 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6848 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6849 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6850 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6851 } else {
6852 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6856 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6857 TRACE("Unloading resource %p\n", resource);
6858 IWineD3DResource_UnLoad(resource);
6859 IWineD3DResource_Release(resource);
6860 return S_OK;
6863 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6865 UINT i, count;
6866 WINED3DDISPLAYMODE m;
6867 HRESULT hr;
6869 /* All Windowed modes are supported, as is leaving the current mode */
6870 if(pp->Windowed) return TRUE;
6871 if(!pp->BackBufferWidth) return TRUE;
6872 if(!pp->BackBufferHeight) return TRUE;
6874 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6875 for(i = 0; i < count; i++) {
6876 memset(&m, 0, sizeof(m));
6877 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6878 if(FAILED(hr)) {
6879 ERR("EnumAdapterModes failed\n");
6881 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6882 /* Mode found, it is supported */
6883 return TRUE;
6886 /* Mode not found -> not supported */
6887 return FALSE;
6890 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6892 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6893 UINT i;
6894 IWineD3DBaseShaderImpl *shader;
6896 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6897 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6898 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6901 ENTER_GL();
6902 if(This->depth_blt_texture) {
6903 glDeleteTextures(1, &This->depth_blt_texture);
6904 This->depth_blt_texture = 0;
6906 if (This->depth_blt_rb) {
6907 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
6908 This->depth_blt_rb = 0;
6909 This->depth_blt_rb_w = 0;
6910 This->depth_blt_rb_h = 0;
6912 LEAVE_GL();
6914 This->blitter->free_private(iface);
6915 This->frag_pipe->free_private(iface);
6916 This->shader_backend->shader_free_private(iface);
6918 ENTER_GL();
6919 for (i = 0; i < GL_LIMITS(textures); i++) {
6920 /* Textures are recreated below */
6921 glDeleteTextures(1, &This->dummyTextureName[i]);
6922 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6923 This->dummyTextureName[i] = 0;
6925 LEAVE_GL();
6927 while(This->numContexts) {
6928 DestroyContext(This, This->contexts[0]);
6930 This->activeContext = NULL;
6931 HeapFree(GetProcessHeap(), 0, swapchain->context);
6932 swapchain->context = NULL;
6933 swapchain->num_contexts = 0;
6936 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6938 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6939 HRESULT hr;
6940 IWineD3DSurfaceImpl *target;
6942 /* Recreate the primary swapchain's context */
6943 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6944 if(swapchain->backBuffer) {
6945 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6946 } else {
6947 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6949 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
6950 &swapchain->presentParms);
6951 swapchain->num_contexts = 1;
6952 This->activeContext = swapchain->context[0];
6954 create_dummy_textures(This);
6956 hr = This->shader_backend->shader_alloc_private(iface);
6957 if(FAILED(hr)) {
6958 ERR("Failed to recreate shader private data\n");
6959 goto err_out;
6961 hr = This->frag_pipe->alloc_private(iface);
6962 if(FAILED(hr)) {
6963 TRACE("Fragment pipeline private data couldn't be allocated\n");
6964 goto err_out;
6966 hr = This->blitter->alloc_private(iface);
6967 if(FAILED(hr)) {
6968 TRACE("Blitter private data couldn't be allocated\n");
6969 goto err_out;
6972 return WINED3D_OK;
6974 err_out:
6975 This->blitter->free_private(iface);
6976 This->frag_pipe->free_private(iface);
6977 This->shader_backend->shader_free_private(iface);
6978 return hr;
6981 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6983 IWineD3DSwapChainImpl *swapchain;
6984 HRESULT hr;
6985 BOOL DisplayModeChanged = FALSE;
6986 WINED3DDISPLAYMODE mode;
6987 TRACE("(%p)\n", This);
6989 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6990 if(FAILED(hr)) {
6991 ERR("Failed to get the first implicit swapchain\n");
6992 return hr;
6995 if(!is_display_mode_supported(This, pPresentationParameters)) {
6996 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6997 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6998 pPresentationParameters->BackBufferHeight);
6999 return WINED3DERR_INVALIDCALL;
7002 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7003 * on an existing gl context, so there's no real need for recreation.
7005 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7007 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7009 TRACE("New params:\n");
7010 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7011 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7012 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7013 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7014 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7015 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7016 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7017 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7018 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7019 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7020 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7021 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7022 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7024 /* No special treatment of these parameters. Just store them */
7025 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7026 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7027 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7028 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7030 /* What to do about these? */
7031 if(pPresentationParameters->BackBufferCount != 0 &&
7032 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7033 ERR("Cannot change the back buffer count yet\n");
7035 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7036 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7037 ERR("Cannot change the back buffer format yet\n");
7039 if(pPresentationParameters->hDeviceWindow != NULL &&
7040 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7041 ERR("Cannot change the device window yet\n");
7043 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7044 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7045 return WINED3DERR_INVALIDCALL;
7048 /* Reset the depth stencil */
7049 if (pPresentationParameters->EnableAutoDepthStencil)
7050 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7051 else
7052 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7054 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7056 if(pPresentationParameters->Windowed) {
7057 mode.Width = swapchain->orig_width;
7058 mode.Height = swapchain->orig_height;
7059 mode.RefreshRate = 0;
7060 mode.Format = swapchain->presentParms.BackBufferFormat;
7061 } else {
7062 mode.Width = pPresentationParameters->BackBufferWidth;
7063 mode.Height = pPresentationParameters->BackBufferHeight;
7064 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7065 mode.Format = swapchain->presentParms.BackBufferFormat;
7068 /* Should Width == 800 && Height == 0 set 800x600? */
7069 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7070 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7071 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7073 UINT i;
7075 if(!pPresentationParameters->Windowed) {
7076 DisplayModeChanged = TRUE;
7078 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7079 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7081 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7082 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7083 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7085 if(This->auto_depth_stencil_buffer) {
7086 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7090 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7091 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7092 DisplayModeChanged) {
7094 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7096 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7097 if(swapchain->presentParms.Windowed) {
7098 /* switch from windowed to fs */
7099 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7100 pPresentationParameters->BackBufferWidth,
7101 pPresentationParameters->BackBufferHeight);
7102 } else {
7103 /* Fullscreen -> fullscreen mode change */
7104 MoveWindow(swapchain->win_handle, 0, 0,
7105 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7106 TRUE);
7108 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7109 /* Fullscreen -> windowed switch */
7110 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7112 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7113 } else if(!pPresentationParameters->Windowed) {
7114 DWORD style = This->style, exStyle = This->exStyle;
7115 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7116 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7117 * Reset to clear up their mess. Guild Wars also loses the device during that.
7119 This->style = 0;
7120 This->exStyle = 0;
7121 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7122 pPresentationParameters->BackBufferWidth,
7123 pPresentationParameters->BackBufferHeight);
7124 This->style = style;
7125 This->exStyle = exStyle;
7128 TRACE("Resetting stateblock\n");
7129 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7130 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7132 /* Note: No parent needed for initial internal stateblock */
7133 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7134 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7135 else TRACE("Created stateblock %p\n", This->stateBlock);
7136 This->updateStateBlock = This->stateBlock;
7137 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7139 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7140 if(FAILED(hr)) {
7141 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7144 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7145 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7147 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7148 * first use
7150 return hr;
7153 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7155 /** FIXME: always true at the moment **/
7156 if(!bEnableDialogs) {
7157 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7159 return WINED3D_OK;
7163 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7165 TRACE("(%p) : pParameters %p\n", This, pParameters);
7167 *pParameters = This->createParms;
7168 return WINED3D_OK;
7171 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7172 IWineD3DSwapChain *swapchain;
7174 TRACE("Relaying to swapchain\n");
7176 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7177 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7178 IWineD3DSwapChain_Release(swapchain);
7180 return;
7183 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7184 IWineD3DSwapChain *swapchain;
7186 TRACE("Relaying to swapchain\n");
7188 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7189 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7190 IWineD3DSwapChain_Release(swapchain);
7192 return;
7196 /** ********************************************************
7197 * Notification functions
7198 ** ********************************************************/
7199 /** This function must be called in the release of a resource when ref == 0,
7200 * the contents of resource must still be correct,
7201 * any handles to other resource held by the caller must be closed
7202 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7203 *****************************************************/
7204 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7207 TRACE("(%p) : Adding Resource %p\n", This, resource);
7208 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7211 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7212 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7214 TRACE("(%p) : Removing resource %p\n", This, resource);
7216 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7220 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7222 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7223 int counter;
7225 TRACE("(%p) : resource %p\n", This, resource);
7227 context_resource_released(iface, resource, type);
7229 switch (type) {
7230 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7231 case WINED3DRTYPE_SURFACE: {
7232 unsigned int i;
7234 /* Cleanup any FBO attachments if d3d is enabled */
7235 if(This->d3d_initialized) {
7236 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7237 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7239 TRACE("Last active render target destroyed\n");
7240 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7241 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7242 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7243 * and the lastActiveRenderTarget member shouldn't matter
7245 if(swapchain) {
7246 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7247 TRACE("Activating primary back buffer\n");
7248 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7249 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7250 /* Single buffering environment */
7251 TRACE("Activating primary front buffer\n");
7252 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7253 } else {
7254 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7255 /* Implicit render target destroyed, that means the device is being destroyed
7256 * whatever we set here, it shouldn't matter
7258 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7260 } else {
7261 /* May happen during ddraw uninitialization */
7262 TRACE("Render target set, but swapchain does not exist!\n");
7263 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7267 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7268 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7269 This->render_targets[i] = NULL;
7272 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7273 This->stencilBufferTarget = NULL;
7277 break;
7279 case WINED3DRTYPE_TEXTURE:
7280 case WINED3DRTYPE_CUBETEXTURE:
7281 case WINED3DRTYPE_VOLUMETEXTURE:
7282 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7283 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7284 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7285 This->stateBlock->textures[counter] = NULL;
7287 if (This->updateStateBlock != This->stateBlock ){
7288 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7289 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7290 This->updateStateBlock->textures[counter] = NULL;
7294 break;
7295 case WINED3DRTYPE_VOLUME:
7296 /* TODO: nothing really? */
7297 break;
7298 case WINED3DRTYPE_VERTEXBUFFER:
7299 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7301 int streamNumber;
7302 TRACE("Cleaning up stream pointers\n");
7304 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7305 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7306 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7308 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7309 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7310 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7311 This->updateStateBlock->streamSource[streamNumber] = 0;
7312 /* Set changed flag? */
7315 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) */
7316 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7317 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7318 This->stateBlock->streamSource[streamNumber] = 0;
7323 break;
7324 case WINED3DRTYPE_INDEXBUFFER:
7325 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7326 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7327 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7328 This->updateStateBlock->pIndexData = NULL;
7331 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7332 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7333 This->stateBlock->pIndexData = NULL;
7337 break;
7338 default:
7339 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7340 break;
7344 /* Remove the resource from the resourceStore */
7345 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7347 TRACE("Resource released\n");
7351 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7353 IWineD3DResourceImpl *resource, *cursor;
7354 HRESULT ret;
7355 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7357 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7358 TRACE("enumerating resource %p\n", resource);
7359 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7360 ret = pCallback((IWineD3DResource *) resource, pData);
7361 if(ret == S_FALSE) {
7362 TRACE("Canceling enumeration\n");
7363 break;
7366 return WINED3D_OK;
7369 /**********************************************************
7370 * IWineD3DDevice VTbl follows
7371 **********************************************************/
7373 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7375 /*** IUnknown methods ***/
7376 IWineD3DDeviceImpl_QueryInterface,
7377 IWineD3DDeviceImpl_AddRef,
7378 IWineD3DDeviceImpl_Release,
7379 /*** IWineD3DDevice methods ***/
7380 IWineD3DDeviceImpl_GetParent,
7381 /*** Creation methods**/
7382 IWineD3DDeviceImpl_CreateVertexBuffer,
7383 IWineD3DDeviceImpl_CreateIndexBuffer,
7384 IWineD3DDeviceImpl_CreateStateBlock,
7385 IWineD3DDeviceImpl_CreateSurface,
7386 IWineD3DDeviceImpl_CreateTexture,
7387 IWineD3DDeviceImpl_CreateVolumeTexture,
7388 IWineD3DDeviceImpl_CreateVolume,
7389 IWineD3DDeviceImpl_CreateCubeTexture,
7390 IWineD3DDeviceImpl_CreateQuery,
7391 IWineD3DDeviceImpl_CreateSwapChain,
7392 IWineD3DDeviceImpl_CreateVertexDeclaration,
7393 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7394 IWineD3DDeviceImpl_CreateVertexShader,
7395 IWineD3DDeviceImpl_CreatePixelShader,
7396 IWineD3DDeviceImpl_CreatePalette,
7397 /*** Odd functions **/
7398 IWineD3DDeviceImpl_Init3D,
7399 IWineD3DDeviceImpl_InitGDI,
7400 IWineD3DDeviceImpl_Uninit3D,
7401 IWineD3DDeviceImpl_UninitGDI,
7402 IWineD3DDeviceImpl_SetMultithreaded,
7403 IWineD3DDeviceImpl_EvictManagedResources,
7404 IWineD3DDeviceImpl_GetAvailableTextureMem,
7405 IWineD3DDeviceImpl_GetBackBuffer,
7406 IWineD3DDeviceImpl_GetCreationParameters,
7407 IWineD3DDeviceImpl_GetDeviceCaps,
7408 IWineD3DDeviceImpl_GetDirect3D,
7409 IWineD3DDeviceImpl_GetDisplayMode,
7410 IWineD3DDeviceImpl_SetDisplayMode,
7411 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7412 IWineD3DDeviceImpl_GetRasterStatus,
7413 IWineD3DDeviceImpl_GetSwapChain,
7414 IWineD3DDeviceImpl_Reset,
7415 IWineD3DDeviceImpl_SetDialogBoxMode,
7416 IWineD3DDeviceImpl_SetCursorProperties,
7417 IWineD3DDeviceImpl_SetCursorPosition,
7418 IWineD3DDeviceImpl_ShowCursor,
7419 IWineD3DDeviceImpl_TestCooperativeLevel,
7420 /*** Getters and setters **/
7421 IWineD3DDeviceImpl_SetClipPlane,
7422 IWineD3DDeviceImpl_GetClipPlane,
7423 IWineD3DDeviceImpl_SetClipStatus,
7424 IWineD3DDeviceImpl_GetClipStatus,
7425 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7426 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7427 IWineD3DDeviceImpl_SetDepthStencilSurface,
7428 IWineD3DDeviceImpl_GetDepthStencilSurface,
7429 IWineD3DDeviceImpl_SetGammaRamp,
7430 IWineD3DDeviceImpl_GetGammaRamp,
7431 IWineD3DDeviceImpl_SetIndices,
7432 IWineD3DDeviceImpl_GetIndices,
7433 IWineD3DDeviceImpl_SetBaseVertexIndex,
7434 IWineD3DDeviceImpl_GetBaseVertexIndex,
7435 IWineD3DDeviceImpl_SetLight,
7436 IWineD3DDeviceImpl_GetLight,
7437 IWineD3DDeviceImpl_SetLightEnable,
7438 IWineD3DDeviceImpl_GetLightEnable,
7439 IWineD3DDeviceImpl_SetMaterial,
7440 IWineD3DDeviceImpl_GetMaterial,
7441 IWineD3DDeviceImpl_SetNPatchMode,
7442 IWineD3DDeviceImpl_GetNPatchMode,
7443 IWineD3DDeviceImpl_SetPaletteEntries,
7444 IWineD3DDeviceImpl_GetPaletteEntries,
7445 IWineD3DDeviceImpl_SetPixelShader,
7446 IWineD3DDeviceImpl_GetPixelShader,
7447 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7448 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7449 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7450 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7451 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7452 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7453 IWineD3DDeviceImpl_SetRenderState,
7454 IWineD3DDeviceImpl_GetRenderState,
7455 IWineD3DDeviceImpl_SetRenderTarget,
7456 IWineD3DDeviceImpl_GetRenderTarget,
7457 IWineD3DDeviceImpl_SetFrontBackBuffers,
7458 IWineD3DDeviceImpl_SetSamplerState,
7459 IWineD3DDeviceImpl_GetSamplerState,
7460 IWineD3DDeviceImpl_SetScissorRect,
7461 IWineD3DDeviceImpl_GetScissorRect,
7462 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7463 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7464 IWineD3DDeviceImpl_SetStreamSource,
7465 IWineD3DDeviceImpl_GetStreamSource,
7466 IWineD3DDeviceImpl_SetStreamSourceFreq,
7467 IWineD3DDeviceImpl_GetStreamSourceFreq,
7468 IWineD3DDeviceImpl_SetTexture,
7469 IWineD3DDeviceImpl_GetTexture,
7470 IWineD3DDeviceImpl_SetTextureStageState,
7471 IWineD3DDeviceImpl_GetTextureStageState,
7472 IWineD3DDeviceImpl_SetTransform,
7473 IWineD3DDeviceImpl_GetTransform,
7474 IWineD3DDeviceImpl_SetVertexDeclaration,
7475 IWineD3DDeviceImpl_GetVertexDeclaration,
7476 IWineD3DDeviceImpl_SetVertexShader,
7477 IWineD3DDeviceImpl_GetVertexShader,
7478 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7479 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7480 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7481 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7482 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7483 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7484 IWineD3DDeviceImpl_SetViewport,
7485 IWineD3DDeviceImpl_GetViewport,
7486 IWineD3DDeviceImpl_MultiplyTransform,
7487 IWineD3DDeviceImpl_ValidateDevice,
7488 IWineD3DDeviceImpl_ProcessVertices,
7489 /*** State block ***/
7490 IWineD3DDeviceImpl_BeginStateBlock,
7491 IWineD3DDeviceImpl_EndStateBlock,
7492 /*** Scene management ***/
7493 IWineD3DDeviceImpl_BeginScene,
7494 IWineD3DDeviceImpl_EndScene,
7495 IWineD3DDeviceImpl_Present,
7496 IWineD3DDeviceImpl_Clear,
7497 /*** Drawing ***/
7498 IWineD3DDeviceImpl_DrawPrimitive,
7499 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7500 IWineD3DDeviceImpl_DrawPrimitiveUP,
7501 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7502 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7503 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7504 IWineD3DDeviceImpl_DrawRectPatch,
7505 IWineD3DDeviceImpl_DrawTriPatch,
7506 IWineD3DDeviceImpl_DeletePatch,
7507 IWineD3DDeviceImpl_ColorFill,
7508 IWineD3DDeviceImpl_UpdateTexture,
7509 IWineD3DDeviceImpl_UpdateSurface,
7510 IWineD3DDeviceImpl_GetFrontBufferData,
7511 /*** object tracking ***/
7512 IWineD3DDeviceImpl_ResourceReleased,
7513 IWineD3DDeviceImpl_EnumResources
7516 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7517 WINED3DRS_ALPHABLENDENABLE ,
7518 WINED3DRS_ALPHAFUNC ,
7519 WINED3DRS_ALPHAREF ,
7520 WINED3DRS_ALPHATESTENABLE ,
7521 WINED3DRS_BLENDOP ,
7522 WINED3DRS_COLORWRITEENABLE ,
7523 WINED3DRS_DESTBLEND ,
7524 WINED3DRS_DITHERENABLE ,
7525 WINED3DRS_FILLMODE ,
7526 WINED3DRS_FOGDENSITY ,
7527 WINED3DRS_FOGEND ,
7528 WINED3DRS_FOGSTART ,
7529 WINED3DRS_LASTPIXEL ,
7530 WINED3DRS_SHADEMODE ,
7531 WINED3DRS_SRCBLEND ,
7532 WINED3DRS_STENCILENABLE ,
7533 WINED3DRS_STENCILFAIL ,
7534 WINED3DRS_STENCILFUNC ,
7535 WINED3DRS_STENCILMASK ,
7536 WINED3DRS_STENCILPASS ,
7537 WINED3DRS_STENCILREF ,
7538 WINED3DRS_STENCILWRITEMASK ,
7539 WINED3DRS_STENCILZFAIL ,
7540 WINED3DRS_TEXTUREFACTOR ,
7541 WINED3DRS_WRAP0 ,
7542 WINED3DRS_WRAP1 ,
7543 WINED3DRS_WRAP2 ,
7544 WINED3DRS_WRAP3 ,
7545 WINED3DRS_WRAP4 ,
7546 WINED3DRS_WRAP5 ,
7547 WINED3DRS_WRAP6 ,
7548 WINED3DRS_WRAP7 ,
7549 WINED3DRS_ZENABLE ,
7550 WINED3DRS_ZFUNC ,
7551 WINED3DRS_ZWRITEENABLE
7554 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7555 WINED3DTSS_ADDRESSW ,
7556 WINED3DTSS_ALPHAARG0 ,
7557 WINED3DTSS_ALPHAARG1 ,
7558 WINED3DTSS_ALPHAARG2 ,
7559 WINED3DTSS_ALPHAOP ,
7560 WINED3DTSS_BUMPENVLOFFSET ,
7561 WINED3DTSS_BUMPENVLSCALE ,
7562 WINED3DTSS_BUMPENVMAT00 ,
7563 WINED3DTSS_BUMPENVMAT01 ,
7564 WINED3DTSS_BUMPENVMAT10 ,
7565 WINED3DTSS_BUMPENVMAT11 ,
7566 WINED3DTSS_COLORARG0 ,
7567 WINED3DTSS_COLORARG1 ,
7568 WINED3DTSS_COLORARG2 ,
7569 WINED3DTSS_COLOROP ,
7570 WINED3DTSS_RESULTARG ,
7571 WINED3DTSS_TEXCOORDINDEX ,
7572 WINED3DTSS_TEXTURETRANSFORMFLAGS
7575 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7576 WINED3DSAMP_ADDRESSU ,
7577 WINED3DSAMP_ADDRESSV ,
7578 WINED3DSAMP_ADDRESSW ,
7579 WINED3DSAMP_BORDERCOLOR ,
7580 WINED3DSAMP_MAGFILTER ,
7581 WINED3DSAMP_MINFILTER ,
7582 WINED3DSAMP_MIPFILTER ,
7583 WINED3DSAMP_MIPMAPLODBIAS ,
7584 WINED3DSAMP_MAXMIPLEVEL ,
7585 WINED3DSAMP_MAXANISOTROPY ,
7586 WINED3DSAMP_SRGBTEXTURE ,
7587 WINED3DSAMP_ELEMENTINDEX
7590 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7591 WINED3DRS_AMBIENT ,
7592 WINED3DRS_AMBIENTMATERIALSOURCE ,
7593 WINED3DRS_CLIPPING ,
7594 WINED3DRS_CLIPPLANEENABLE ,
7595 WINED3DRS_COLORVERTEX ,
7596 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7597 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7598 WINED3DRS_FOGDENSITY ,
7599 WINED3DRS_FOGEND ,
7600 WINED3DRS_FOGSTART ,
7601 WINED3DRS_FOGTABLEMODE ,
7602 WINED3DRS_FOGVERTEXMODE ,
7603 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7604 WINED3DRS_LIGHTING ,
7605 WINED3DRS_LOCALVIEWER ,
7606 WINED3DRS_MULTISAMPLEANTIALIAS ,
7607 WINED3DRS_MULTISAMPLEMASK ,
7608 WINED3DRS_NORMALIZENORMALS ,
7609 WINED3DRS_PATCHEDGESTYLE ,
7610 WINED3DRS_POINTSCALE_A ,
7611 WINED3DRS_POINTSCALE_B ,
7612 WINED3DRS_POINTSCALE_C ,
7613 WINED3DRS_POINTSCALEENABLE ,
7614 WINED3DRS_POINTSIZE ,
7615 WINED3DRS_POINTSIZE_MAX ,
7616 WINED3DRS_POINTSIZE_MIN ,
7617 WINED3DRS_POINTSPRITEENABLE ,
7618 WINED3DRS_RANGEFOGENABLE ,
7619 WINED3DRS_SPECULARMATERIALSOURCE ,
7620 WINED3DRS_TWEENFACTOR ,
7621 WINED3DRS_VERTEXBLEND ,
7622 WINED3DRS_CULLMODE ,
7623 WINED3DRS_FOGCOLOR
7626 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7627 WINED3DTSS_TEXCOORDINDEX ,
7628 WINED3DTSS_TEXTURETRANSFORMFLAGS
7631 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7632 WINED3DSAMP_DMAPOFFSET
7635 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7636 DWORD rep = This->StateTable[state].representative;
7637 DWORD idx;
7638 BYTE shift;
7639 UINT i;
7640 WineD3DContext *context;
7642 if(!rep) return;
7643 for(i = 0; i < This->numContexts; i++) {
7644 context = This->contexts[i];
7645 if(isStateDirty(context, rep)) continue;
7647 context->dirtyArray[context->numDirtyEntries++] = rep;
7648 idx = rep >> 5;
7649 shift = rep & 0x1f;
7650 context->isStateDirty[idx] |= (1 << shift);
7654 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7655 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7656 /* The drawable size of a pbuffer render target is the current pbuffer size
7658 *width = dev->pbufferWidth;
7659 *height = dev->pbufferHeight;
7662 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7663 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7665 *width = This->pow2Width;
7666 *height = This->pow2Height;
7669 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7670 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7671 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7672 * current context's drawable, which is the size of the back buffer of the swapchain
7673 * the active context belongs to. The back buffer of the swapchain is stored as the
7674 * surface the context belongs to.
7676 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7677 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;