push 9d6e510d5bb9560a6aa2e6ec402cb2d2444b5081
[wine/hacks.git] / dlls / wined3d / device.c
blob688b2f28c83ac5a11b545a87c8eafedf6f8ef240
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 = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
421 object->contained_tss_states[object->num_contained_tss_states].stage = i;
422 object->contained_tss_states[object->num_contained_tss_states].state = j;
423 object->num_contained_tss_states++;
426 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
427 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
428 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
429 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
430 object->num_contained_sampler_states++;
434 for(i = 0; i < MAX_STREAMS; i++) {
435 if(object->streamSource[i]) {
436 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
439 if(object->pIndexData) {
440 IWineD3DIndexBuffer_AddRef(object->pIndexData);
442 if(object->vertexShader) {
443 IWineD3DVertexShader_AddRef(object->vertexShader);
445 if(object->pixelShader) {
446 IWineD3DPixelShader_AddRef(object->pixelShader);
449 } else if (Type == WINED3DSBT_PIXELSTATE) {
451 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
452 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
454 object->changed.pixelShader = TRUE;
456 /* Pixel Shader Constants */
457 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
458 object->contained_ps_consts_f[i] = i;
459 object->changed.pixelShaderConstantsF[i] = TRUE;
461 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
462 for (i = 0; i < MAX_CONST_B; ++i) {
463 object->contained_ps_consts_b[i] = i;
464 object->changed.pixelShaderConstantsB |= (1 << i);
466 object->num_contained_ps_consts_b = MAX_CONST_B;
467 for (i = 0; i < MAX_CONST_I; ++i) {
468 object->contained_ps_consts_i[i] = i;
469 object->changed.pixelShaderConstantsI |= (1 << i);
471 object->num_contained_ps_consts_i = MAX_CONST_I;
473 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
474 DWORD rs = SavedPixelStates_R[i];
475 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
476 object->contained_render_states[i] = rs;
478 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
479 for (j = 0; j < MAX_TEXTURES; j++) {
480 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
481 DWORD state = SavedPixelStates_T[i];
482 object->changed.textureState[j] |= 1 << state;
483 object->contained_tss_states[object->num_contained_tss_states].stage = j;
484 object->contained_tss_states[object->num_contained_tss_states].state = state;
485 object->num_contained_tss_states++;
488 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
489 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
490 DWORD state = SavedPixelStates_S[i];
491 object->changed.samplerState[j] |= 1 << state;
492 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
493 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
494 object->num_contained_sampler_states++;
497 if(object->pixelShader) {
498 IWineD3DPixelShader_AddRef(object->pixelShader);
501 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
502 * on them. This makes releasing the buffer easier
504 for(i = 0; i < MAX_STREAMS; i++) {
505 object->streamSource[i] = NULL;
507 object->pIndexData = NULL;
508 object->vertexShader = NULL;
510 } else if (Type == WINED3DSBT_VERTEXSTATE) {
512 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
513 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
515 object->changed.vertexShader = TRUE;
517 /* Vertex Shader Constants */
518 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
519 object->changed.vertexShaderConstantsF[i] = TRUE;
520 object->contained_vs_consts_f[i] = i;
522 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
523 for (i = 0; i < MAX_CONST_B; ++i) {
524 object->contained_vs_consts_b[i] = i;
525 object->changed.vertexShaderConstantsB |= (1 << i);
527 object->num_contained_vs_consts_b = MAX_CONST_B;
528 for (i = 0; i < MAX_CONST_I; ++i) {
529 object->contained_vs_consts_i[i] = i;
530 object->changed.vertexShaderConstantsI |= (1 << i);
532 object->num_contained_vs_consts_i = MAX_CONST_I;
533 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
534 DWORD rs = SavedVertexStates_R[i];
535 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
536 object->contained_render_states[i] = rs;
538 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
539 for (j = 0; j < MAX_TEXTURES; j++) {
540 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
541 DWORD state = SavedVertexStates_T[i];
542 object->changed.textureState[j] |= 1 << state;
543 object->contained_tss_states[object->num_contained_tss_states].stage = j;
544 object->contained_tss_states[object->num_contained_tss_states].state = state;
545 object->num_contained_tss_states++;
548 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
549 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
550 DWORD state = SavedVertexStates_S[i];
551 object->changed.samplerState[j] |= 1 << state;
552 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
553 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
554 object->num_contained_sampler_states++;
558 for(j = 0; j < LIGHTMAP_SIZE; j++) {
559 struct list *e;
560 LIST_FOR_EACH(e, &object->lightMap[j]) {
561 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
562 light->changed = TRUE;
563 light->enabledChanged = TRUE;
567 for(i = 0; i < MAX_STREAMS; i++) {
568 if(object->streamSource[i]) {
569 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
572 if(object->vertexShader) {
573 IWineD3DVertexShader_AddRef(object->vertexShader);
575 object->pIndexData = NULL;
576 object->pixelShader = NULL;
577 } else {
578 FIXME("Unrecognized state block type %d\n", Type);
581 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
582 return WINED3D_OK;
585 /* ************************************
586 MSDN:
587 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
589 Discard
590 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
592 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.
594 ******************************** */
596 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) {
597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
598 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
599 unsigned int Size = 1;
600 const struct GlPixelFormatDesc *glDesc;
601 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
602 UINT mul_4w, mul_4h;
603 TRACE("(%p) Create surface\n",This);
605 /** FIXME: Check ranges on the inputs are valid
606 * MSDN
607 * MultisampleQuality
608 * [in] Quality level. The valid range is between zero and one less than the level
609 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
610 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
611 * values of paired render targets, depth stencil surfaces, and the MultiSample type
612 * must all match.
613 *******************************/
617 * TODO: Discard MSDN
618 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
620 * If this flag is set, the contents of the depth stencil buffer will be
621 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
622 * with a different depth surface.
624 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
625 ***************************/
627 if(MultisampleQuality > 0) {
628 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
629 MultisampleQuality=0;
632 /** FIXME: Check that the format is supported
633 * by the device.
634 *******************************/
636 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
637 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
638 * space!
639 *********************************/
640 mul_4w = (Width + 3) & ~3;
641 mul_4h = (Height + 3) & ~3;
642 if (WINED3DFMT_UNKNOWN == Format) {
643 Size = 0;
644 } else if (Format == WINED3DFMT_DXT1) {
645 /* DXT1 is half byte per pixel */
646 Size = (mul_4w * tableEntry->bpp * mul_4h) >> 1;
648 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
649 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
650 Format == WINED3DFMT_ATI2N) {
651 Size = (mul_4w * tableEntry->bpp * mul_4h);
652 } else {
653 /* The pitch is a multiple of 4 bytes */
654 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
655 Size *= Height;
658 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
660 /** Create and initialise the surface resource **/
661 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
662 /* "Standalone" surface */
663 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
665 object->currentDesc.Width = Width;
666 object->currentDesc.Height = Height;
667 object->currentDesc.MultiSampleType = MultiSample;
668 object->currentDesc.MultiSampleQuality = MultisampleQuality;
669 object->glDescription.level = Level;
670 object->heightscale = glDesc->heightscale != 0.0 ? glDesc->heightscale : 1.0;
671 list_init(&object->overlays);
673 /* Flags */
674 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
675 object->Flags |= Discard ? SFLAG_DISCARD : 0;
676 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
677 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
680 if (WINED3DFMT_UNKNOWN != Format) {
681 object->bytesPerPixel = tableEntry->bpp;
682 } else {
683 object->bytesPerPixel = 0;
686 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
688 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
690 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
691 * this function is too deep to need to care about things like this.
692 * Levels need to be checked too, and possibly Type since they all affect what can be done.
693 * ****************************************/
694 switch(Pool) {
695 case WINED3DPOOL_SCRATCH:
696 if(!Lockable)
697 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
698 "which are mutually exclusive, setting lockable to TRUE\n");
699 Lockable = TRUE;
700 break;
701 case WINED3DPOOL_SYSTEMMEM:
702 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
703 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
704 case WINED3DPOOL_MANAGED:
705 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
706 "Usage of DYNAMIC which are mutually exclusive, not doing "
707 "anything just telling you.\n");
708 break;
709 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
710 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
711 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
712 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
713 break;
714 default:
715 FIXME("(%p) Unknown pool %d\n", This, Pool);
716 break;
719 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
720 FIXME("Trying to create a render target that isn't in the default pool\n");
723 /* mark the texture as dirty so that it gets loaded first time around*/
724 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
725 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
726 This, Width, Height, Format, debug_d3dformat(Format),
727 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
729 /* Look at the implementation and set the correct Vtable */
730 switch(Impl) {
731 case SURFACE_OPENGL:
732 /* Check if a 3D adapter is available when creating gl surfaces */
733 if(!This->adapter) {
734 ERR("OpenGL surfaces are not available without opengl\n");
735 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
736 HeapFree(GetProcessHeap(), 0, object);
737 return WINED3DERR_NOTAVAILABLE;
739 break;
741 case SURFACE_GDI:
742 object->lpVtbl = &IWineGDISurface_Vtbl;
743 break;
745 default:
746 /* To be sure to catch this */
747 ERR("Unknown requested surface implementation %d!\n", Impl);
748 IWineD3DSurface_Release((IWineD3DSurface *) object);
749 return WINED3DERR_INVALIDCALL;
752 list_init(&object->renderbuffers);
754 /* Call the private setup routine */
755 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
759 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
760 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
761 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
762 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
765 IWineD3DTextureImpl *object;
766 unsigned int i;
767 UINT tmpW;
768 UINT tmpH;
769 HRESULT hr;
770 unsigned int pow2Width;
771 unsigned int pow2Height;
772 const struct GlPixelFormatDesc *glDesc;
773 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
775 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
776 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
777 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
779 /* TODO: It should only be possible to create textures for formats
780 that are reported as supported */
781 if (WINED3DFMT_UNKNOWN >= Format) {
782 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
783 return WINED3DERR_INVALIDCALL;
786 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
787 D3DINITIALIZEBASETEXTURE(object->baseTexture);
788 object->width = Width;
789 object->height = Height;
791 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
792 object->baseTexture.minMipLookup = minMipLookup;
793 object->baseTexture.magLookup = magLookup;
794 } else {
795 object->baseTexture.minMipLookup = minMipLookup_noFilter;
796 object->baseTexture.magLookup = magLookup_noFilter;
799 /** Non-power2 support **/
800 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
801 pow2Width = Width;
802 pow2Height = Height;
803 } else {
804 /* Find the nearest pow2 match */
805 pow2Width = pow2Height = 1;
806 while (pow2Width < Width) pow2Width <<= 1;
807 while (pow2Height < Height) pow2Height <<= 1;
809 if(pow2Width != Width || pow2Height != Height) {
810 if(Levels > 1) {
811 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
812 HeapFree(GetProcessHeap(), 0, object);
813 *ppTexture = NULL;
814 return WINED3DERR_INVALIDCALL;
815 } else {
816 Levels = 1;
821 /** FIXME: add support for real non-power-two if it's provided by the video card **/
822 /* Precalculated scaling for 'faked' non power of two texture coords.
823 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
824 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
825 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
827 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
828 object->baseTexture.pow2Matrix[0] = 1.0;
829 object->baseTexture.pow2Matrix[5] = 1.0;
830 object->baseTexture.pow2Matrix[10] = 1.0;
831 object->baseTexture.pow2Matrix[15] = 1.0;
832 object->target = GL_TEXTURE_2D;
833 object->cond_np2 = TRUE;
834 object->baseTexture.minMipLookup = minMipLookup_noFilter;
835 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
836 (Width != pow2Width || Height != pow2Height) &&
837 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
839 object->baseTexture.pow2Matrix[0] = (float)Width;
840 object->baseTexture.pow2Matrix[5] = (float)Height;
841 object->baseTexture.pow2Matrix[10] = 1.0;
842 object->baseTexture.pow2Matrix[15] = 1.0;
843 object->target = GL_TEXTURE_RECTANGLE_ARB;
844 object->cond_np2 = TRUE;
845 object->baseTexture.minMipLookup = minMipLookup_noFilter;
846 } else {
847 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
848 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
849 object->baseTexture.pow2Matrix[10] = 1.0;
850 object->baseTexture.pow2Matrix[15] = 1.0;
851 object->target = GL_TEXTURE_2D;
852 object->cond_np2 = FALSE;
854 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
856 /* Calculate levels for mip mapping */
857 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
858 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
859 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
860 return WINED3DERR_INVALIDCALL;
862 if(Levels > 1) {
863 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
864 return WINED3DERR_INVALIDCALL;
866 object->baseTexture.levels = 1;
867 } else if (Levels == 0) {
868 object->baseTexture.levels = wined3d_log2i(max(Width, Height)) + 1;
869 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
872 /* Generate all the surfaces */
873 tmpW = Width;
874 tmpH = Height;
875 for (i = 0; i < object->baseTexture.levels; i++)
877 /* use the callback to create the texture surface */
878 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
879 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
880 FIXME("Failed to create surface %p\n", object);
881 /* clean up */
882 object->surfaces[i] = NULL;
883 IWineD3DTexture_Release((IWineD3DTexture *)object);
885 *ppTexture = NULL;
886 return hr;
889 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
890 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
891 surface_set_texture_target(object->surfaces[i], object->target);
892 /* calculate the next mipmap level */
893 tmpW = max(1, tmpW >> 1);
894 tmpH = max(1, tmpH >> 1);
896 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
898 TRACE("(%p) : Created texture %p\n", This, object);
899 return WINED3D_OK;
902 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
903 UINT Width, UINT Height, UINT Depth,
904 UINT Levels, DWORD Usage,
905 WINED3DFORMAT Format, WINED3DPOOL Pool,
906 IWineD3DVolumeTexture **ppVolumeTexture,
907 HANDLE *pSharedHandle, IUnknown *parent,
908 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
911 IWineD3DVolumeTextureImpl *object;
912 unsigned int i;
913 UINT tmpW;
914 UINT tmpH;
915 UINT tmpD;
916 const struct GlPixelFormatDesc *glDesc;
918 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
920 /* TODO: It should only be possible to create textures for formats
921 that are reported as supported */
922 if (WINED3DFMT_UNKNOWN >= Format) {
923 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
924 return WINED3DERR_INVALIDCALL;
926 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
927 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
928 return WINED3DERR_INVALIDCALL;
931 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
932 D3DINITIALIZEBASETEXTURE(object->baseTexture);
934 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
935 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
937 /* Is NP2 support for volumes needed? */
938 object->baseTexture.pow2Matrix[ 0] = 1.0;
939 object->baseTexture.pow2Matrix[ 5] = 1.0;
940 object->baseTexture.pow2Matrix[10] = 1.0;
941 object->baseTexture.pow2Matrix[15] = 1.0;
943 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
944 object->baseTexture.minMipLookup = minMipLookup;
945 object->baseTexture.magLookup = magLookup;
946 } else {
947 object->baseTexture.minMipLookup = minMipLookup_noFilter;
948 object->baseTexture.magLookup = magLookup_noFilter;
951 /* Calculate levels for mip mapping */
952 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
953 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
954 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
955 return WINED3DERR_INVALIDCALL;
957 if(Levels > 1) {
958 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
959 return WINED3DERR_INVALIDCALL;
961 object->baseTexture.levels = 1;
962 } else if (Levels == 0) {
963 object->baseTexture.levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
964 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
967 /* Generate all the surfaces */
968 tmpW = Width;
969 tmpH = Height;
970 tmpD = Depth;
972 for (i = 0; i < object->baseTexture.levels; i++)
974 HRESULT hr;
975 /* Create the volume */
976 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
977 &object->volumes[i], pSharedHandle);
979 if(FAILED(hr)) {
980 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
981 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
982 *ppVolumeTexture = NULL;
983 return hr;
986 /* Set its container to this object */
987 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
989 /* calculate the next mipmap level */
990 tmpW = max(1, tmpW >> 1);
991 tmpH = max(1, tmpH >> 1);
992 tmpD = max(1, tmpD >> 1);
994 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
996 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
997 TRACE("(%p) : Created volume texture %p\n", This, object);
998 return WINED3D_OK;
1001 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1002 UINT Width, UINT Height, UINT Depth,
1003 DWORD Usage,
1004 WINED3DFORMAT Format, WINED3DPOOL Pool,
1005 IWineD3DVolume** ppVolume,
1006 HANDLE* pSharedHandle, IUnknown *parent) {
1008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1009 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1010 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1012 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1013 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1014 return WINED3DERR_INVALIDCALL;
1017 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1019 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1020 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1022 object->currentDesc.Width = Width;
1023 object->currentDesc.Height = Height;
1024 object->currentDesc.Depth = Depth;
1025 object->bytesPerPixel = formatDesc->bpp;
1027 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1028 object->lockable = TRUE;
1029 object->locked = FALSE;
1030 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1031 object->dirty = TRUE;
1033 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1036 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1037 UINT Levels, DWORD Usage,
1038 WINED3DFORMAT Format, WINED3DPOOL Pool,
1039 IWineD3DCubeTexture **ppCubeTexture,
1040 HANDLE *pSharedHandle, IUnknown *parent,
1041 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1044 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1045 unsigned int i, j;
1046 UINT tmpW;
1047 HRESULT hr;
1048 unsigned int pow2EdgeLength;
1049 const struct GlPixelFormatDesc *glDesc;
1050 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1052 /* TODO: It should only be possible to create textures for formats
1053 that are reported as supported */
1054 if (WINED3DFMT_UNKNOWN >= Format) {
1055 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1056 return WINED3DERR_INVALIDCALL;
1059 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1060 WARN("(%p) : Tried to create not supported cube texture\n", This);
1061 return WINED3DERR_INVALIDCALL;
1064 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1065 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1067 TRACE("(%p) Create Cube Texture\n", This);
1069 /* Find the nearest pow2 match */
1070 pow2EdgeLength = 1;
1071 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1073 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
1074 /* Precalculated scaling for 'faked' non power of two texture coords */
1075 object->baseTexture.pow2Matrix[ 0] = 1.0;
1076 object->baseTexture.pow2Matrix[ 5] = 1.0;
1077 object->baseTexture.pow2Matrix[10] = 1.0;
1078 object->baseTexture.pow2Matrix[15] = 1.0;
1079 } else {
1080 /* Precalculated scaling for 'faked' non power of two texture coords */
1081 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1082 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1083 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1084 object->baseTexture.pow2Matrix[15] = 1.0;
1087 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1088 object->baseTexture.minMipLookup = minMipLookup;
1089 object->baseTexture.magLookup = magLookup;
1090 } else {
1091 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1092 object->baseTexture.magLookup = magLookup_noFilter;
1095 /* Calculate levels for mip mapping */
1096 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1097 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1098 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1099 HeapFree(GetProcessHeap(), 0, object);
1100 *ppCubeTexture = NULL;
1102 return WINED3DERR_INVALIDCALL;
1104 if(Levels > 1) {
1105 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1106 HeapFree(GetProcessHeap(), 0, object);
1107 *ppCubeTexture = NULL;
1109 return WINED3DERR_INVALIDCALL;
1111 object->baseTexture.levels = 1;
1112 } else if (Levels == 0) {
1113 object->baseTexture.levels = wined3d_log2i(EdgeLength) + 1;
1114 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1117 /* Generate all the surfaces */
1118 tmpW = EdgeLength;
1119 for (i = 0; i < object->baseTexture.levels; i++) {
1121 /* Create the 6 faces */
1122 for (j = 0; j < 6; j++) {
1123 static const GLenum cube_targets[6] = {
1124 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1125 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1126 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1127 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1128 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1129 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1132 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1133 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1135 if(hr!= WINED3D_OK) {
1136 /* clean up */
1137 unsigned int k;
1138 unsigned int l;
1139 for (l = 0; l < j; l++) {
1140 IWineD3DSurface_Release(object->surfaces[l][i]);
1142 for (k = 0; k < i; k++) {
1143 for (l = 0; l < 6; l++) {
1144 IWineD3DSurface_Release(object->surfaces[l][k]);
1148 FIXME("(%p) Failed to create surface\n",object);
1149 HeapFree(GetProcessHeap(),0,object);
1150 *ppCubeTexture = NULL;
1151 return hr;
1153 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1154 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1155 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1157 tmpW = max(1, tmpW >> 1);
1159 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
1161 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1162 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1163 return WINED3D_OK;
1166 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1168 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1169 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1170 const IWineD3DQueryVtbl *vtable;
1172 /* Just a check to see if we support this type of query */
1173 switch(Type) {
1174 case WINED3DQUERYTYPE_OCCLUSION:
1175 TRACE("(%p) occlusion query\n", This);
1176 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1177 hr = WINED3D_OK;
1178 else
1179 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1181 vtable = &IWineD3DOcclusionQuery_Vtbl;
1182 break;
1184 case WINED3DQUERYTYPE_EVENT:
1185 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1186 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1187 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1189 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1191 vtable = &IWineD3DEventQuery_Vtbl;
1192 hr = WINED3D_OK;
1193 break;
1195 case WINED3DQUERYTYPE_VCACHE:
1196 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1197 case WINED3DQUERYTYPE_VERTEXSTATS:
1198 case WINED3DQUERYTYPE_TIMESTAMP:
1199 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1200 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1201 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1202 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1203 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1204 case WINED3DQUERYTYPE_PIXELTIMINGS:
1205 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1206 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1207 default:
1208 /* Use the base Query vtable until we have a special one for each query */
1209 vtable = &IWineD3DQuery_Vtbl;
1210 FIXME("(%p) Unhandled query type %d\n", This, Type);
1212 if(NULL == ppQuery || hr != WINED3D_OK) {
1213 return hr;
1216 D3DCREATEOBJECTINSTANCE(object, Query)
1217 object->lpVtbl = vtable;
1218 object->type = Type;
1219 object->state = QUERY_CREATED;
1220 /* allocated the 'extended' data based on the type of query requested */
1221 switch(Type){
1222 case WINED3DQUERYTYPE_OCCLUSION:
1223 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1224 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1226 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1227 TRACE("(%p) Allocating data for an occlusion query\n", This);
1229 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1230 ENTER_GL();
1231 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1232 LEAVE_GL();
1233 break;
1235 case WINED3DQUERYTYPE_EVENT:
1236 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1237 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1239 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1240 ENTER_GL();
1241 if(GL_SUPPORT(APPLE_FENCE)) {
1242 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1243 checkGLcall("glGenFencesAPPLE");
1244 } else if(GL_SUPPORT(NV_FENCE)) {
1245 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1246 checkGLcall("glGenFencesNV");
1248 LEAVE_GL();
1249 break;
1251 case WINED3DQUERYTYPE_VCACHE:
1252 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1253 case WINED3DQUERYTYPE_VERTEXSTATS:
1254 case WINED3DQUERYTYPE_TIMESTAMP:
1255 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1256 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1257 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1258 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1259 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1260 case WINED3DQUERYTYPE_PIXELTIMINGS:
1261 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1262 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1263 default:
1264 object->extendedData = 0;
1265 FIXME("(%p) Unhandled query type %d\n",This , Type);
1267 TRACE("(%p) : Created Query %p\n", This, object);
1268 return WINED3D_OK;
1271 /*****************************************************************************
1272 * IWineD3DDeviceImpl_SetupFullscreenWindow
1274 * Helper function that modifies a HWND's Style and ExStyle for proper
1275 * fullscreen use.
1277 * Params:
1278 * iface: Pointer to the IWineD3DDevice interface
1279 * window: Window to setup
1281 *****************************************************************************/
1282 static LONG fullscreen_style(LONG orig_style) {
1283 LONG style = orig_style;
1284 style &= ~WS_CAPTION;
1285 style &= ~WS_THICKFRAME;
1287 /* Make sure the window is managed, otherwise we won't get keyboard input */
1288 style |= WS_POPUP | WS_SYSMENU;
1290 return style;
1293 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1294 LONG exStyle = orig_exStyle;
1296 /* Filter out window decorations */
1297 exStyle &= ~WS_EX_WINDOWEDGE;
1298 exStyle &= ~WS_EX_CLIENTEDGE;
1300 return exStyle;
1303 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1306 LONG style, exStyle;
1307 /* Don't do anything if an original style is stored.
1308 * That shouldn't happen
1310 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1311 if (This->style || This->exStyle) {
1312 ERR("(%p): Want to change the window parameters of HWND %p, but "
1313 "another style is stored for restoration afterwards\n", This, window);
1316 /* Get the parameters and save them */
1317 style = GetWindowLongW(window, GWL_STYLE);
1318 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1319 This->style = style;
1320 This->exStyle = exStyle;
1322 style = fullscreen_style(style);
1323 exStyle = fullscreen_exStyle(exStyle);
1325 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1326 This->style, This->exStyle, style, exStyle);
1328 SetWindowLongW(window, GWL_STYLE, style);
1329 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1331 /* Inform the window about the update. */
1332 SetWindowPos(window, HWND_TOP, 0, 0,
1333 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1336 /*****************************************************************************
1337 * IWineD3DDeviceImpl_RestoreWindow
1339 * Helper function that restores a windows' properties when taking it out
1340 * of fullscreen mode
1342 * Params:
1343 * iface: Pointer to the IWineD3DDevice interface
1344 * window: Window to setup
1346 *****************************************************************************/
1347 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1349 LONG style, exStyle;
1351 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1352 * switch, do nothing
1354 if (!This->style && !This->exStyle) return;
1356 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1357 This, window, This->style, This->exStyle);
1359 style = GetWindowLongW(window, GWL_STYLE);
1360 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1362 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1363 * Some applications change it before calling Reset() when switching between windowed and
1364 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1366 if(style == fullscreen_style(This->style) &&
1367 exStyle == fullscreen_style(This->exStyle)) {
1368 SetWindowLongW(window, GWL_STYLE, This->style);
1369 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1372 /* Delete the old values */
1373 This->style = 0;
1374 This->exStyle = 0;
1376 /* Inform the window about the update */
1377 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1378 0, 0, 0, 0, /* Pos, Size, ignored */
1379 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1382 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1383 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice* iface,
1384 WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1385 IUnknown* parent, D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1386 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil, WINED3DSURFTYPE surface_type)
1388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1390 HDC hDc;
1391 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1392 HRESULT hr;
1393 IUnknown *bufferParent;
1394 BOOL displaymode_set = FALSE;
1395 WINED3DDISPLAYMODE Mode;
1396 const StaticPixelFormatDesc *formatDesc;
1398 TRACE("(%p) : Created Additional Swap Chain\n", This);
1400 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1401 * does a device hold a reference to a swap chain giving them a lifetime of the device
1402 * or does the swap chain notify the device of its destruction.
1403 *******************************/
1405 /* Check the params */
1406 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1407 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1408 return WINED3DERR_INVALIDCALL;
1409 } else if (pPresentationParameters->BackBufferCount > 1) {
1410 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");
1413 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1414 switch(surface_type) {
1415 case SURFACE_GDI:
1416 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1417 break;
1418 case SURFACE_OPENGL:
1419 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1420 break;
1421 case SURFACE_UNKNOWN:
1422 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1423 return WINED3DERR_INVALIDCALL;
1426 /*********************
1427 * Lookup the window Handle and the relating X window handle
1428 ********************/
1430 /* Setup hwnd we are using, plus which display this equates to */
1431 object->win_handle = pPresentationParameters->hDeviceWindow;
1432 if (!object->win_handle) {
1433 object->win_handle = This->createParms.hFocusWindow;
1435 if(!pPresentationParameters->Windowed && object->win_handle) {
1436 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1437 pPresentationParameters->BackBufferWidth,
1438 pPresentationParameters->BackBufferHeight);
1441 hDc = GetDC(object->win_handle);
1442 TRACE("Using hDc %p\n", hDc);
1444 if (NULL == hDc) {
1445 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1446 return WINED3DERR_NOTAVAILABLE;
1449 /* Get info on the current display setup */
1450 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1451 object->orig_width = Mode.Width;
1452 object->orig_height = Mode.Height;
1453 object->orig_fmt = Mode.Format;
1454 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1456 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1457 * then the corresponding dimension of the client area of the hDeviceWindow
1458 * (or the focus window, if hDeviceWindow is NULL) is taken.
1459 **********************/
1461 if (pPresentationParameters->Windowed &&
1462 ((pPresentationParameters->BackBufferWidth == 0) ||
1463 (pPresentationParameters->BackBufferHeight == 0) ||
1464 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1466 RECT Rect;
1467 GetClientRect(object->win_handle, &Rect);
1469 if (pPresentationParameters->BackBufferWidth == 0) {
1470 pPresentationParameters->BackBufferWidth = Rect.right;
1471 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1473 if (pPresentationParameters->BackBufferHeight == 0) {
1474 pPresentationParameters->BackBufferHeight = Rect.bottom;
1475 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1477 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1478 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1479 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1483 /* Put the correct figures in the presentation parameters */
1484 TRACE("Copying across presentation parameters\n");
1485 object->presentParms = *pPresentationParameters;
1487 TRACE("calling rendertarget CB\n");
1488 hr = D3DCB_CreateRenderTarget(This->parent,
1489 parent,
1490 object->presentParms.BackBufferWidth,
1491 object->presentParms.BackBufferHeight,
1492 object->presentParms.BackBufferFormat,
1493 object->presentParms.MultiSampleType,
1494 object->presentParms.MultiSampleQuality,
1495 TRUE /* Lockable */,
1496 &object->frontBuffer,
1497 NULL /* pShared (always null)*/);
1498 if (SUCCEEDED(hr)) {
1499 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1500 if(surface_type == SURFACE_OPENGL) {
1501 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1503 } else {
1504 ERR("Failed to create the front buffer\n");
1505 goto error;
1508 /*********************
1509 * Windowed / Fullscreen
1510 *******************/
1513 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1514 * so we should really check to see if there is a fullscreen swapchain already
1515 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1516 **************************************/
1518 if (!pPresentationParameters->Windowed) {
1519 WINED3DDISPLAYMODE mode;
1522 /* Change the display settings */
1523 mode.Width = pPresentationParameters->BackBufferWidth;
1524 mode.Height = pPresentationParameters->BackBufferHeight;
1525 mode.Format = pPresentationParameters->BackBufferFormat;
1526 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1528 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1529 displaymode_set = TRUE;
1533 * Create an opengl context for the display visual
1534 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1535 * use different properties after that point in time. FIXME: How to handle when requested format
1536 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1537 * it chooses is identical to the one already being used!
1538 **********************************/
1539 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1541 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1542 if(!object->context) {
1543 ERR("Failed to create the context array\n");
1544 hr = E_OUTOFMEMORY;
1545 goto error;
1547 object->num_contexts = 1;
1549 if(surface_type == SURFACE_OPENGL) {
1550 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1551 if (!object->context[0]) {
1552 ERR("Failed to create a new context\n");
1553 hr = WINED3DERR_NOTAVAILABLE;
1554 goto error;
1555 } else {
1556 TRACE("Context created (HWND=%p, glContext=%p)\n",
1557 object->win_handle, object->context[0]->glCtx);
1561 /*********************
1562 * Create the back, front and stencil buffers
1563 *******************/
1564 if(object->presentParms.BackBufferCount > 0) {
1565 UINT i;
1567 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1568 if(!object->backBuffer) {
1569 ERR("Out of memory\n");
1570 hr = E_OUTOFMEMORY;
1571 goto error;
1574 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1575 TRACE("calling rendertarget CB\n");
1576 hr = D3DCB_CreateRenderTarget(This->parent,
1577 parent,
1578 object->presentParms.BackBufferWidth,
1579 object->presentParms.BackBufferHeight,
1580 object->presentParms.BackBufferFormat,
1581 object->presentParms.MultiSampleType,
1582 object->presentParms.MultiSampleQuality,
1583 TRUE /* Lockable */,
1584 &object->backBuffer[i],
1585 NULL /* pShared (always null)*/);
1586 if(SUCCEEDED(hr)) {
1587 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1588 } else {
1589 ERR("Cannot create new back buffer\n");
1590 goto error;
1592 if(surface_type == SURFACE_OPENGL) {
1593 ENTER_GL();
1594 glDrawBuffer(GL_BACK);
1595 checkGLcall("glDrawBuffer(GL_BACK)");
1596 LEAVE_GL();
1599 } else {
1600 object->backBuffer = NULL;
1602 /* Single buffering - draw to front buffer */
1603 if(surface_type == SURFACE_OPENGL) {
1604 ENTER_GL();
1605 glDrawBuffer(GL_FRONT);
1606 checkGLcall("glDrawBuffer(GL_FRONT)");
1607 LEAVE_GL();
1611 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1612 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1613 TRACE("Creating depth stencil buffer\n");
1614 if (This->auto_depth_stencil_buffer == NULL ) {
1615 hr = D3DCB_CreateDepthStencil(This->parent,
1616 parent,
1617 object->presentParms.BackBufferWidth,
1618 object->presentParms.BackBufferHeight,
1619 object->presentParms.AutoDepthStencilFormat,
1620 object->presentParms.MultiSampleType,
1621 object->presentParms.MultiSampleQuality,
1622 FALSE /* FIXME: Discard */,
1623 &This->auto_depth_stencil_buffer,
1624 NULL /* pShared (always null)*/ );
1625 if (SUCCEEDED(hr)) {
1626 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1627 } else {
1628 ERR("Failed to create the auto depth stencil\n");
1629 goto error;
1634 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1636 TRACE("Created swapchain %p\n", object);
1637 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1638 return WINED3D_OK;
1640 error:
1641 if (displaymode_set) {
1642 DEVMODEW devmode;
1643 RECT clip_rc;
1645 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1646 ClipCursor(NULL);
1648 /* Change the display settings */
1649 memset(&devmode, 0, sizeof(devmode));
1650 devmode.dmSize = sizeof(devmode);
1651 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1652 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1653 devmode.dmPelsWidth = object->orig_width;
1654 devmode.dmPelsHeight = object->orig_height;
1655 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1658 if (object->backBuffer) {
1659 UINT i;
1660 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1661 if(object->backBuffer[i]) {
1662 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1663 IUnknown_Release(bufferParent); /* once for the get parent */
1664 if (IUnknown_Release(bufferParent) > 0) {
1665 FIXME("(%p) Something's still holding the back buffer\n",This);
1669 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1670 object->backBuffer = NULL;
1672 if(object->context && object->context[0])
1673 DestroyContext(This, object->context[0]);
1674 if(object->frontBuffer) {
1675 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1676 IUnknown_Release(bufferParent); /* once for the get parent */
1677 if (IUnknown_Release(bufferParent) > 0) {
1678 FIXME("(%p) Something's still holding the front buffer\n",This);
1681 HeapFree(GetProcessHeap(), 0, object);
1682 return hr;
1685 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1686 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1688 TRACE("(%p)\n", This);
1690 return This->NumberOfSwapChains;
1693 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1695 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1697 if(iSwapChain < This->NumberOfSwapChains) {
1698 *pSwapChain = This->swapchains[iSwapChain];
1699 IWineD3DSwapChain_AddRef(*pSwapChain);
1700 TRACE("(%p) returning %p\n", This, *pSwapChain);
1701 return WINED3D_OK;
1702 } else {
1703 TRACE("Swapchain out of range\n");
1704 *pSwapChain = NULL;
1705 return WINED3DERR_INVALIDCALL;
1709 /*****
1710 * Vertex Declaration
1711 *****/
1712 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1713 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1715 IWineD3DVertexDeclarationImpl *object = NULL;
1716 HRESULT hr = WINED3D_OK;
1718 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1719 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1721 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1723 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1724 if(FAILED(hr)) {
1725 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1726 *ppVertexDeclaration = NULL;
1729 return hr;
1732 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1733 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1735 unsigned int idx, idx2;
1736 unsigned int offset;
1737 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1738 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1739 BOOL has_blend_idx = has_blend &&
1740 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1741 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1742 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1743 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1744 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1745 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1746 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1748 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1749 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1751 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1752 WINED3DVERTEXELEMENT *elements = NULL;
1754 unsigned int size;
1755 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1756 if (has_blend_idx) num_blends--;
1758 /* Compute declaration size */
1759 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1760 has_psize + has_diffuse + has_specular + num_textures + 1;
1762 /* convert the declaration */
1763 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1764 if (!elements)
1765 return 0;
1767 elements[size-1] = end_element;
1768 idx = 0;
1769 if (has_pos) {
1770 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1771 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1772 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1774 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1775 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1776 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1778 else {
1779 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1780 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1782 elements[idx].UsageIndex = 0;
1783 idx++;
1785 if (has_blend && (num_blends > 0)) {
1786 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1787 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1788 else {
1789 switch(num_blends) {
1790 case 1: elements[idx].Type = WINED3DDECLTYPE_FLOAT1; break;
1791 case 2: elements[idx].Type = WINED3DDECLTYPE_FLOAT2; break;
1792 case 3: elements[idx].Type = WINED3DDECLTYPE_FLOAT3; break;
1793 case 4: elements[idx].Type = WINED3DDECLTYPE_FLOAT4; break;
1794 default:
1795 ERR("Unexpected amount of blend values: %u\n", num_blends);
1798 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1799 elements[idx].UsageIndex = 0;
1800 idx++;
1802 if (has_blend_idx) {
1803 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1804 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1805 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1806 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1807 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1808 else
1809 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1810 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1811 elements[idx].UsageIndex = 0;
1812 idx++;
1814 if (has_normal) {
1815 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1816 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1817 elements[idx].UsageIndex = 0;
1818 idx++;
1820 if (has_psize) {
1821 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1822 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1823 elements[idx].UsageIndex = 0;
1824 idx++;
1826 if (has_diffuse) {
1827 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1828 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1829 elements[idx].UsageIndex = 0;
1830 idx++;
1832 if (has_specular) {
1833 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1834 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1835 elements[idx].UsageIndex = 1;
1836 idx++;
1838 for (idx2 = 0; idx2 < num_textures; idx2++) {
1839 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1840 switch (numcoords) {
1841 case WINED3DFVF_TEXTUREFORMAT1:
1842 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1843 break;
1844 case WINED3DFVF_TEXTUREFORMAT2:
1845 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1846 break;
1847 case WINED3DFVF_TEXTUREFORMAT3:
1848 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1849 break;
1850 case WINED3DFVF_TEXTUREFORMAT4:
1851 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1852 break;
1854 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1855 elements[idx].UsageIndex = idx2;
1856 idx++;
1859 /* Now compute offsets, and initialize the rest of the fields */
1860 for (idx = 0, offset = 0; idx < size-1; idx++) {
1861 elements[idx].Stream = 0;
1862 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1863 elements[idx].Offset = offset;
1864 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1867 *ppVertexElements = elements;
1868 return size;
1871 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1872 WINED3DVERTEXELEMENT* elements = NULL;
1873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1874 unsigned int size;
1875 DWORD hr;
1877 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1878 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1880 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1881 HeapFree(GetProcessHeap(), 0, elements);
1882 if (hr != S_OK) return hr;
1884 return WINED3D_OK;
1887 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1889 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1890 HRESULT hr = WINED3D_OK;
1892 if (!pFunction) return WINED3DERR_INVALIDCALL;
1894 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1895 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1897 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1899 if (vertex_declaration) {
1900 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1903 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1905 if (WINED3D_OK != hr) {
1906 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1907 IWineD3DVertexShader_Release(*ppVertexShader);
1908 return WINED3DERR_INVALIDCALL;
1910 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1912 return WINED3D_OK;
1915 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1917 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1918 HRESULT hr = WINED3D_OK;
1920 if (!pFunction) return WINED3DERR_INVALIDCALL;
1922 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1923 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1924 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1925 if (WINED3D_OK == hr) {
1926 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1927 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1928 } else {
1929 WARN("(%p) : Failed to create pixel shader\n", This);
1932 return hr;
1935 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1936 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1939 IWineD3DPaletteImpl *object;
1940 HRESULT hr;
1941 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1943 /* Create the new object */
1944 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1945 if(!object) {
1946 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1947 return E_OUTOFMEMORY;
1950 object->lpVtbl = &IWineD3DPalette_Vtbl;
1951 object->ref = 1;
1952 object->Flags = Flags;
1953 object->parent = Parent;
1954 object->wineD3DDevice = This;
1955 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1957 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1959 if(!object->hpal) {
1960 HeapFree( GetProcessHeap(), 0, object);
1961 return E_OUTOFMEMORY;
1964 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1965 if(FAILED(hr)) {
1966 IWineD3DPalette_Release((IWineD3DPalette *) object);
1967 return hr;
1970 *Palette = (IWineD3DPalette *) object;
1972 return WINED3D_OK;
1975 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1976 HBITMAP hbm;
1977 BITMAP bm;
1978 HRESULT hr;
1979 HDC dcb = NULL, dcs = NULL;
1980 WINEDDCOLORKEY colorkey;
1982 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1983 if(hbm)
1985 GetObjectA(hbm, sizeof(BITMAP), &bm);
1986 dcb = CreateCompatibleDC(NULL);
1987 if(!dcb) goto out;
1988 SelectObject(dcb, hbm);
1990 else
1992 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1993 * couldn't be loaded
1995 memset(&bm, 0, sizeof(bm));
1996 bm.bmWidth = 32;
1997 bm.bmHeight = 32;
2000 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2001 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2002 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
2003 if(FAILED(hr)) {
2004 ERR("Wine logo requested, but failed to create surface\n");
2005 goto out;
2008 if(dcb) {
2009 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2010 if(FAILED(hr)) goto out;
2011 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2012 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2014 colorkey.dwColorSpaceLowValue = 0;
2015 colorkey.dwColorSpaceHighValue = 0;
2016 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2017 } else {
2018 /* Fill the surface with a white color to show that wined3d is there */
2019 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2022 out:
2023 if(dcb) {
2024 DeleteDC(dcb);
2026 if(hbm) {
2027 DeleteObject(hbm);
2029 return;
2032 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2033 unsigned int i;
2034 /* Under DirectX you can have texture stage operations even if no texture is
2035 bound, whereas opengl will only do texture operations when a valid texture is
2036 bound. We emulate this by creating dummy textures and binding them to each
2037 texture stage, but disable all stages by default. Hence if a stage is enabled
2038 then the default texture will kick in until replaced by a SetTexture call */
2039 ENTER_GL();
2041 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2042 /* The dummy texture does not have client storage backing */
2043 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2044 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2046 for (i = 0; i < GL_LIMITS(textures); i++) {
2047 GLubyte white = 255;
2049 /* Make appropriate texture active */
2050 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2051 checkGLcall("glActiveTextureARB");
2053 /* Generate an opengl texture name */
2054 glGenTextures(1, &This->dummyTextureName[i]);
2055 checkGLcall("glGenTextures");
2056 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2058 /* Generate a dummy 2d texture (not using 1d because they cause many
2059 * DRI drivers fall back to sw) */
2060 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2061 checkGLcall("glBindTexture");
2063 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2064 checkGLcall("glTexImage2D");
2066 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2067 /* Reenable because if supported it is enabled by default */
2068 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2069 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2072 LEAVE_GL();
2075 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2077 IWineD3DSwapChainImpl *swapchain = NULL;
2078 HRESULT hr;
2079 DWORD state;
2080 unsigned int i;
2082 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateSwapChain);
2083 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2084 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2086 /* TODO: Test if OpenGL is compiled in and loaded */
2088 TRACE("(%p) : Creating stateblock\n", This);
2089 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2090 hr = IWineD3DDevice_CreateStateBlock(iface,
2091 WINED3DSBT_INIT,
2092 (IWineD3DStateBlock **)&This->stateBlock,
2093 NULL);
2094 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2095 WARN("Failed to create stateblock\n");
2096 goto err_out;
2098 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2099 This->updateStateBlock = This->stateBlock;
2100 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2102 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2103 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2105 This->NumberOfPalettes = 1;
2106 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2107 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2108 ERR("Out of memory!\n");
2109 goto err_out;
2111 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2112 if(!This->palettes[0]) {
2113 ERR("Out of memory!\n");
2114 goto err_out;
2116 for (i = 0; i < 256; ++i) {
2117 This->palettes[0][i].peRed = 0xFF;
2118 This->palettes[0][i].peGreen = 0xFF;
2119 This->palettes[0][i].peBlue = 0xFF;
2120 This->palettes[0][i].peFlags = 0xFF;
2122 This->currentPalette = 0;
2124 /* Initialize the texture unit mapping to a 1:1 mapping */
2125 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2126 if (state < GL_LIMITS(fragment_samplers)) {
2127 This->texUnitMap[state] = state;
2128 This->rev_tex_unit_map[state] = state;
2129 } else {
2130 This->texUnitMap[state] = -1;
2131 This->rev_tex_unit_map[state] = -1;
2135 /* Setup the implicit swapchain */
2136 TRACE("Creating implicit swapchain\n");
2137 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2138 if (FAILED(hr) || !swapchain) {
2139 WARN("Failed to create implicit swapchain\n");
2140 goto err_out;
2143 This->NumberOfSwapChains = 1;
2144 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2145 if(!This->swapchains) {
2146 ERR("Out of memory!\n");
2147 goto err_out;
2149 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2151 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2152 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2153 This->render_targets[0] = swapchain->backBuffer[0];
2154 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2156 else {
2157 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2158 This->render_targets[0] = swapchain->frontBuffer;
2159 This->lastActiveRenderTarget = swapchain->frontBuffer;
2161 IWineD3DSurface_AddRef(This->render_targets[0]);
2162 This->activeContext = swapchain->context[0];
2163 This->lastThread = GetCurrentThreadId();
2165 /* Depth Stencil support */
2166 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2167 if (NULL != This->stencilBufferTarget) {
2168 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2171 hr = This->shader_backend->shader_alloc_private(iface);
2172 if(FAILED(hr)) {
2173 TRACE("Shader private data couldn't be allocated\n");
2174 goto err_out;
2176 hr = This->frag_pipe->alloc_private(iface);
2177 if(FAILED(hr)) {
2178 TRACE("Fragment pipeline private data couldn't be allocated\n");
2179 goto err_out;
2181 hr = This->blitter->alloc_private(iface);
2182 if(FAILED(hr)) {
2183 TRACE("Blitter private data couldn't be allocated\n");
2184 goto err_out;
2187 /* Set up some starting GL setup */
2189 /* Setup all the devices defaults */
2190 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2191 create_dummy_textures(This);
2193 ENTER_GL();
2195 /* Initialize the current view state */
2196 This->view_ident = 1;
2197 This->contexts[0]->last_was_rhw = 0;
2198 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2199 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2201 switch(wined3d_settings.offscreen_rendering_mode) {
2202 case ORM_FBO:
2203 case ORM_PBUFFER:
2204 This->offscreenBuffer = GL_BACK;
2205 break;
2207 case ORM_BACKBUFFER:
2209 if(This->activeContext->aux_buffers > 0) {
2210 TRACE("Using auxilliary buffer for offscreen rendering\n");
2211 This->offscreenBuffer = GL_AUX0;
2212 } else {
2213 TRACE("Using back buffer for offscreen rendering\n");
2214 This->offscreenBuffer = GL_BACK;
2219 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2220 LEAVE_GL();
2222 /* Clear the screen */
2223 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2224 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2225 0x00, 1.0, 0);
2227 This->d3d_initialized = TRUE;
2229 if(wined3d_settings.logo) {
2230 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2232 This->highest_dirty_ps_const = 0;
2233 This->highest_dirty_vs_const = 0;
2234 return WINED3D_OK;
2236 err_out:
2237 HeapFree(GetProcessHeap(), 0, This->render_targets);
2238 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2239 HeapFree(GetProcessHeap(), 0, This->swapchains);
2240 This->NumberOfSwapChains = 0;
2241 if(This->palettes) {
2242 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2243 HeapFree(GetProcessHeap(), 0, This->palettes);
2245 This->NumberOfPalettes = 0;
2246 if(swapchain) {
2247 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2249 if(This->stateBlock) {
2250 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2251 This->stateBlock = NULL;
2253 if (This->blit_priv) {
2254 This->blitter->free_private(iface);
2256 if (This->fragment_priv) {
2257 This->frag_pipe->free_private(iface);
2259 if (This->shader_priv) {
2260 This->shader_backend->shader_free_private(iface);
2262 return hr;
2265 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2267 IWineD3DSwapChainImpl *swapchain = NULL;
2268 HRESULT hr;
2270 /* Setup the implicit swapchain */
2271 TRACE("Creating implicit swapchain\n");
2272 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2273 if (FAILED(hr) || !swapchain) {
2274 WARN("Failed to create implicit swapchain\n");
2275 goto err_out;
2278 This->NumberOfSwapChains = 1;
2279 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2280 if(!This->swapchains) {
2281 ERR("Out of memory!\n");
2282 goto err_out;
2284 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2285 return WINED3D_OK;
2287 err_out:
2288 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2289 return hr;
2292 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2294 int sampler;
2295 UINT i;
2296 TRACE("(%p)\n", This);
2298 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2300 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2301 * it was created. Thus make sure a context is active for the glDelete* calls
2303 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2305 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2307 TRACE("Deleting high order patches\n");
2308 for(i = 0; i < PATCHMAP_SIZE; i++) {
2309 struct list *e1, *e2;
2310 struct WineD3DRectPatch *patch;
2311 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2312 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2313 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2317 /* Delete the palette conversion shader if it is around */
2318 if(This->paletteConversionShader) {
2319 ENTER_GL();
2320 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2321 LEAVE_GL();
2322 This->paletteConversionShader = 0;
2325 /* Delete the pbuffer context if there is any */
2326 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2328 /* Delete the mouse cursor texture */
2329 if(This->cursorTexture) {
2330 ENTER_GL();
2331 glDeleteTextures(1, &This->cursorTexture);
2332 LEAVE_GL();
2333 This->cursorTexture = 0;
2336 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2337 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2339 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2340 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2343 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2344 * private data, it might contain opengl pointers
2346 if(This->depth_blt_texture) {
2347 glDeleteTextures(1, &This->depth_blt_texture);
2348 This->depth_blt_texture = 0;
2350 if (This->depth_blt_rb) {
2351 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2352 This->depth_blt_rb = 0;
2353 This->depth_blt_rb_w = 0;
2354 This->depth_blt_rb_h = 0;
2357 /* Release the update stateblock */
2358 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2359 if(This->updateStateBlock != This->stateBlock)
2360 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2362 This->updateStateBlock = NULL;
2364 { /* because were not doing proper internal refcounts releasing the primary state block
2365 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2366 to set this->stateBlock = NULL; first */
2367 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2368 This->stateBlock = NULL;
2370 /* Release the stateblock */
2371 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2372 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2376 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2377 This->blitter->free_private(iface);
2378 This->frag_pipe->free_private(iface);
2379 This->shader_backend->shader_free_private(iface);
2381 /* Release the buffers (with sanity checks)*/
2382 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2383 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2384 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2385 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2387 This->stencilBufferTarget = NULL;
2389 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2390 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2391 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2393 TRACE("Setting rendertarget to NULL\n");
2394 This->render_targets[0] = NULL;
2396 if (This->auto_depth_stencil_buffer) {
2397 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2398 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2400 This->auto_depth_stencil_buffer = NULL;
2403 for(i=0; i < This->NumberOfSwapChains; i++) {
2404 TRACE("Releasing the implicit swapchain %d\n", i);
2405 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2406 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2410 HeapFree(GetProcessHeap(), 0, This->swapchains);
2411 This->swapchains = NULL;
2412 This->NumberOfSwapChains = 0;
2414 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2415 HeapFree(GetProcessHeap(), 0, This->palettes);
2416 This->palettes = NULL;
2417 This->NumberOfPalettes = 0;
2419 HeapFree(GetProcessHeap(), 0, This->render_targets);
2420 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2421 This->render_targets = NULL;
2422 This->draw_buffers = NULL;
2424 This->d3d_initialized = FALSE;
2425 return WINED3D_OK;
2428 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2430 unsigned int i;
2432 for(i=0; i < This->NumberOfSwapChains; i++) {
2433 TRACE("Releasing the implicit swapchain %d\n", i);
2434 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2435 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2439 HeapFree(GetProcessHeap(), 0, This->swapchains);
2440 This->swapchains = NULL;
2441 This->NumberOfSwapChains = 0;
2442 return WINED3D_OK;
2445 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2446 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2447 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2449 * There is no way to deactivate thread safety once it is enabled.
2451 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2454 /*For now just store the flag(needed in case of ddraw) */
2455 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2457 return;
2460 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2461 const WINED3DDISPLAYMODE* pMode) {
2462 DEVMODEW devmode;
2463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2464 LONG ret;
2465 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2466 RECT clip_rc;
2468 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2470 /* Resize the screen even without a window:
2471 * The app could have unset it with SetCooperativeLevel, but not called
2472 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2473 * but we don't have any hwnd
2476 memset(&devmode, 0, sizeof(devmode));
2477 devmode.dmSize = sizeof(devmode);
2478 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2479 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2480 devmode.dmPelsWidth = pMode->Width;
2481 devmode.dmPelsHeight = pMode->Height;
2483 devmode.dmDisplayFrequency = pMode->RefreshRate;
2484 if (pMode->RefreshRate != 0) {
2485 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2488 /* Only change the mode if necessary */
2489 if( (This->ddraw_width == pMode->Width) &&
2490 (This->ddraw_height == pMode->Height) &&
2491 (This->ddraw_format == pMode->Format) &&
2492 (pMode->RefreshRate == 0) ) {
2493 return WINED3D_OK;
2496 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2497 if (ret != DISP_CHANGE_SUCCESSFUL) {
2498 if(devmode.dmDisplayFrequency != 0) {
2499 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2500 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2501 devmode.dmDisplayFrequency = 0;
2502 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2504 if(ret != DISP_CHANGE_SUCCESSFUL) {
2505 return WINED3DERR_NOTAVAILABLE;
2509 /* Store the new values */
2510 This->ddraw_width = pMode->Width;
2511 This->ddraw_height = pMode->Height;
2512 This->ddraw_format = pMode->Format;
2514 /* And finally clip mouse to our screen */
2515 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2516 ClipCursor(&clip_rc);
2518 return WINED3D_OK;
2521 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2523 *ppD3D= This->wineD3D;
2524 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2525 IWineD3D_AddRef(*ppD3D);
2526 return WINED3D_OK;
2529 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2532 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2533 (This->adapter->TextureRam/(1024*1024)),
2534 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2535 /* return simulated texture memory left */
2536 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2539 /*****
2540 * Get / Set Stream Source
2541 *****/
2542 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2544 IWineD3DVertexBuffer *oldSrc;
2546 if (StreamNumber >= MAX_STREAMS) {
2547 WARN("Stream out of range %d\n", StreamNumber);
2548 return WINED3DERR_INVALIDCALL;
2549 } else if(OffsetInBytes & 0x3) {
2550 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2551 return WINED3DERR_INVALIDCALL;
2554 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2555 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2557 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2559 if(oldSrc == pStreamData &&
2560 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2561 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2562 TRACE("Application is setting the old values over, nothing to do\n");
2563 return WINED3D_OK;
2566 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2567 if (pStreamData) {
2568 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2569 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2572 /* Handle recording of state blocks */
2573 if (This->isRecordingState) {
2574 TRACE("Recording... not performing anything\n");
2575 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2576 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2577 return WINED3D_OK;
2580 /* Need to do a getParent and pass the references up */
2581 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2582 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2583 so for now, just count internally */
2584 if (pStreamData != NULL) {
2585 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2586 InterlockedIncrement(&vbImpl->bindCount);
2587 IWineD3DVertexBuffer_AddRef(pStreamData);
2589 if (oldSrc != NULL) {
2590 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2591 IWineD3DVertexBuffer_Release(oldSrc);
2594 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2596 return WINED3D_OK;
2599 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2602 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2603 This->stateBlock->streamSource[StreamNumber],
2604 This->stateBlock->streamOffset[StreamNumber],
2605 This->stateBlock->streamStride[StreamNumber]);
2607 if (StreamNumber >= MAX_STREAMS) {
2608 WARN("Stream out of range %d\n", StreamNumber);
2609 return WINED3DERR_INVALIDCALL;
2611 *pStream = This->stateBlock->streamSource[StreamNumber];
2612 *pStride = This->stateBlock->streamStride[StreamNumber];
2613 if (pOffset) {
2614 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2617 if (*pStream != NULL) {
2618 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2620 return WINED3D_OK;
2623 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2625 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2626 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2628 /* Verify input at least in d3d9 this is invalid*/
2629 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2630 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2631 return WINED3DERR_INVALIDCALL;
2633 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2634 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2635 return WINED3DERR_INVALIDCALL;
2637 if( Divider == 0 ){
2638 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2639 return WINED3DERR_INVALIDCALL;
2642 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2643 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2645 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2646 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2648 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2649 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2650 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2653 return WINED3D_OK;
2656 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2659 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2660 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2662 TRACE("(%p) : returning %d\n", This, *Divider);
2664 return WINED3D_OK;
2667 /*****
2668 * Get / Set & Multiply Transform
2669 *****/
2670 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2673 /* Most of this routine, comments included copied from ddraw tree initially: */
2674 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2676 /* Handle recording of state blocks */
2677 if (This->isRecordingState) {
2678 TRACE("Recording... not performing anything\n");
2679 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2680 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2681 return WINED3D_OK;
2685 * If the new matrix is the same as the current one,
2686 * we cut off any further processing. this seems to be a reasonable
2687 * optimization because as was noticed, some apps (warcraft3 for example)
2688 * tend towards setting the same matrix repeatedly for some reason.
2690 * From here on we assume that the new matrix is different, wherever it matters.
2692 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2693 TRACE("The app is setting the same matrix over again\n");
2694 return WINED3D_OK;
2695 } else {
2696 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2700 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2701 where ViewMat = Camera space, WorldMat = world space.
2703 In OpenGL, camera and world space is combined into GL_MODELVIEW
2704 matrix. The Projection matrix stay projection matrix.
2707 /* Capture the times we can just ignore the change for now */
2708 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2709 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2710 /* Handled by the state manager */
2713 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2714 return WINED3D_OK;
2717 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2719 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2720 *pMatrix = This->stateBlock->transforms[State];
2721 return WINED3D_OK;
2724 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2725 const WINED3DMATRIX *mat = NULL;
2726 WINED3DMATRIX temp;
2728 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2729 * below means it will be recorded in a state block change, but it
2730 * works regardless where it is recorded.
2731 * If this is found to be wrong, change to StateBlock.
2733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2734 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2736 if (State <= HIGHEST_TRANSFORMSTATE)
2738 mat = &This->updateStateBlock->transforms[State];
2739 } else {
2740 FIXME("Unhandled transform state!!\n");
2743 multiply_matrix(&temp, mat, pMatrix);
2745 /* Apply change via set transform - will reapply to eg. lights this way */
2746 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2749 /*****
2750 * Get / Set Light
2751 *****/
2752 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2753 you can reference any indexes you want as long as that number max are enabled at any
2754 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2755 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2756 but when recording, just build a chain pretty much of commands to be replayed. */
2758 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2759 float rho;
2760 PLIGHTINFOEL *object = NULL;
2761 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2762 struct list *e;
2764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2765 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2767 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2768 * the gl driver.
2770 if(!pLight) {
2771 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2772 return WINED3DERR_INVALIDCALL;
2775 switch(pLight->Type) {
2776 case WINED3DLIGHT_POINT:
2777 case WINED3DLIGHT_SPOT:
2778 case WINED3DLIGHT_PARALLELPOINT:
2779 case WINED3DLIGHT_GLSPOT:
2780 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2781 * most wanted
2783 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2784 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2785 return WINED3DERR_INVALIDCALL;
2787 break;
2789 case WINED3DLIGHT_DIRECTIONAL:
2790 /* Ignores attenuation */
2791 break;
2793 default:
2794 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2795 return WINED3DERR_INVALIDCALL;
2798 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2799 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2800 if(object->OriginalIndex == Index) break;
2801 object = NULL;
2804 if(!object) {
2805 TRACE("Adding new light\n");
2806 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2807 if(!object) {
2808 ERR("Out of memory error when allocating a light\n");
2809 return E_OUTOFMEMORY;
2811 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2812 object->glIndex = -1;
2813 object->OriginalIndex = Index;
2814 object->changed = TRUE;
2817 /* Initialize the object */
2818 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,
2819 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2820 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2821 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2822 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2823 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2824 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2826 /* Save away the information */
2827 object->OriginalParms = *pLight;
2829 switch (pLight->Type) {
2830 case WINED3DLIGHT_POINT:
2831 /* Position */
2832 object->lightPosn[0] = pLight->Position.x;
2833 object->lightPosn[1] = pLight->Position.y;
2834 object->lightPosn[2] = pLight->Position.z;
2835 object->lightPosn[3] = 1.0f;
2836 object->cutoff = 180.0f;
2837 /* FIXME: Range */
2838 break;
2840 case WINED3DLIGHT_DIRECTIONAL:
2841 /* Direction */
2842 object->lightPosn[0] = -pLight->Direction.x;
2843 object->lightPosn[1] = -pLight->Direction.y;
2844 object->lightPosn[2] = -pLight->Direction.z;
2845 object->lightPosn[3] = 0.0;
2846 object->exponent = 0.0f;
2847 object->cutoff = 180.0f;
2848 break;
2850 case WINED3DLIGHT_SPOT:
2851 /* Position */
2852 object->lightPosn[0] = pLight->Position.x;
2853 object->lightPosn[1] = pLight->Position.y;
2854 object->lightPosn[2] = pLight->Position.z;
2855 object->lightPosn[3] = 1.0;
2857 /* Direction */
2858 object->lightDirn[0] = pLight->Direction.x;
2859 object->lightDirn[1] = pLight->Direction.y;
2860 object->lightDirn[2] = pLight->Direction.z;
2861 object->lightDirn[3] = 1.0;
2864 * opengl-ish and d3d-ish spot lights use too different models for the
2865 * light "intensity" as a function of the angle towards the main light direction,
2866 * so we only can approximate very roughly.
2867 * however spot lights are rather rarely used in games (if ever used at all).
2868 * furthermore if still used, probably nobody pays attention to such details.
2870 if (pLight->Falloff == 0) {
2871 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2872 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2873 * will always be 1.0 for both of them, and we don't have to care for the
2874 * rest of the rather complex calculation
2876 object->exponent = 0;
2877 } else {
2878 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2879 if (rho < 0.0001) rho = 0.0001f;
2880 object->exponent = -0.3/log(cos(rho/2));
2882 if (object->exponent > 128.0) {
2883 object->exponent = 128.0;
2885 object->cutoff = pLight->Phi*90/M_PI;
2887 /* FIXME: Range */
2888 break;
2890 default:
2891 FIXME("Unrecognized light type %d\n", pLight->Type);
2894 /* Update the live definitions if the light is currently assigned a glIndex */
2895 if (object->glIndex != -1 && !This->isRecordingState) {
2896 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2898 return WINED3D_OK;
2901 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2902 PLIGHTINFOEL *lightInfo = NULL;
2903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2904 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2905 struct list *e;
2906 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2908 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2909 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2910 if(lightInfo->OriginalIndex == Index) break;
2911 lightInfo = NULL;
2914 if (lightInfo == NULL) {
2915 TRACE("Light information requested but light not defined\n");
2916 return WINED3DERR_INVALIDCALL;
2919 *pLight = lightInfo->OriginalParms;
2920 return WINED3D_OK;
2923 /*****
2924 * Get / Set Light Enable
2925 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2926 *****/
2927 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2928 PLIGHTINFOEL *lightInfo = NULL;
2929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2930 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2931 struct list *e;
2932 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2934 /* Tests show true = 128...not clear why */
2935 Enable = Enable? 128: 0;
2937 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2938 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2939 if(lightInfo->OriginalIndex == Index) break;
2940 lightInfo = NULL;
2942 TRACE("Found light: %p\n", lightInfo);
2944 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2945 if (lightInfo == NULL) {
2947 TRACE("Light enabled requested but light not defined, so defining one!\n");
2948 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2950 /* Search for it again! Should be fairly quick as near head of list */
2951 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2952 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2953 if(lightInfo->OriginalIndex == Index) break;
2954 lightInfo = NULL;
2956 if (lightInfo == NULL) {
2957 FIXME("Adding default lights has failed dismally\n");
2958 return WINED3DERR_INVALIDCALL;
2962 lightInfo->enabledChanged = TRUE;
2963 if(!Enable) {
2964 if(lightInfo->glIndex != -1) {
2965 if(!This->isRecordingState) {
2966 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2969 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2970 lightInfo->glIndex = -1;
2971 } else {
2972 TRACE("Light already disabled, nothing to do\n");
2974 lightInfo->enabled = FALSE;
2975 } else {
2976 lightInfo->enabled = TRUE;
2977 if (lightInfo->glIndex != -1) {
2978 /* nop */
2979 TRACE("Nothing to do as light was enabled\n");
2980 } else {
2981 int i;
2982 /* Find a free gl light */
2983 for(i = 0; i < This->maxConcurrentLights; i++) {
2984 if(This->updateStateBlock->activeLights[i] == NULL) {
2985 This->updateStateBlock->activeLights[i] = lightInfo;
2986 lightInfo->glIndex = i;
2987 break;
2990 if(lightInfo->glIndex == -1) {
2991 /* Our tests show that Windows returns D3D_OK in this situation, even with
2992 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2993 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2994 * as well for those lights.
2996 * TODO: Test how this affects rendering
2998 WARN("Too many concurrently active lights\n");
2999 return WINED3D_OK;
3002 /* i == lightInfo->glIndex */
3003 if(!This->isRecordingState) {
3004 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3009 return WINED3D_OK;
3012 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3014 PLIGHTINFOEL *lightInfo = NULL;
3015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3016 struct list *e;
3017 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3018 TRACE("(%p) : for idx(%d)\n", This, Index);
3020 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3021 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3022 if(lightInfo->OriginalIndex == Index) break;
3023 lightInfo = NULL;
3026 if (lightInfo == NULL) {
3027 TRACE("Light enabled state requested but light not defined\n");
3028 return WINED3DERR_INVALIDCALL;
3030 /* true is 128 according to SetLightEnable */
3031 *pEnable = lightInfo->enabled ? 128 : 0;
3032 return WINED3D_OK;
3035 /*****
3036 * Get / Set Clip Planes
3037 *****/
3038 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3040 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3042 /* Validate Index */
3043 if (Index >= GL_LIMITS(clipplanes)) {
3044 TRACE("Application has requested clipplane this device doesn't support\n");
3045 return WINED3DERR_INVALIDCALL;
3048 This->updateStateBlock->changed.clipplane |= 1 << Index;
3050 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3051 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3052 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3053 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3054 TRACE("Application is setting old values over, nothing to do\n");
3055 return WINED3D_OK;
3058 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3059 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3060 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3061 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3063 /* Handle recording of state blocks */
3064 if (This->isRecordingState) {
3065 TRACE("Recording... not performing anything\n");
3066 return WINED3D_OK;
3069 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3071 return WINED3D_OK;
3074 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3076 TRACE("(%p) : for idx %d\n", This, Index);
3078 /* Validate Index */
3079 if (Index >= GL_LIMITS(clipplanes)) {
3080 TRACE("Application has requested clipplane this device doesn't support\n");
3081 return WINED3DERR_INVALIDCALL;
3084 pPlane[0] = This->stateBlock->clipplane[Index][0];
3085 pPlane[1] = This->stateBlock->clipplane[Index][1];
3086 pPlane[2] = This->stateBlock->clipplane[Index][2];
3087 pPlane[3] = This->stateBlock->clipplane[Index][3];
3088 return WINED3D_OK;
3091 /*****
3092 * Get / Set Clip Plane Status
3093 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3094 *****/
3095 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3097 FIXME("(%p) : stub\n", This);
3098 if (NULL == pClipStatus) {
3099 return WINED3DERR_INVALIDCALL;
3101 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3102 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3103 return WINED3D_OK;
3106 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3108 FIXME("(%p) : stub\n", This);
3109 if (NULL == pClipStatus) {
3110 return WINED3DERR_INVALIDCALL;
3112 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3113 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3114 return WINED3D_OK;
3117 /*****
3118 * Get / Set Material
3119 *****/
3120 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3123 This->updateStateBlock->changed.material = TRUE;
3124 This->updateStateBlock->material = *pMaterial;
3126 /* Handle recording of state blocks */
3127 if (This->isRecordingState) {
3128 TRACE("Recording... not performing anything\n");
3129 return WINED3D_OK;
3132 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3133 return WINED3D_OK;
3136 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3138 *pMaterial = This->updateStateBlock->material;
3139 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3140 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3141 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3142 pMaterial->Ambient.b, pMaterial->Ambient.a);
3143 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3144 pMaterial->Specular.b, pMaterial->Specular.a);
3145 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3146 pMaterial->Emissive.b, pMaterial->Emissive.a);
3147 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3149 return WINED3D_OK;
3152 /*****
3153 * Get / Set Indices
3154 *****/
3155 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3157 IWineD3DIndexBuffer *oldIdxs;
3159 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3160 oldIdxs = This->updateStateBlock->pIndexData;
3162 This->updateStateBlock->changed.indices = TRUE;
3163 This->updateStateBlock->pIndexData = pIndexData;
3165 /* Handle recording of state blocks */
3166 if (This->isRecordingState) {
3167 TRACE("Recording... not performing anything\n");
3168 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3169 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3170 return WINED3D_OK;
3173 if(oldIdxs != pIndexData) {
3174 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3175 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3176 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3178 return WINED3D_OK;
3181 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3184 *ppIndexData = This->stateBlock->pIndexData;
3186 /* up ref count on ppindexdata */
3187 if (*ppIndexData) {
3188 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3189 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3190 }else{
3191 TRACE("(%p) No index data set\n", This);
3193 TRACE("Returning %p\n", *ppIndexData);
3195 return WINED3D_OK;
3198 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3199 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3201 TRACE("(%p)->(%d)\n", This, BaseIndex);
3203 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3204 TRACE("Application is setting the old value over, nothing to do\n");
3205 return WINED3D_OK;
3208 This->updateStateBlock->baseVertexIndex = BaseIndex;
3210 if (This->isRecordingState) {
3211 TRACE("Recording... not performing anything\n");
3212 return WINED3D_OK;
3214 /* The base vertex index affects the stream sources */
3215 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3216 return WINED3D_OK;
3219 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3221 TRACE("(%p) : base_index %p\n", This, base_index);
3223 *base_index = This->stateBlock->baseVertexIndex;
3225 TRACE("Returning %u\n", *base_index);
3227 return WINED3D_OK;
3230 /*****
3231 * Get / Set Viewports
3232 *****/
3233 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3236 TRACE("(%p)\n", This);
3237 This->updateStateBlock->changed.viewport = TRUE;
3238 This->updateStateBlock->viewport = *pViewport;
3240 /* Handle recording of state blocks */
3241 if (This->isRecordingState) {
3242 TRACE("Recording... not performing anything\n");
3243 return WINED3D_OK;
3246 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3247 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3249 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3250 return WINED3D_OK;
3254 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3256 TRACE("(%p)\n", This);
3257 *pViewport = This->stateBlock->viewport;
3258 return WINED3D_OK;
3261 /*****
3262 * Get / Set Render States
3263 * TODO: Verify against dx9 definitions
3264 *****/
3265 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3268 DWORD oldValue = This->stateBlock->renderState[State];
3270 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3272 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3273 This->updateStateBlock->renderState[State] = Value;
3275 /* Handle recording of state blocks */
3276 if (This->isRecordingState) {
3277 TRACE("Recording... not performing anything\n");
3278 return WINED3D_OK;
3281 /* Compared here and not before the assignment to allow proper stateblock recording */
3282 if(Value == oldValue) {
3283 TRACE("Application is setting the old value over, nothing to do\n");
3284 } else {
3285 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3288 return WINED3D_OK;
3291 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3293 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3294 *pValue = This->stateBlock->renderState[State];
3295 return WINED3D_OK;
3298 /*****
3299 * Get / Set Sampler States
3300 * TODO: Verify against dx9 definitions
3301 *****/
3303 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3305 DWORD oldValue;
3307 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3308 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3310 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3311 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3314 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3315 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3316 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3319 * SetSampler is designed to allow for more than the standard up to 8 textures
3320 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3321 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3323 * http://developer.nvidia.com/object/General_FAQ.html#t6
3325 * There are two new settings for GForce
3326 * the sampler one:
3327 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3328 * and the texture one:
3329 * GL_MAX_TEXTURE_COORDS_ARB.
3330 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3331 ******************/
3333 oldValue = This->stateBlock->samplerState[Sampler][Type];
3334 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3335 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3337 /* Handle recording of state blocks */
3338 if (This->isRecordingState) {
3339 TRACE("Recording... not performing anything\n");
3340 return WINED3D_OK;
3343 if(oldValue == Value) {
3344 TRACE("Application is setting the old value over, nothing to do\n");
3345 return WINED3D_OK;
3348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3350 return WINED3D_OK;
3353 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3356 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3357 This, Sampler, debug_d3dsamplerstate(Type), Type);
3359 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3360 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3363 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3364 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3365 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3367 *Value = This->stateBlock->samplerState[Sampler][Type];
3368 TRACE("(%p) : Returning %#x\n", This, *Value);
3370 return WINED3D_OK;
3373 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3376 This->updateStateBlock->changed.scissorRect = TRUE;
3377 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3378 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3379 return WINED3D_OK;
3381 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3383 if(This->isRecordingState) {
3384 TRACE("Recording... not performing anything\n");
3385 return WINED3D_OK;
3388 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3390 return WINED3D_OK;
3393 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3396 *pRect = This->updateStateBlock->scissorRect;
3397 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3398 return WINED3D_OK;
3401 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3403 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3405 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3407 This->updateStateBlock->vertexDecl = pDecl;
3408 This->updateStateBlock->changed.vertexDecl = TRUE;
3410 if (This->isRecordingState) {
3411 TRACE("Recording... not performing anything\n");
3412 return WINED3D_OK;
3413 } else if(pDecl == oldDecl) {
3414 /* Checked after the assignment to allow proper stateblock recording */
3415 TRACE("Application is setting the old declaration over, nothing to do\n");
3416 return WINED3D_OK;
3419 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3420 return WINED3D_OK;
3423 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3426 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3428 *ppDecl = This->stateBlock->vertexDecl;
3429 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3430 return WINED3D_OK;
3433 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3435 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3437 This->updateStateBlock->vertexShader = pShader;
3438 This->updateStateBlock->changed.vertexShader = TRUE;
3440 if (This->isRecordingState) {
3441 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3442 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3443 TRACE("Recording... not performing anything\n");
3444 return WINED3D_OK;
3445 } else if(oldShader == pShader) {
3446 /* Checked here to allow proper stateblock recording */
3447 TRACE("App is setting the old shader over, nothing to do\n");
3448 return WINED3D_OK;
3451 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3452 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3453 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3455 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3457 return WINED3D_OK;
3460 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3461 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3463 if (NULL == ppShader) {
3464 return WINED3DERR_INVALIDCALL;
3466 *ppShader = This->stateBlock->vertexShader;
3467 if( NULL != *ppShader)
3468 IWineD3DVertexShader_AddRef(*ppShader);
3470 TRACE("(%p) : returning %p\n", This, *ppShader);
3471 return WINED3D_OK;
3474 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3475 IWineD3DDevice *iface,
3476 UINT start,
3477 CONST BOOL *srcData,
3478 UINT count) {
3480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3481 int i, cnt = min(count, MAX_CONST_B - start);
3483 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3484 iface, srcData, start, count);
3486 if (srcData == NULL || cnt < 0)
3487 return WINED3DERR_INVALIDCALL;
3489 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3490 for (i = 0; i < cnt; i++)
3491 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3493 for (i = start; i < cnt + start; ++i) {
3494 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3497 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3499 return WINED3D_OK;
3502 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3503 IWineD3DDevice *iface,
3504 UINT start,
3505 BOOL *dstData,
3506 UINT count) {
3508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3509 int cnt = min(count, MAX_CONST_B - start);
3511 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3512 iface, dstData, start, count);
3514 if (dstData == NULL || cnt < 0)
3515 return WINED3DERR_INVALIDCALL;
3517 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3518 return WINED3D_OK;
3521 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3522 IWineD3DDevice *iface,
3523 UINT start,
3524 CONST int *srcData,
3525 UINT count) {
3527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3528 int i, cnt = min(count, MAX_CONST_I - start);
3530 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3531 iface, srcData, start, count);
3533 if (srcData == NULL || cnt < 0)
3534 return WINED3DERR_INVALIDCALL;
3536 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3537 for (i = 0; i < cnt; i++)
3538 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3539 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3541 for (i = start; i < cnt + start; ++i) {
3542 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3545 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3547 return WINED3D_OK;
3550 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3551 IWineD3DDevice *iface,
3552 UINT start,
3553 int *dstData,
3554 UINT count) {
3556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3557 int cnt = min(count, MAX_CONST_I - start);
3559 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3560 iface, dstData, start, count);
3562 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3563 return WINED3DERR_INVALIDCALL;
3565 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3566 return WINED3D_OK;
3569 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3570 IWineD3DDevice *iface,
3571 UINT start,
3572 CONST float *srcData,
3573 UINT count) {
3575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3576 UINT i;
3578 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3579 iface, srcData, start, count);
3581 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3582 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3583 return WINED3DERR_INVALIDCALL;
3585 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3586 if(TRACE_ON(d3d)) {
3587 for (i = 0; i < count; i++)
3588 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3589 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3592 if (!This->isRecordingState)
3594 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3595 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3598 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3599 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3601 return WINED3D_OK;
3604 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3605 IWineD3DDevice *iface,
3606 UINT start,
3607 float *dstData,
3608 UINT count) {
3610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3611 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3613 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3614 iface, dstData, start, count);
3616 if (dstData == NULL || cnt < 0)
3617 return WINED3DERR_INVALIDCALL;
3619 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3620 return WINED3D_OK;
3623 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3624 DWORD i;
3625 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3627 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3631 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3632 int i = This->rev_tex_unit_map[unit];
3633 int j = This->texUnitMap[stage];
3635 This->texUnitMap[stage] = unit;
3636 if (i != -1 && i != stage) {
3637 This->texUnitMap[i] = -1;
3640 This->rev_tex_unit_map[unit] = stage;
3641 if (j != -1 && j != unit) {
3642 This->rev_tex_unit_map[j] = -1;
3646 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3647 int i;
3649 This->fixed_function_usage_map = 0;
3650 for (i = 0; i < MAX_TEXTURES; ++i) {
3651 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3652 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3653 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3654 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3655 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3656 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3657 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3658 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3660 if (color_op == WINED3DTOP_DISABLE) {
3661 /* Not used, and disable higher stages */
3662 break;
3665 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3666 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3667 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3668 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3669 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3670 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3671 This->fixed_function_usage_map |= (1 << i);
3674 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3675 This->fixed_function_usage_map |= (1 << (i + 1));
3680 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3681 int i, tex;
3682 WORD ffu_map;
3684 device_update_fixed_function_usage_map(This);
3685 ffu_map = This->fixed_function_usage_map;
3687 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3688 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3689 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3691 if (!(ffu_map & 1)) continue;
3693 if (This->texUnitMap[i] != i) {
3694 device_map_stage(This, i, i);
3695 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3696 markTextureStagesDirty(This, i);
3699 return;
3702 /* Now work out the mapping */
3703 tex = 0;
3704 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3706 if (!(ffu_map & 1)) continue;
3708 if (This->texUnitMap[i] != tex) {
3709 device_map_stage(This, i, tex);
3710 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3711 markTextureStagesDirty(This, i);
3714 ++tex;
3718 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3719 const DWORD *sampler_tokens =
3720 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3721 int i;
3723 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3724 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3725 device_map_stage(This, i, i);
3726 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3727 if (i < MAX_TEXTURES) {
3728 markTextureStagesDirty(This, i);
3734 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3735 const DWORD *vshader_sampler_tokens, int unit)
3737 int current_mapping = This->rev_tex_unit_map[unit];
3739 if (current_mapping == -1) {
3740 /* Not currently used */
3741 return TRUE;
3744 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3745 /* Used by a fragment sampler */
3747 if (!pshader_sampler_tokens) {
3748 /* No pixel shader, check fixed function */
3749 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3752 /* Pixel shader, check the shader's sampler map */
3753 return !pshader_sampler_tokens[current_mapping];
3756 /* Used by a vertex sampler */
3757 return !vshader_sampler_tokens[current_mapping];
3760 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3761 const DWORD *vshader_sampler_tokens =
3762 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3763 const DWORD *pshader_sampler_tokens = NULL;
3764 int start = GL_LIMITS(combined_samplers) - 1;
3765 int i;
3767 if (ps) {
3768 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3770 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3771 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3772 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3775 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3776 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3777 if (vshader_sampler_tokens[i]) {
3778 if (This->texUnitMap[vsampler_idx] != -1) {
3779 /* Already mapped somewhere */
3780 continue;
3783 while (start >= 0) {
3784 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3785 device_map_stage(This, vsampler_idx, start);
3786 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3788 --start;
3789 break;
3792 --start;
3798 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3799 BOOL vs = use_vs(This->stateBlock);
3800 BOOL ps = use_ps(This->stateBlock);
3802 * Rules are:
3803 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3804 * that would be really messy and require shader recompilation
3805 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3806 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3808 if (ps) {
3809 device_map_psamplers(This);
3810 } else {
3811 device_map_fixed_function_samplers(This);
3814 if (vs) {
3815 device_map_vsamplers(This, ps);
3819 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3821 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3822 This->updateStateBlock->pixelShader = pShader;
3823 This->updateStateBlock->changed.pixelShader = TRUE;
3825 /* Handle recording of state blocks */
3826 if (This->isRecordingState) {
3827 TRACE("Recording... not performing anything\n");
3830 if (This->isRecordingState) {
3831 TRACE("Recording... not performing anything\n");
3832 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3833 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3834 return WINED3D_OK;
3837 if(pShader == oldShader) {
3838 TRACE("App is setting the old pixel shader over, nothing to do\n");
3839 return WINED3D_OK;
3842 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3843 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3845 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3846 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3848 return WINED3D_OK;
3851 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3854 if (NULL == ppShader) {
3855 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3856 return WINED3DERR_INVALIDCALL;
3859 *ppShader = This->stateBlock->pixelShader;
3860 if (NULL != *ppShader) {
3861 IWineD3DPixelShader_AddRef(*ppShader);
3863 TRACE("(%p) : returning %p\n", This, *ppShader);
3864 return WINED3D_OK;
3867 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3868 IWineD3DDevice *iface,
3869 UINT start,
3870 CONST BOOL *srcData,
3871 UINT count) {
3873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3874 int i, cnt = min(count, MAX_CONST_B - start);
3876 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3877 iface, srcData, start, count);
3879 if (srcData == NULL || cnt < 0)
3880 return WINED3DERR_INVALIDCALL;
3882 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3883 for (i = 0; i < cnt; i++)
3884 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3886 for (i = start; i < cnt + start; ++i) {
3887 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3890 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3892 return WINED3D_OK;
3895 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3896 IWineD3DDevice *iface,
3897 UINT start,
3898 BOOL *dstData,
3899 UINT count) {
3901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3902 int cnt = min(count, MAX_CONST_B - start);
3904 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3905 iface, dstData, start, count);
3907 if (dstData == NULL || cnt < 0)
3908 return WINED3DERR_INVALIDCALL;
3910 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3911 return WINED3D_OK;
3914 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3915 IWineD3DDevice *iface,
3916 UINT start,
3917 CONST int *srcData,
3918 UINT count) {
3920 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3921 int i, cnt = min(count, MAX_CONST_I - start);
3923 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3924 iface, srcData, start, count);
3926 if (srcData == NULL || cnt < 0)
3927 return WINED3DERR_INVALIDCALL;
3929 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3930 for (i = 0; i < cnt; i++)
3931 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3932 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3934 for (i = start; i < cnt + start; ++i) {
3935 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3938 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3940 return WINED3D_OK;
3943 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3944 IWineD3DDevice *iface,
3945 UINT start,
3946 int *dstData,
3947 UINT count) {
3949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3950 int cnt = min(count, MAX_CONST_I - start);
3952 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3953 iface, dstData, start, count);
3955 if (dstData == NULL || cnt < 0)
3956 return WINED3DERR_INVALIDCALL;
3958 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3959 return WINED3D_OK;
3962 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3963 IWineD3DDevice *iface,
3964 UINT start,
3965 CONST float *srcData,
3966 UINT count) {
3968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3969 UINT i;
3971 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3972 iface, srcData, start, count);
3974 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3975 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3976 return WINED3DERR_INVALIDCALL;
3978 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3979 if(TRACE_ON(d3d)) {
3980 for (i = 0; i < count; i++)
3981 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3982 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3985 if (!This->isRecordingState)
3987 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3988 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3991 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3992 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3994 return WINED3D_OK;
3997 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3998 IWineD3DDevice *iface,
3999 UINT start,
4000 float *dstData,
4001 UINT count) {
4003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4004 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4006 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4007 iface, dstData, start, count);
4009 if (dstData == NULL || cnt < 0)
4010 return WINED3DERR_INVALIDCALL;
4012 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4013 return WINED3D_OK;
4016 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4017 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4018 const WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags)
4020 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4021 unsigned int i;
4022 DWORD DestFVF = dest->fvf;
4023 WINED3DVIEWPORT vp;
4024 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4025 BOOL doClip;
4026 DWORD numTextures;
4028 if (lpStrideData->u.s.normal.lpData) {
4029 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4032 if (lpStrideData->u.s.position.lpData == NULL) {
4033 ERR("Source has no position mask\n");
4034 return WINED3DERR_INVALIDCALL;
4037 /* We might access VBOs from this code, so hold the lock */
4038 ENTER_GL();
4040 if (dest->resource.allocatedMemory == NULL) {
4041 /* This may happen if we do direct locking into a vbo. Unlikely,
4042 * but theoretically possible(ddraw processvertices test)
4044 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4045 if(!dest->resource.allocatedMemory) {
4046 LEAVE_GL();
4047 ERR("Out of memory\n");
4048 return E_OUTOFMEMORY;
4050 if(dest->vbo) {
4051 const void *src;
4052 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4053 checkGLcall("glBindBufferARB");
4054 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4055 if(src) {
4056 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4058 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4059 checkGLcall("glUnmapBufferARB");
4063 /* Get a pointer into the destination vbo(create one if none exists) and
4064 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4066 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4067 dest->Flags |= VBFLAG_CREATEVBO;
4068 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4071 if(dest->vbo) {
4072 unsigned char extrabytes = 0;
4073 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4074 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4075 * this may write 4 extra bytes beyond the area that should be written
4077 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4078 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4079 if(!dest_conv_addr) {
4080 ERR("Out of memory\n");
4081 /* Continue without storing converted vertices */
4083 dest_conv = dest_conv_addr;
4086 /* Should I clip?
4087 * a) WINED3DRS_CLIPPING is enabled
4088 * b) WINED3DVOP_CLIP is passed
4090 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4091 static BOOL warned = FALSE;
4093 * The clipping code is not quite correct. Some things need
4094 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4095 * so disable clipping for now.
4096 * (The graphics in Half-Life are broken, and my processvertices
4097 * test crashes with IDirect3DDevice3)
4098 doClip = TRUE;
4100 doClip = FALSE;
4101 if(!warned) {
4102 warned = TRUE;
4103 FIXME("Clipping is broken and disabled for now\n");
4105 } else doClip = FALSE;
4106 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4108 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4109 WINED3DTS_VIEW,
4110 &view_mat);
4111 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4112 WINED3DTS_PROJECTION,
4113 &proj_mat);
4114 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4115 WINED3DTS_WORLDMATRIX(0),
4116 &world_mat);
4118 TRACE("View mat:\n");
4119 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);
4120 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);
4121 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);
4122 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);
4124 TRACE("Proj mat:\n");
4125 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);
4126 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);
4127 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);
4128 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);
4130 TRACE("World mat:\n");
4131 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);
4132 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);
4133 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);
4134 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);
4136 /* Get the viewport */
4137 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4138 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4139 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4141 multiply_matrix(&mat,&view_mat,&world_mat);
4142 multiply_matrix(&mat,&proj_mat,&mat);
4144 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4146 for (i = 0; i < dwCount; i+= 1) {
4147 unsigned int tex_index;
4149 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4150 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4151 /* The position first */
4152 const float *p =
4153 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4154 float x, y, z, rhw;
4155 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4157 /* Multiplication with world, view and projection matrix */
4158 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);
4159 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);
4160 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);
4161 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);
4163 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4165 /* WARNING: The following things are taken from d3d7 and were not yet checked
4166 * against d3d8 or d3d9!
4169 /* Clipping conditions: From msdn
4171 * A vertex is clipped if it does not match the following requirements
4172 * -rhw < x <= rhw
4173 * -rhw < y <= rhw
4174 * 0 < z <= rhw
4175 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4177 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4178 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4182 if( !doClip ||
4183 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4184 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4185 ( rhw > eps ) ) ) {
4187 /* "Normal" viewport transformation (not clipped)
4188 * 1) The values are divided by rhw
4189 * 2) The y axis is negative, so multiply it with -1
4190 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4191 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4192 * 4) Multiply x with Width/2 and add Width/2
4193 * 5) The same for the height
4194 * 6) Add the viewpoint X and Y to the 2D coordinates and
4195 * The minimum Z value to z
4196 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4198 * Well, basically it's simply a linear transformation into viewport
4199 * coordinates
4202 x /= rhw;
4203 y /= rhw;
4204 z /= rhw;
4206 y *= -1;
4208 x *= vp.Width / 2;
4209 y *= vp.Height / 2;
4210 z *= vp.MaxZ - vp.MinZ;
4212 x += vp.Width / 2 + vp.X;
4213 y += vp.Height / 2 + vp.Y;
4214 z += vp.MinZ;
4216 rhw = 1 / rhw;
4217 } else {
4218 /* That vertex got clipped
4219 * Contrary to OpenGL it is not dropped completely, it just
4220 * undergoes a different calculation.
4222 TRACE("Vertex got clipped\n");
4223 x += rhw;
4224 y += rhw;
4226 x /= 2;
4227 y /= 2;
4229 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4230 * outside of the main vertex buffer memory. That needs some more
4231 * investigation...
4235 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4238 ( (float *) dest_ptr)[0] = x;
4239 ( (float *) dest_ptr)[1] = y;
4240 ( (float *) dest_ptr)[2] = z;
4241 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4243 dest_ptr += 3 * sizeof(float);
4245 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4246 dest_ptr += sizeof(float);
4249 if(dest_conv) {
4250 float w = 1 / rhw;
4251 ( (float *) dest_conv)[0] = x * w;
4252 ( (float *) dest_conv)[1] = y * w;
4253 ( (float *) dest_conv)[2] = z * w;
4254 ( (float *) dest_conv)[3] = w;
4256 dest_conv += 3 * sizeof(float);
4258 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4259 dest_conv += sizeof(float);
4263 if (DestFVF & WINED3DFVF_PSIZE) {
4264 dest_ptr += sizeof(DWORD);
4265 if(dest_conv) dest_conv += sizeof(DWORD);
4267 if (DestFVF & WINED3DFVF_NORMAL) {
4268 const float *normal =
4269 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4270 /* AFAIK this should go into the lighting information */
4271 FIXME("Didn't expect the destination to have a normal\n");
4272 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4273 if(dest_conv) {
4274 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4278 if (DestFVF & WINED3DFVF_DIFFUSE) {
4279 const DWORD *color_d =
4280 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4281 if(!color_d) {
4282 static BOOL warned = FALSE;
4284 if(!warned) {
4285 ERR("No diffuse color in source, but destination has one\n");
4286 warned = TRUE;
4289 *( (DWORD *) dest_ptr) = 0xffffffff;
4290 dest_ptr += sizeof(DWORD);
4292 if(dest_conv) {
4293 *( (DWORD *) dest_conv) = 0xffffffff;
4294 dest_conv += sizeof(DWORD);
4297 else {
4298 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4299 if(dest_conv) {
4300 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4301 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4302 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4303 dest_conv += sizeof(DWORD);
4308 if (DestFVF & WINED3DFVF_SPECULAR) {
4309 /* What's the color value in the feedback buffer? */
4310 const DWORD *color_s =
4311 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4312 if(!color_s) {
4313 static BOOL warned = FALSE;
4315 if(!warned) {
4316 ERR("No specular color in source, but destination has one\n");
4317 warned = TRUE;
4320 *( (DWORD *) dest_ptr) = 0xFF000000;
4321 dest_ptr += sizeof(DWORD);
4323 if(dest_conv) {
4324 *( (DWORD *) dest_conv) = 0xFF000000;
4325 dest_conv += sizeof(DWORD);
4328 else {
4329 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4330 if(dest_conv) {
4331 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4332 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4333 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4334 dest_conv += sizeof(DWORD);
4339 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4340 const float *tex_coord =
4341 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4342 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4343 if(!tex_coord) {
4344 ERR("No source texture, but destination requests one\n");
4345 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4346 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4348 else {
4349 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4350 if(dest_conv) {
4351 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4357 if(dest_conv) {
4358 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4359 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4360 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4361 dwCount * get_flexible_vertex_size(DestFVF),
4362 dest_conv_addr));
4363 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4364 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4367 LEAVE_GL();
4369 return WINED3D_OK;
4371 #undef copy_and_next
4373 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4375 WineDirect3DVertexStridedData strided;
4376 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4377 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4379 if(pVertexDecl) {
4380 ERR("Output vertex declaration not implemented yet\n");
4383 /* Need any context to write to the vbo. */
4384 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4386 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4387 * control the streamIsUP flag, thus restore it afterwards.
4389 This->stateBlock->streamIsUP = FALSE;
4390 memset(&strided, 0, sizeof(strided));
4391 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4392 This->stateBlock->streamIsUP = streamWasUP;
4394 if(vbo || SrcStartIndex) {
4395 unsigned int i;
4396 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4397 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4399 * Also get the start index in, but only loop over all elements if there's something to add at all.
4401 #define FIXSRC(type) \
4402 if(strided.u.s.type.VBO) { \
4403 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4404 strided.u.s.type.VBO = 0; \
4405 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4406 ENTER_GL(); \
4407 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4408 vb->vbo = 0; \
4409 LEAVE_GL(); \
4411 if(strided.u.s.type.lpData) { \
4412 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4414 FIXSRC(position);
4415 FIXSRC(blendWeights);
4416 FIXSRC(blendMatrixIndices);
4417 FIXSRC(normal);
4418 FIXSRC(pSize);
4419 FIXSRC(diffuse);
4420 FIXSRC(specular);
4421 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4422 FIXSRC(texCoords[i]);
4424 FIXSRC(position2);
4425 FIXSRC(normal2);
4426 FIXSRC(tangent);
4427 FIXSRC(binormal);
4428 FIXSRC(tessFactor);
4429 FIXSRC(fog);
4430 FIXSRC(depth);
4431 FIXSRC(sample);
4432 #undef FIXSRC
4435 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4438 /*****
4439 * Get / Set Texture Stage States
4440 * TODO: Verify against dx9 definitions
4441 *****/
4442 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4444 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4446 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4448 if (Stage >= MAX_TEXTURES) {
4449 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4450 return WINED3D_OK;
4453 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4454 This->updateStateBlock->textureState[Stage][Type] = Value;
4456 if (This->isRecordingState) {
4457 TRACE("Recording... not performing anything\n");
4458 return WINED3D_OK;
4461 /* Checked after the assignments to allow proper stateblock recording */
4462 if(oldValue == Value) {
4463 TRACE("App is setting the old value over, nothing to do\n");
4464 return WINED3D_OK;
4467 if(Stage > This->stateBlock->lowest_disabled_stage &&
4468 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4469 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4470 * Changes in other states are important on disabled stages too
4472 return WINED3D_OK;
4475 if(Type == WINED3DTSS_COLOROP) {
4476 int i;
4478 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4479 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4480 * they have to be disabled
4482 * The current stage is dirtified below.
4484 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4485 TRACE("Additionally dirtifying stage %d\n", i);
4486 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4488 This->stateBlock->lowest_disabled_stage = Stage;
4489 TRACE("New lowest disabled: %d\n", Stage);
4490 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4491 /* Previously disabled stage enabled. Stages above it may need enabling
4492 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4493 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4495 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4498 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4499 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4500 break;
4502 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4503 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4505 This->stateBlock->lowest_disabled_stage = i;
4506 TRACE("New lowest disabled: %d\n", i);
4510 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4512 return WINED3D_OK;
4515 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4517 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4518 *pValue = This->updateStateBlock->textureState[Stage][Type];
4519 return WINED3D_OK;
4522 /*****
4523 * Get / Set Texture
4524 *****/
4525 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4527 IWineD3DBaseTexture *oldTexture;
4529 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4531 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4532 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4535 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4536 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4537 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4540 oldTexture = This->updateStateBlock->textures[Stage];
4542 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4543 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4545 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4546 return WINED3DERR_INVALIDCALL;
4549 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4550 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4552 This->updateStateBlock->changed.textures |= 1 << Stage;
4553 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4554 This->updateStateBlock->textures[Stage] = pTexture;
4556 /* Handle recording of state blocks */
4557 if (This->isRecordingState) {
4558 TRACE("Recording... not performing anything\n");
4559 return WINED3D_OK;
4562 if(oldTexture == pTexture) {
4563 TRACE("App is setting the same texture again, nothing to do\n");
4564 return WINED3D_OK;
4567 /** NOTE: MSDN says that setTexture increases the reference count,
4568 * and that the application must set the texture back to null (or have a leaky application),
4569 * This means we should pass the refcount up to the parent
4570 *******************************/
4571 if (NULL != This->updateStateBlock->textures[Stage]) {
4572 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4573 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4575 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4576 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4577 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4578 * so the COLOROP and ALPHAOP have to be dirtified.
4580 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4581 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4583 if(bindCount == 1) {
4584 new->baseTexture.sampler = Stage;
4586 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4590 if (NULL != oldTexture) {
4591 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4592 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4594 IWineD3DBaseTexture_Release(oldTexture);
4595 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4596 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4597 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4600 if(bindCount && old->baseTexture.sampler == Stage) {
4601 int i;
4602 /* Have to do a search for the other sampler(s) where the texture is bound to
4603 * Shouldn't happen as long as apps bind a texture only to one stage
4605 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4606 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4607 if(This->updateStateBlock->textures[i] == oldTexture) {
4608 old->baseTexture.sampler = i;
4609 break;
4615 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4617 return WINED3D_OK;
4620 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4623 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4625 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4626 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4629 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4630 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4631 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4634 *ppTexture=This->stateBlock->textures[Stage];
4635 if (*ppTexture)
4636 IWineD3DBaseTexture_AddRef(*ppTexture);
4638 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4640 return WINED3D_OK;
4643 /*****
4644 * Get Back Buffer
4645 *****/
4646 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4647 IWineD3DSurface **ppBackBuffer) {
4648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4649 IWineD3DSwapChain *swapChain;
4650 HRESULT hr;
4652 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4654 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4655 if (hr == WINED3D_OK) {
4656 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4657 IWineD3DSwapChain_Release(swapChain);
4658 } else {
4659 *ppBackBuffer = NULL;
4661 return hr;
4664 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4666 WARN("(%p) : stub, calling idirect3d for now\n", This);
4667 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4670 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4672 IWineD3DSwapChain *swapChain;
4673 HRESULT hr;
4675 if(iSwapChain > 0) {
4676 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4677 if (hr == WINED3D_OK) {
4678 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4679 IWineD3DSwapChain_Release(swapChain);
4680 } else {
4681 FIXME("(%p) Error getting display mode\n", This);
4683 } else {
4684 /* Don't read the real display mode,
4685 but return the stored mode instead. X11 can't change the color
4686 depth, and some apps are pretty angry if they SetDisplayMode from
4687 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4689 Also don't relay to the swapchain because with ddraw it's possible
4690 that there isn't a swapchain at all */
4691 pMode->Width = This->ddraw_width;
4692 pMode->Height = This->ddraw_height;
4693 pMode->Format = This->ddraw_format;
4694 pMode->RefreshRate = 0;
4695 hr = WINED3D_OK;
4698 return hr;
4701 /*****
4702 * Stateblock related functions
4703 *****/
4705 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4707 IWineD3DStateBlockImpl *object;
4708 HRESULT temp_result;
4709 int i;
4711 TRACE("(%p)\n", This);
4713 if (This->isRecordingState) {
4714 return WINED3DERR_INVALIDCALL;
4717 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4718 if (NULL == object ) {
4719 FIXME("(%p)Error allocating memory for stateblock\n", This);
4720 return E_OUTOFMEMORY;
4722 TRACE("(%p) created object %p\n", This, object);
4723 object->wineD3DDevice= This;
4724 /** FIXME: object->parent = parent; **/
4725 object->parent = NULL;
4726 object->blockType = WINED3DSBT_RECORDED;
4727 object->ref = 1;
4728 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4730 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4731 list_init(&object->lightMap[i]);
4734 temp_result = allocate_shader_constants(object);
4735 if (WINED3D_OK != temp_result)
4736 return temp_result;
4738 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4739 This->updateStateBlock = object;
4740 This->isRecordingState = TRUE;
4742 TRACE("(%p) recording stateblock %p\n",This , object);
4743 return WINED3D_OK;
4746 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4748 unsigned int i, j;
4749 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4751 if (!This->isRecordingState) {
4752 WARN("(%p) not recording! returning error\n", This);
4753 *ppStateBlock = NULL;
4754 return WINED3DERR_INVALIDCALL;
4757 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
4759 DWORD map = object->changed.renderState[i];
4760 for (j = 0; map; map >>= 1, ++j)
4762 if (!(map & 1)) continue;
4764 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
4768 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
4770 DWORD map = object->changed.transform[i];
4771 for (j = 0; map; map >>= 1, ++j)
4773 if (!(map & 1)) continue;
4775 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
4778 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4779 if(object->changed.vertexShaderConstantsF[i]) {
4780 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4781 object->num_contained_vs_consts_f++;
4784 for(i = 0; i < MAX_CONST_I; i++) {
4785 if (object->changed.vertexShaderConstantsI & (1 << i))
4787 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4788 object->num_contained_vs_consts_i++;
4791 for(i = 0; i < MAX_CONST_B; i++) {
4792 if (object->changed.vertexShaderConstantsB & (1 << i))
4794 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4795 object->num_contained_vs_consts_b++;
4798 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4800 if (object->changed.pixelShaderConstantsF[i])
4802 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4803 ++object->num_contained_ps_consts_f;
4806 for(i = 0; i < MAX_CONST_I; i++) {
4807 if (object->changed.pixelShaderConstantsI & (1 << i))
4809 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4810 object->num_contained_ps_consts_i++;
4813 for(i = 0; i < MAX_CONST_B; i++) {
4814 if (object->changed.pixelShaderConstantsB & (1 << i))
4816 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4817 object->num_contained_ps_consts_b++;
4820 for(i = 0; i < MAX_TEXTURES; i++) {
4821 DWORD map = object->changed.textureState[i];
4823 for(j = 0; map; map >>= 1, ++j)
4825 if (!(map & 1)) continue;
4827 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4828 object->contained_tss_states[object->num_contained_tss_states].state = j;
4829 ++object->num_contained_tss_states;
4832 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4833 DWORD map = object->changed.samplerState[i];
4835 for (j = 0; map; map >>= 1, ++j)
4837 if (!(map & 1)) continue;
4839 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4840 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4841 ++object->num_contained_sampler_states;
4845 *ppStateBlock = (IWineD3DStateBlock*) object;
4846 This->isRecordingState = FALSE;
4847 This->updateStateBlock = This->stateBlock;
4848 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4849 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4850 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4851 return WINED3D_OK;
4854 /*****
4855 * Scene related functions
4856 *****/
4857 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4858 /* At the moment we have no need for any functionality at the beginning
4859 of a scene */
4860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4861 TRACE("(%p)\n", This);
4863 if(This->inScene) {
4864 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4865 return WINED3DERR_INVALIDCALL;
4867 This->inScene = TRUE;
4868 return WINED3D_OK;
4871 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4873 TRACE("(%p)\n", This);
4875 if(!This->inScene) {
4876 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4877 return WINED3DERR_INVALIDCALL;
4880 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4881 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4882 glFlush();
4883 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4884 * fails
4887 This->inScene = FALSE;
4888 return WINED3D_OK;
4891 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4892 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4893 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4895 IWineD3DSwapChain *swapChain = NULL;
4896 int i;
4897 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4899 TRACE("(%p) Presenting the frame\n", This);
4901 for(i = 0 ; i < swapchains ; i ++) {
4903 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4904 TRACE("presentinng chain %d, %p\n", i, swapChain);
4905 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4906 IWineD3DSwapChain_Release(swapChain);
4909 return WINED3D_OK;
4912 /* Not called from the VTable (internal subroutine) */
4913 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4914 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4915 float Z, DWORD Stencil) {
4916 GLbitfield glMask = 0;
4917 unsigned int i;
4918 WINED3DRECT curRect;
4919 RECT vp_rect;
4920 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4921 UINT drawable_width, drawable_height;
4922 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4923 IWineD3DSwapChainImpl *swapchain = NULL;
4925 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4926 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4927 * for the cleared parts, and the untouched parts.
4929 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4930 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4931 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4932 * checking all this if the dest surface is in the drawable anyway.
4934 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4935 while(1) {
4936 if(vp->X != 0 || vp->Y != 0 ||
4937 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4938 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4939 break;
4941 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4942 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4943 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4944 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4945 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4946 break;
4948 if(Count > 0 && pRects && (
4949 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4950 pRects[0].x2 < target->currentDesc.Width ||
4951 pRects[0].y2 < target->currentDesc.Height)) {
4952 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4953 break;
4955 break;
4959 target->get_drawable_size(target, &drawable_width, &drawable_height);
4961 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4962 ENTER_GL();
4964 /* Only set the values up once, as they are not changing */
4965 if (Flags & WINED3DCLEAR_STENCIL) {
4966 glClearStencil(Stencil);
4967 checkGLcall("glClearStencil");
4968 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4969 glStencilMask(0xFFFFFFFF);
4972 if (Flags & WINED3DCLEAR_ZBUFFER) {
4973 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4974 glDepthMask(GL_TRUE);
4975 glClearDepth(Z);
4976 checkGLcall("glClearDepth");
4977 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4978 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4980 if (vp->X != 0 || vp->Y != 0 ||
4981 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4982 surface_load_ds_location(This->stencilBufferTarget, location);
4984 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4985 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4986 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4987 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4988 surface_load_ds_location(This->stencilBufferTarget, location);
4990 else if (Count > 0 && pRects && (
4991 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4992 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4993 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4994 surface_load_ds_location(This->stencilBufferTarget, location);
4998 if (Flags & WINED3DCLEAR_TARGET) {
4999 TRACE("Clearing screen with glClear to color %x\n", Color);
5000 glClearColor(D3DCOLOR_R(Color),
5001 D3DCOLOR_G(Color),
5002 D3DCOLOR_B(Color),
5003 D3DCOLOR_A(Color));
5004 checkGLcall("glClearColor");
5006 /* Clear ALL colors! */
5007 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5008 glMask = glMask | GL_COLOR_BUFFER_BIT;
5011 vp_rect.left = vp->X;
5012 vp_rect.top = vp->Y;
5013 vp_rect.right = vp->X + vp->Width;
5014 vp_rect.bottom = vp->Y + vp->Height;
5015 if (!(Count > 0 && pRects)) {
5016 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5017 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5019 if(This->render_offscreen) {
5020 glScissor(vp_rect.left, vp_rect.top,
5021 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5022 } else {
5023 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5024 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5026 checkGLcall("glScissor");
5027 glClear(glMask);
5028 checkGLcall("glClear");
5029 } else {
5030 /* Now process each rect in turn */
5031 for (i = 0; i < Count; i++) {
5032 /* Note gl uses lower left, width/height */
5033 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5034 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5035 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5037 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5038 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5039 curRect.x1, (target->currentDesc.Height - curRect.y2),
5040 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5042 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5043 * The rectangle is not cleared, no error is returned, but further rectanlges are
5044 * still cleared if they are valid
5046 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5047 TRACE("Rectangle with negative dimensions, ignoring\n");
5048 continue;
5051 if(This->render_offscreen) {
5052 glScissor(curRect.x1, curRect.y1,
5053 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5054 } else {
5055 glScissor(curRect.x1, drawable_height - curRect.y2,
5056 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5058 checkGLcall("glScissor");
5060 glClear(glMask);
5061 checkGLcall("glClear");
5065 /* Restore the old values (why..?) */
5066 if (Flags & WINED3DCLEAR_STENCIL) {
5067 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5069 if (Flags & WINED3DCLEAR_TARGET) {
5070 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5071 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5072 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5073 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5074 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5076 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5077 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5079 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5081 if (Flags & WINED3DCLEAR_ZBUFFER) {
5082 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5083 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5084 surface_modify_ds_location(This->stencilBufferTarget, location);
5087 LEAVE_GL();
5089 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5090 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5091 glFlush();
5093 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5096 return WINED3D_OK;
5099 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5100 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5102 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5104 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5105 Count, pRects, Flags, Color, Z, Stencil);
5107 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5108 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5109 /* TODO: What about depth stencil buffers without stencil bits? */
5110 return WINED3DERR_INVALIDCALL;
5113 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5116 /*****
5117 * Drawing functions
5118 *****/
5119 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5120 UINT PrimitiveCount) {
5122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5124 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5125 debug_d3dprimitivetype(PrimitiveType),
5126 StartVertex, PrimitiveCount);
5128 if(!This->stateBlock->vertexDecl) {
5129 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5130 return WINED3DERR_INVALIDCALL;
5133 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5134 if(This->stateBlock->streamIsUP) {
5135 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5136 This->stateBlock->streamIsUP = FALSE;
5139 if(This->stateBlock->loadBaseVertexIndex != 0) {
5140 This->stateBlock->loadBaseVertexIndex = 0;
5141 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5143 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5144 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0/* NumVertices */, StartVertex /* start_idx */,
5145 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5146 return WINED3D_OK;
5149 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5150 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5151 WINED3DPRIMITIVETYPE PrimitiveType,
5152 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5155 UINT idxStride = 2;
5156 IWineD3DIndexBuffer *pIB;
5157 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5158 GLuint vbo;
5160 pIB = This->stateBlock->pIndexData;
5161 if (!pIB) {
5162 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5163 * without an index buffer set. (The first time at least...)
5164 * D3D8 simply dies, but I doubt it can do much harm to return
5165 * D3DERR_INVALIDCALL there as well. */
5166 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5167 return WINED3DERR_INVALIDCALL;
5170 if(!This->stateBlock->vertexDecl) {
5171 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5172 return WINED3DERR_INVALIDCALL;
5175 if(This->stateBlock->streamIsUP) {
5176 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5177 This->stateBlock->streamIsUP = FALSE;
5179 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5181 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5182 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5183 minIndex, NumVertices, startIndex, primCount);
5185 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5186 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5187 idxStride = 2;
5188 } else {
5189 idxStride = 4;
5192 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5193 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5194 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5197 drawPrimitive(iface, PrimitiveType, primCount, NumVertices, startIndex,
5198 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5200 return WINED3D_OK;
5203 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5204 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5205 UINT VertexStreamZeroStride) {
5206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5207 IWineD3DVertexBuffer *vb;
5209 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5210 debug_d3dprimitivetype(PrimitiveType),
5211 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5213 if(!This->stateBlock->vertexDecl) {
5214 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5215 return WINED3DERR_INVALIDCALL;
5218 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5219 vb = This->stateBlock->streamSource[0];
5220 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5221 if(vb) IWineD3DVertexBuffer_Release(vb);
5222 This->stateBlock->streamOffset[0] = 0;
5223 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5224 This->stateBlock->streamIsUP = TRUE;
5225 This->stateBlock->loadBaseVertexIndex = 0;
5227 /* TODO: Only mark dirty if drawing from a different UP address */
5228 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5230 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* NumVertices */,
5231 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5233 /* MSDN specifies stream zero settings must be set to NULL */
5234 This->stateBlock->streamStride[0] = 0;
5235 This->stateBlock->streamSource[0] = NULL;
5237 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5238 * the new stream sources or use UP drawing again
5240 return WINED3D_OK;
5243 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5244 UINT MinVertexIndex, UINT NumVertices,
5245 UINT PrimitiveCount, CONST void* pIndexData,
5246 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5247 UINT VertexStreamZeroStride) {
5248 int idxStride;
5249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5250 IWineD3DVertexBuffer *vb;
5251 IWineD3DIndexBuffer *ib;
5253 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5254 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5255 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5256 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5258 if(!This->stateBlock->vertexDecl) {
5259 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5260 return WINED3DERR_INVALIDCALL;
5263 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5264 idxStride = 2;
5265 } else {
5266 idxStride = 4;
5269 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5270 vb = This->stateBlock->streamSource[0];
5271 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5272 if(vb) IWineD3DVertexBuffer_Release(vb);
5273 This->stateBlock->streamIsUP = TRUE;
5274 This->stateBlock->streamOffset[0] = 0;
5275 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5277 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5278 This->stateBlock->baseVertexIndex = 0;
5279 This->stateBlock->loadBaseVertexIndex = 0;
5280 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5281 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5282 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5284 drawPrimitive(iface, PrimitiveType, PrimitiveCount, NumVertices, 0 /* start_idx */, idxStride, pIndexData, MinVertexIndex);
5286 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5287 This->stateBlock->streamSource[0] = NULL;
5288 This->stateBlock->streamStride[0] = 0;
5289 ib = This->stateBlock->pIndexData;
5290 if(ib) {
5291 IWineD3DIndexBuffer_Release(ib);
5292 This->stateBlock->pIndexData = NULL;
5294 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5295 * SetStreamSource to specify a vertex buffer
5298 return WINED3D_OK;
5301 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5302 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5303 const WineDirect3DVertexStridedData *DrawPrimStrideData)
5305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5307 /* Mark the state dirty until we have nicer tracking
5308 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5309 * that value.
5311 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5312 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5313 This->stateBlock->baseVertexIndex = 0;
5314 This->up_strided = DrawPrimStrideData;
5315 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, NULL, 0);
5316 This->up_strided = NULL;
5317 return WINED3D_OK;
5320 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5321 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5322 const WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, const void *pIndexData,
5323 WINED3DFORMAT IndexDataFormat)
5325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5326 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5328 /* Mark the state dirty until we have nicer tracking
5329 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5330 * that value.
5332 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5333 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5334 This->stateBlock->streamIsUP = TRUE;
5335 This->stateBlock->baseVertexIndex = 0;
5336 This->up_strided = DrawPrimStrideData;
5337 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5338 This->up_strided = NULL;
5339 return WINED3D_OK;
5342 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5343 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5344 * not callable by the app directly no parameter validation checks are needed here.
5346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5347 WINED3DLOCKED_BOX src;
5348 WINED3DLOCKED_BOX dst;
5349 HRESULT hr;
5350 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5352 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5353 * dirtification to improve loading performance.
5355 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5356 if(FAILED(hr)) return hr;
5357 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5358 if(FAILED(hr)) {
5359 IWineD3DVolume_UnlockBox(pSourceVolume);
5360 return hr;
5363 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5365 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5366 if(FAILED(hr)) {
5367 IWineD3DVolume_UnlockBox(pSourceVolume);
5368 } else {
5369 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5371 return hr;
5374 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5375 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5377 HRESULT hr = WINED3D_OK;
5378 WINED3DRESOURCETYPE sourceType;
5379 WINED3DRESOURCETYPE destinationType;
5380 int i ,levels;
5382 /* TODO: think about moving the code into IWineD3DBaseTexture */
5384 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5386 /* verify that the source and destination textures aren't NULL */
5387 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5388 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5389 This, pSourceTexture, pDestinationTexture);
5390 hr = WINED3DERR_INVALIDCALL;
5393 if (pSourceTexture == pDestinationTexture) {
5394 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5395 This, pSourceTexture, pDestinationTexture);
5396 hr = WINED3DERR_INVALIDCALL;
5398 /* Verify that the source and destination textures are the same type */
5399 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5400 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5402 if (sourceType != destinationType) {
5403 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5404 This);
5405 hr = WINED3DERR_INVALIDCALL;
5408 /* check that both textures have the identical numbers of levels */
5409 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5410 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5411 hr = WINED3DERR_INVALIDCALL;
5414 if (WINED3D_OK == hr) {
5416 /* Make sure that the destination texture is loaded */
5417 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5419 /* Update every surface level of the texture */
5420 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5422 switch (sourceType) {
5423 case WINED3DRTYPE_TEXTURE:
5425 IWineD3DSurface *srcSurface;
5426 IWineD3DSurface *destSurface;
5428 for (i = 0 ; i < levels ; ++i) {
5429 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5430 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5431 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5432 IWineD3DSurface_Release(srcSurface);
5433 IWineD3DSurface_Release(destSurface);
5434 if (WINED3D_OK != hr) {
5435 WARN("(%p) : Call to update surface failed\n", This);
5436 return hr;
5440 break;
5441 case WINED3DRTYPE_CUBETEXTURE:
5443 IWineD3DSurface *srcSurface;
5444 IWineD3DSurface *destSurface;
5445 WINED3DCUBEMAP_FACES faceType;
5447 for (i = 0 ; i < levels ; ++i) {
5448 /* Update each cube face */
5449 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5450 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5451 if (WINED3D_OK != hr) {
5452 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5453 } else {
5454 TRACE("Got srcSurface %p\n", srcSurface);
5456 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5457 if (WINED3D_OK != hr) {
5458 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5459 } else {
5460 TRACE("Got desrSurface %p\n", destSurface);
5462 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5463 IWineD3DSurface_Release(srcSurface);
5464 IWineD3DSurface_Release(destSurface);
5465 if (WINED3D_OK != hr) {
5466 WARN("(%p) : Call to update surface failed\n", This);
5467 return hr;
5472 break;
5474 case WINED3DRTYPE_VOLUMETEXTURE:
5476 IWineD3DVolume *srcVolume = NULL;
5477 IWineD3DVolume *destVolume = NULL;
5479 for (i = 0 ; i < levels ; ++i) {
5480 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5481 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5482 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5483 IWineD3DVolume_Release(srcVolume);
5484 IWineD3DVolume_Release(destVolume);
5485 if (WINED3D_OK != hr) {
5486 WARN("(%p) : Call to update volume failed\n", This);
5487 return hr;
5491 break;
5493 default:
5494 FIXME("(%p) : Unsupported source and destination type\n", This);
5495 hr = WINED3DERR_INVALIDCALL;
5499 return hr;
5502 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5503 IWineD3DSwapChain *swapChain;
5504 HRESULT hr;
5505 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5506 if(hr == WINED3D_OK) {
5507 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5508 IWineD3DSwapChain_Release(swapChain);
5510 return hr;
5513 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5515 IWineD3DBaseTextureImpl *texture;
5516 const struct GlPixelFormatDesc *gl_info;
5517 DWORD i;
5519 TRACE("(%p) : %p\n", This, pNumPasses);
5521 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5522 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5523 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5524 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5526 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5527 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5528 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5531 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5532 if(!texture) continue;
5533 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5534 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5536 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5537 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5538 return E_FAIL;
5540 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5541 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5542 return E_FAIL;
5544 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5545 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5546 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5547 return E_FAIL;
5551 /* return a sensible default */
5552 *pNumPasses = 1;
5554 TRACE("returning D3D_OK\n");
5555 return WINED3D_OK;
5558 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5560 int i;
5562 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5563 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5564 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5565 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5570 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5572 int j;
5573 UINT NewSize;
5574 PALETTEENTRY **palettes;
5576 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5578 if (PaletteNumber >= MAX_PALETTES) {
5579 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5580 return WINED3DERR_INVALIDCALL;
5583 if (PaletteNumber >= This->NumberOfPalettes) {
5584 NewSize = This->NumberOfPalettes;
5585 do {
5586 NewSize *= 2;
5587 } while(PaletteNumber >= NewSize);
5588 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5589 if (!palettes) {
5590 ERR("Out of memory!\n");
5591 return E_OUTOFMEMORY;
5593 This->palettes = palettes;
5594 This->NumberOfPalettes = NewSize;
5597 if (!This->palettes[PaletteNumber]) {
5598 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5599 if (!This->palettes[PaletteNumber]) {
5600 ERR("Out of memory!\n");
5601 return E_OUTOFMEMORY;
5605 for (j = 0; j < 256; ++j) {
5606 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5607 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5608 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5609 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5611 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5612 TRACE("(%p) : returning\n", This);
5613 return WINED3D_OK;
5616 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5618 int j;
5619 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5620 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5621 /* What happens in such situation isn't documented; Native seems to silently abort
5622 on such conditions. Return Invalid Call. */
5623 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5624 return WINED3DERR_INVALIDCALL;
5626 for (j = 0; j < 256; ++j) {
5627 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5628 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5629 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5630 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5632 TRACE("(%p) : returning\n", This);
5633 return WINED3D_OK;
5636 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5638 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5639 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5640 (tested with reference rasterizer). Return Invalid Call. */
5641 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5642 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5643 return WINED3DERR_INVALIDCALL;
5645 /*TODO: stateblocks */
5646 if (This->currentPalette != PaletteNumber) {
5647 This->currentPalette = PaletteNumber;
5648 dirtify_p8_texture_samplers(This);
5650 TRACE("(%p) : returning\n", This);
5651 return WINED3D_OK;
5654 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5656 if (PaletteNumber == NULL) {
5657 WARN("(%p) : returning Invalid Call\n", This);
5658 return WINED3DERR_INVALIDCALL;
5660 /*TODO: stateblocks */
5661 *PaletteNumber = This->currentPalette;
5662 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5663 return WINED3D_OK;
5666 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5668 static BOOL warned;
5669 if (!warned)
5671 FIXME("(%p) : stub\n", This);
5672 warned = TRUE;
5675 This->softwareVertexProcessing = bSoftware;
5676 return WINED3D_OK;
5680 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5682 static BOOL warned;
5683 if (!warned)
5685 FIXME("(%p) : stub\n", This);
5686 warned = TRUE;
5688 return This->softwareVertexProcessing;
5692 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5694 IWineD3DSwapChain *swapChain;
5695 HRESULT hr;
5697 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5699 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5700 if(hr == WINED3D_OK){
5701 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5702 IWineD3DSwapChain_Release(swapChain);
5703 }else{
5704 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5706 return hr;
5710 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5712 static BOOL warned;
5713 if(nSegments != 0.0f) {
5714 if (!warned)
5716 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5717 warned = TRUE;
5720 return WINED3D_OK;
5723 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5725 static BOOL warned;
5726 if (!warned)
5728 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5729 warned = TRUE;
5731 return 0.0f;
5734 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5736 /** TODO: remove casts to IWineD3DSurfaceImpl
5737 * NOTE: move code to surface to accomplish this
5738 ****************************************/
5739 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5740 int srcWidth, srcHeight;
5741 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5742 WINED3DFORMAT destFormat, srcFormat;
5743 UINT destSize;
5744 int srcLeft, destLeft, destTop;
5745 WINED3DPOOL srcPool, destPool;
5746 int offset = 0;
5747 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5748 glDescriptor *glDescription = NULL;
5749 GLenum dummy;
5750 int sampler;
5751 int bpp;
5752 CONVERT_TYPES convert = NO_CONVERSION;
5754 WINED3DSURFACE_DESC winedesc;
5756 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5757 memset(&winedesc, 0, sizeof(winedesc));
5758 winedesc.Width = &srcSurfaceWidth;
5759 winedesc.Height = &srcSurfaceHeight;
5760 winedesc.Pool = &srcPool;
5761 winedesc.Format = &srcFormat;
5763 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5765 winedesc.Width = &destSurfaceWidth;
5766 winedesc.Height = &destSurfaceHeight;
5767 winedesc.Pool = &destPool;
5768 winedesc.Format = &destFormat;
5769 winedesc.Size = &destSize;
5771 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5773 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5774 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5775 return WINED3DERR_INVALIDCALL;
5778 /* This call loads the opengl surface directly, instead of copying the surface to the
5779 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5780 * copy in sysmem and use regular surface loading.
5782 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5783 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5784 if(convert != NO_CONVERSION) {
5785 return IWineD3DSurface_BltFast(pDestinationSurface,
5786 pDestPoint ? pDestPoint->x : 0,
5787 pDestPoint ? pDestPoint->y : 0,
5788 pSourceSurface, pSourceRect, 0);
5791 if (destFormat == WINED3DFMT_UNKNOWN) {
5792 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5793 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5795 /* Get the update surface description */
5796 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5799 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5801 ENTER_GL();
5802 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5803 checkGLcall("glActiveTextureARB");
5804 LEAVE_GL();
5806 /* Make sure the surface is loaded and up to date */
5807 IWineD3DSurface_PreLoad(pDestinationSurface);
5808 IWineD3DSurface_BindTexture(pDestinationSurface);
5810 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5812 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5813 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5814 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5815 srcLeft = pSourceRect ? pSourceRect->left : 0;
5816 destLeft = pDestPoint ? pDestPoint->x : 0;
5817 destTop = pDestPoint ? pDestPoint->y : 0;
5820 /* This function doesn't support compressed textures
5821 the pitch is just bytesPerPixel * width */
5822 if(srcWidth != srcSurfaceWidth || srcLeft ){
5823 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5824 offset += srcLeft * pSrcSurface->bytesPerPixel;
5825 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5827 /* TODO DXT formats */
5829 if(pSourceRect != NULL && pSourceRect->top != 0){
5830 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5832 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5833 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat,
5834 glDescription->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5836 /* Sanity check */
5837 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5839 /* need to lock the surface to get the data */
5840 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5843 ENTER_GL();
5845 /* TODO: Cube and volume support */
5846 if(rowoffset != 0){
5847 /* not a whole row so we have to do it a line at a time */
5848 int j;
5850 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5851 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5853 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5855 glTexSubImage2D(glDescription->target
5856 ,glDescription->level
5857 ,destLeft
5859 ,srcWidth
5861 ,glDescription->glFormat
5862 ,glDescription->glType
5863 ,data /* could be quicker using */
5865 data += rowoffset;
5868 } else { /* Full width, so just write out the whole texture */
5869 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5871 if (WINED3DFMT_DXT1 == destFormat ||
5872 WINED3DFMT_DXT2 == destFormat ||
5873 WINED3DFMT_DXT3 == destFormat ||
5874 WINED3DFMT_DXT4 == destFormat ||
5875 WINED3DFMT_DXT5 == destFormat) {
5876 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5877 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5878 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5879 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5880 } if (destFormat != srcFormat) {
5881 FIXME("Updating mixed format compressed texture is not curretly support\n");
5882 } else {
5883 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
5884 glDescription->glFormatInternal, srcWidth, srcHeight, 0, destSize, data));
5886 } else {
5887 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5891 } else {
5892 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
5893 srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, data);
5896 checkGLcall("glTexSubImage2D");
5898 LEAVE_GL();
5900 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5901 sampler = This->rev_tex_unit_map[0];
5902 if (sampler != -1) {
5903 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5906 return WINED3D_OK;
5909 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5911 struct WineD3DRectPatch *patch;
5912 unsigned int i;
5913 struct list *e;
5914 BOOL found;
5915 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5917 if(!(Handle || pRectPatchInfo)) {
5918 /* TODO: Write a test for the return value, thus the FIXME */
5919 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5920 return WINED3DERR_INVALIDCALL;
5923 if(Handle) {
5924 i = PATCHMAP_HASHFUNC(Handle);
5925 found = FALSE;
5926 LIST_FOR_EACH(e, &This->patches[i]) {
5927 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5928 if(patch->Handle == Handle) {
5929 found = TRUE;
5930 break;
5934 if(!found) {
5935 TRACE("Patch does not exist. Creating a new one\n");
5936 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5937 patch->Handle = Handle;
5938 list_add_head(&This->patches[i], &patch->entry);
5939 } else {
5940 TRACE("Found existing patch %p\n", patch);
5942 } else {
5943 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5944 * attributes we have to tesselate, read back, and draw. This needs a patch
5945 * management structure instance. Create one.
5947 * A possible improvement is to check if a vertex shader is used, and if not directly
5948 * draw the patch.
5950 FIXME("Drawing an uncached patch. This is slow\n");
5951 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5954 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5955 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5956 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5957 HRESULT hr;
5958 TRACE("Tesselation density or patch info changed, retesselating\n");
5960 if(pRectPatchInfo) {
5961 patch->RectPatchInfo = *pRectPatchInfo;
5963 patch->numSegs[0] = pNumSegs[0];
5964 patch->numSegs[1] = pNumSegs[1];
5965 patch->numSegs[2] = pNumSegs[2];
5966 patch->numSegs[3] = pNumSegs[3];
5968 hr = tesselate_rectpatch(This, patch);
5969 if(FAILED(hr)) {
5970 WARN("Patch tesselation failed\n");
5972 /* Do not release the handle to store the params of the patch */
5973 if(!Handle) {
5974 HeapFree(GetProcessHeap(), 0, patch);
5976 return hr;
5980 This->currentPatch = patch;
5981 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5982 This->currentPatch = NULL;
5984 /* Destroy uncached patches */
5985 if(!Handle) {
5986 HeapFree(GetProcessHeap(), 0, patch->mem);
5987 HeapFree(GetProcessHeap(), 0, patch);
5989 return WINED3D_OK;
5992 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5994 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5995 FIXME("(%p) : Stub\n", This);
5996 return WINED3D_OK;
5999 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6001 int i;
6002 struct WineD3DRectPatch *patch;
6003 struct list *e;
6004 TRACE("(%p) Handle(%d)\n", This, Handle);
6006 i = PATCHMAP_HASHFUNC(Handle);
6007 LIST_FOR_EACH(e, &This->patches[i]) {
6008 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6009 if(patch->Handle == Handle) {
6010 TRACE("Deleting patch %p\n", patch);
6011 list_remove(&patch->entry);
6012 HeapFree(GetProcessHeap(), 0, patch->mem);
6013 HeapFree(GetProcessHeap(), 0, patch);
6014 return WINED3D_OK;
6018 /* TODO: Write a test for the return value */
6019 FIXME("Attempt to destroy nonexistent patch\n");
6020 return WINED3DERR_INVALIDCALL;
6023 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6024 HRESULT hr;
6025 IWineD3DSwapChain *swapchain;
6027 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6028 if (SUCCEEDED(hr)) {
6029 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6030 return swapchain;
6033 return NULL;
6036 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6038 IWineD3DSwapChain *swapchain;
6040 swapchain = get_swapchain(surface);
6041 if (swapchain) {
6042 GLenum buffer;
6044 TRACE("Surface %p is onscreen\n", surface);
6046 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6047 ENTER_GL();
6048 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6049 buffer = surface_get_gl_buffer(surface, swapchain);
6050 glDrawBuffer(buffer);
6051 checkGLcall("glDrawBuffer()");
6052 } else {
6053 TRACE("Surface %p is offscreen\n", surface);
6055 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6056 ENTER_GL();
6057 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6058 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6059 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6060 checkGLcall("glFramebufferRenderbufferEXT");
6063 if (rect) {
6064 glEnable(GL_SCISSOR_TEST);
6065 if(!swapchain) {
6066 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6067 } else {
6068 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6069 rect->x2 - rect->x1, rect->y2 - rect->y1);
6071 checkGLcall("glScissor");
6072 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6073 } else {
6074 glDisable(GL_SCISSOR_TEST);
6076 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6078 glDisable(GL_BLEND);
6079 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6081 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6082 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6084 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6085 glClear(GL_COLOR_BUFFER_BIT);
6086 checkGLcall("glClear");
6088 if (This->activeContext->current_fbo) {
6089 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6090 } else {
6091 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6092 checkGLcall("glBindFramebuffer()");
6095 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6096 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6097 glDrawBuffer(GL_BACK);
6098 checkGLcall("glDrawBuffer()");
6101 LEAVE_GL();
6104 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6105 unsigned int r, g, b, a;
6106 DWORD ret;
6108 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6109 destfmt == WINED3DFMT_R8G8B8)
6110 return color;
6112 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6114 a = (color & 0xff000000) >> 24;
6115 r = (color & 0x00ff0000) >> 16;
6116 g = (color & 0x0000ff00) >> 8;
6117 b = (color & 0x000000ff) >> 0;
6119 switch(destfmt)
6121 case WINED3DFMT_R5G6B5:
6122 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6123 r = (r * 32) / 256;
6124 g = (g * 64) / 256;
6125 b = (b * 32) / 256;
6126 ret = r << 11;
6127 ret |= g << 5;
6128 ret |= b;
6129 TRACE("Returning %08x\n", ret);
6130 return ret;
6132 case WINED3DFMT_X1R5G5B5:
6133 case WINED3DFMT_A1R5G5B5:
6134 a = (a * 2) / 256;
6135 r = (r * 32) / 256;
6136 g = (g * 32) / 256;
6137 b = (b * 32) / 256;
6138 ret = a << 15;
6139 ret |= r << 10;
6140 ret |= g << 5;
6141 ret |= b << 0;
6142 TRACE("Returning %08x\n", ret);
6143 return ret;
6145 case WINED3DFMT_A8:
6146 TRACE("Returning %08x\n", a);
6147 return a;
6149 case WINED3DFMT_X4R4G4B4:
6150 case WINED3DFMT_A4R4G4B4:
6151 a = (a * 16) / 256;
6152 r = (r * 16) / 256;
6153 g = (g * 16) / 256;
6154 b = (b * 16) / 256;
6155 ret = a << 12;
6156 ret |= r << 8;
6157 ret |= g << 4;
6158 ret |= b << 0;
6159 TRACE("Returning %08x\n", ret);
6160 return ret;
6162 case WINED3DFMT_R3G3B2:
6163 r = (r * 8) / 256;
6164 g = (g * 8) / 256;
6165 b = (b * 4) / 256;
6166 ret = r << 5;
6167 ret |= g << 2;
6168 ret |= b << 0;
6169 TRACE("Returning %08x\n", ret);
6170 return ret;
6172 case WINED3DFMT_X8B8G8R8:
6173 case WINED3DFMT_A8B8G8R8:
6174 ret = a << 24;
6175 ret |= b << 16;
6176 ret |= g << 8;
6177 ret |= r << 0;
6178 TRACE("Returning %08x\n", ret);
6179 return ret;
6181 case WINED3DFMT_A2R10G10B10:
6182 a = (a * 4) / 256;
6183 r = (r * 1024) / 256;
6184 g = (g * 1024) / 256;
6185 b = (b * 1024) / 256;
6186 ret = a << 30;
6187 ret |= r << 20;
6188 ret |= g << 10;
6189 ret |= b << 0;
6190 TRACE("Returning %08x\n", ret);
6191 return ret;
6193 case WINED3DFMT_A2B10G10R10:
6194 a = (a * 4) / 256;
6195 r = (r * 1024) / 256;
6196 g = (g * 1024) / 256;
6197 b = (b * 1024) / 256;
6198 ret = a << 30;
6199 ret |= b << 20;
6200 ret |= g << 10;
6201 ret |= r << 0;
6202 TRACE("Returning %08x\n", ret);
6203 return ret;
6205 default:
6206 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6207 return 0;
6211 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6212 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6213 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6214 WINEDDBLTFX BltFx;
6215 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6217 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6218 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6219 return WINED3DERR_INVALIDCALL;
6222 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6223 color_fill_fbo(iface, pSurface, pRect, color);
6224 return WINED3D_OK;
6225 } else {
6226 /* Just forward this to the DirectDraw blitting engine */
6227 memset(&BltFx, 0, sizeof(BltFx));
6228 BltFx.dwSize = sizeof(BltFx);
6229 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6230 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6231 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6235 /* rendertarget and depth stencil functions */
6236 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6239 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6240 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6241 return WINED3DERR_INVALIDCALL;
6244 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6245 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6246 /* Note inc ref on returned surface */
6247 if(*ppRenderTarget != NULL)
6248 IWineD3DSurface_AddRef(*ppRenderTarget);
6249 return WINED3D_OK;
6252 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6253 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6254 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6255 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6256 IWineD3DSwapChainImpl *Swapchain;
6257 HRESULT hr;
6259 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6261 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6262 if(hr != WINED3D_OK) {
6263 ERR("Can't get the swapchain\n");
6264 return hr;
6267 /* Make sure to release the swapchain */
6268 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6270 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6271 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6272 return WINED3DERR_INVALIDCALL;
6274 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6275 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6276 return WINED3DERR_INVALIDCALL;
6279 if(Swapchain->frontBuffer != Front) {
6280 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6282 if(Swapchain->frontBuffer)
6283 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6284 Swapchain->frontBuffer = Front;
6286 if(Swapchain->frontBuffer) {
6287 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6291 if(Back && !Swapchain->backBuffer) {
6292 /* We need memory for the back buffer array - only one back buffer this way */
6293 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6294 if(!Swapchain->backBuffer) {
6295 ERR("Out of memory\n");
6296 return E_OUTOFMEMORY;
6300 if(Swapchain->backBuffer[0] != Back) {
6301 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6303 /* What to do about the context here in the case of multithreading? Not sure.
6304 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6306 ENTER_GL();
6307 if(!Swapchain->backBuffer[0]) {
6308 /* GL was told to draw to the front buffer at creation,
6309 * undo that
6311 glDrawBuffer(GL_BACK);
6312 checkGLcall("glDrawBuffer(GL_BACK)");
6313 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6314 Swapchain->presentParms.BackBufferCount = 1;
6315 } else if (!Back) {
6316 /* That makes problems - disable for now */
6317 /* glDrawBuffer(GL_FRONT); */
6318 checkGLcall("glDrawBuffer(GL_FRONT)");
6319 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6320 Swapchain->presentParms.BackBufferCount = 0;
6322 LEAVE_GL();
6324 if(Swapchain->backBuffer[0])
6325 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6326 Swapchain->backBuffer[0] = Back;
6328 if(Swapchain->backBuffer[0]) {
6329 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6330 } else {
6331 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6332 Swapchain->backBuffer = NULL;
6337 return WINED3D_OK;
6340 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6341 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6342 *ppZStencilSurface = This->stencilBufferTarget;
6343 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6345 if(*ppZStencilSurface != NULL) {
6346 /* Note inc ref on returned surface */
6347 IWineD3DSurface_AddRef(*ppZStencilSurface);
6348 return WINED3D_OK;
6349 } else {
6350 return WINED3DERR_NOTFOUND;
6354 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6355 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6358 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6359 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6360 GLenum gl_filter;
6361 POINT offset = {0, 0};
6363 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6364 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6365 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6366 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6368 switch (filter) {
6369 case WINED3DTEXF_LINEAR:
6370 gl_filter = GL_LINEAR;
6371 break;
6373 default:
6374 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6375 case WINED3DTEXF_NONE:
6376 case WINED3DTEXF_POINT:
6377 gl_filter = GL_NEAREST;
6378 break;
6381 /* Attach src surface to src fbo */
6382 src_swapchain = get_swapchain(src_surface);
6383 if (src_swapchain) {
6384 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6386 TRACE("Source surface %p is onscreen\n", src_surface);
6387 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6388 /* Make sure the drawable is up to date. In the offscreen case
6389 * attach_surface_fbo() implicitly takes care of this. */
6390 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6392 if(buffer == GL_FRONT) {
6393 RECT windowsize;
6394 UINT h;
6395 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6396 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6397 h = windowsize.bottom - windowsize.top;
6398 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6399 src_rect->y1 = offset.y + h - src_rect->y1;
6400 src_rect->y2 = offset.y + h - src_rect->y2;
6401 } else {
6402 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6403 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6406 ENTER_GL();
6407 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6408 glReadBuffer(buffer);
6409 checkGLcall("glReadBuffer()");
6410 } else {
6411 TRACE("Source surface %p is offscreen\n", src_surface);
6412 ENTER_GL();
6413 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6414 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6415 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6416 checkGLcall("glReadBuffer()");
6417 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6418 checkGLcall("glFramebufferRenderbufferEXT");
6420 LEAVE_GL();
6422 /* Attach dst surface to dst fbo */
6423 dst_swapchain = get_swapchain(dst_surface);
6424 if (dst_swapchain) {
6425 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6427 TRACE("Destination surface %p is onscreen\n", dst_surface);
6428 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6429 /* Make sure the drawable is up to date. In the offscreen case
6430 * attach_surface_fbo() implicitly takes care of this. */
6431 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6433 if(buffer == GL_FRONT) {
6434 RECT windowsize;
6435 UINT h;
6436 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6437 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6438 h = windowsize.bottom - windowsize.top;
6439 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6440 dst_rect->y1 = offset.y + h - dst_rect->y1;
6441 dst_rect->y2 = offset.y + h - dst_rect->y2;
6442 } else {
6443 /* Screen coords = window coords, surface height = window height */
6444 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6445 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6448 ENTER_GL();
6449 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6450 glDrawBuffer(buffer);
6451 checkGLcall("glDrawBuffer()");
6452 } else {
6453 TRACE("Destination surface %p is offscreen\n", dst_surface);
6455 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6456 if(!src_swapchain) {
6457 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6460 ENTER_GL();
6461 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6462 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6463 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6464 checkGLcall("glDrawBuffer()");
6465 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6466 checkGLcall("glFramebufferRenderbufferEXT");
6468 glDisable(GL_SCISSOR_TEST);
6469 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6471 if (flip) {
6472 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6473 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6474 checkGLcall("glBlitFramebuffer()");
6475 } else {
6476 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6477 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6478 checkGLcall("glBlitFramebuffer()");
6481 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6483 if (This->activeContext->current_fbo) {
6484 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6485 } else {
6486 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6487 checkGLcall("glBindFramebuffer()");
6490 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6491 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6492 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6493 glDrawBuffer(GL_BACK);
6494 checkGLcall("glDrawBuffer()");
6496 LEAVE_GL();
6499 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6500 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6501 WINED3DVIEWPORT viewport;
6503 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6505 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6506 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6507 This, RenderTargetIndex, GL_LIMITS(buffers));
6508 return WINED3DERR_INVALIDCALL;
6511 /* MSDN says that null disables the render target
6512 but a device must always be associated with a render target
6513 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6515 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6516 FIXME("Trying to set render target 0 to NULL\n");
6517 return WINED3DERR_INVALIDCALL;
6519 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6520 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);
6521 return WINED3DERR_INVALIDCALL;
6524 /* If we are trying to set what we already have, don't bother */
6525 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6526 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6527 return WINED3D_OK;
6529 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6530 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6531 This->render_targets[RenderTargetIndex] = pRenderTarget;
6533 /* Render target 0 is special */
6534 if(RenderTargetIndex == 0) {
6535 /* Finally, reset the viewport as the MSDN states. */
6536 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6537 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6538 viewport.X = 0;
6539 viewport.Y = 0;
6540 viewport.MaxZ = 1.0f;
6541 viewport.MinZ = 0.0f;
6542 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6543 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6544 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6546 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6548 return WINED3D_OK;
6551 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6553 HRESULT hr = WINED3D_OK;
6554 IWineD3DSurface *tmp;
6556 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6558 if (pNewZStencil == This->stencilBufferTarget) {
6559 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6560 } else {
6561 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6562 * depending on the renter target implementation being used.
6563 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6564 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6565 * stencil buffer and incur an extra memory overhead
6566 ******************************************************/
6568 if (This->stencilBufferTarget) {
6569 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6570 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6571 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6572 } else {
6573 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6574 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6575 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6579 tmp = This->stencilBufferTarget;
6580 This->stencilBufferTarget = pNewZStencil;
6581 /* should we be calling the parent or the wined3d surface? */
6582 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6583 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6584 hr = WINED3D_OK;
6586 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6587 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6588 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6589 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6590 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6594 return hr;
6597 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6598 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6600 /* TODO: the use of Impl is deprecated. */
6601 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6602 WINED3DLOCKED_RECT lockedRect;
6604 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6606 /* some basic validation checks */
6607 if(This->cursorTexture) {
6608 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6609 ENTER_GL();
6610 glDeleteTextures(1, &This->cursorTexture);
6611 LEAVE_GL();
6612 This->cursorTexture = 0;
6615 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6616 This->haveHardwareCursor = TRUE;
6617 else
6618 This->haveHardwareCursor = FALSE;
6620 if(pCursorBitmap) {
6621 WINED3DLOCKED_RECT rect;
6623 /* MSDN: Cursor must be A8R8G8B8 */
6624 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6625 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6626 return WINED3DERR_INVALIDCALL;
6629 /* MSDN: Cursor must be smaller than the display mode */
6630 if(pSur->currentDesc.Width > This->ddraw_width ||
6631 pSur->currentDesc.Height > This->ddraw_height) {
6632 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);
6633 return WINED3DERR_INVALIDCALL;
6636 if (!This->haveHardwareCursor) {
6637 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6639 /* Do not store the surface's pointer because the application may
6640 * release it after setting the cursor image. Windows doesn't
6641 * addref the set surface, so we can't do this either without
6642 * creating circular refcount dependencies. Copy out the gl texture
6643 * instead.
6645 This->cursorWidth = pSur->currentDesc.Width;
6646 This->cursorHeight = pSur->currentDesc.Height;
6647 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6649 const struct GlPixelFormatDesc *glDesc;
6650 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6651 char *mem, *bits = (char *)rect.pBits;
6652 GLint intfmt = glDesc->glInternal;
6653 GLint format = glDesc->glFormat;
6654 GLint type = glDesc->glType;
6655 INT height = This->cursorHeight;
6656 INT width = This->cursorWidth;
6657 INT bpp = tableEntry->bpp;
6658 INT i, sampler;
6660 /* Reformat the texture memory (pitch and width can be
6661 * different) */
6662 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6663 for(i = 0; i < height; i++)
6664 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6665 IWineD3DSurface_UnlockRect(pCursorBitmap);
6666 ENTER_GL();
6668 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6669 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6670 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6673 /* Make sure that a proper texture unit is selected */
6674 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6675 checkGLcall("glActiveTextureARB");
6676 sampler = This->rev_tex_unit_map[0];
6677 if (sampler != -1) {
6678 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6680 /* Create a new cursor texture */
6681 glGenTextures(1, &This->cursorTexture);
6682 checkGLcall("glGenTextures");
6683 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6684 checkGLcall("glBindTexture");
6685 /* Copy the bitmap memory into the cursor texture */
6686 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6687 HeapFree(GetProcessHeap(), 0, mem);
6688 checkGLcall("glTexImage2D");
6690 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6691 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6692 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6695 LEAVE_GL();
6697 else
6699 FIXME("A cursor texture was not returned.\n");
6700 This->cursorTexture = 0;
6703 else
6705 /* Draw a hardware cursor */
6706 ICONINFO cursorInfo;
6707 HCURSOR cursor;
6708 /* Create and clear maskBits because it is not needed for
6709 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6710 * chunks. */
6711 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6712 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6713 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6714 WINED3DLOCK_NO_DIRTY_UPDATE |
6715 WINED3DLOCK_READONLY
6717 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6718 pSur->currentDesc.Height);
6720 cursorInfo.fIcon = FALSE;
6721 cursorInfo.xHotspot = XHotSpot;
6722 cursorInfo.yHotspot = YHotSpot;
6723 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6724 pSur->currentDesc.Height, 1,
6725 1, &maskBits);
6726 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6727 pSur->currentDesc.Height, 1,
6728 32, lockedRect.pBits);
6729 IWineD3DSurface_UnlockRect(pCursorBitmap);
6730 /* Create our cursor and clean up. */
6731 cursor = CreateIconIndirect(&cursorInfo);
6732 SetCursor(cursor);
6733 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6734 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6735 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6736 This->hardwareCursor = cursor;
6737 HeapFree(GetProcessHeap(), 0, maskBits);
6741 This->xHotSpot = XHotSpot;
6742 This->yHotSpot = YHotSpot;
6743 return WINED3D_OK;
6746 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6748 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6750 This->xScreenSpace = XScreenSpace;
6751 This->yScreenSpace = YScreenSpace;
6753 return;
6757 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6759 BOOL oldVisible = This->bCursorVisible;
6760 POINT pt;
6762 TRACE("(%p) : visible(%d)\n", This, bShow);
6765 * When ShowCursor is first called it should make the cursor appear at the OS's last
6766 * known cursor position. Because of this, some applications just repetitively call
6767 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6769 GetCursorPos(&pt);
6770 This->xScreenSpace = pt.x;
6771 This->yScreenSpace = pt.y;
6773 if (This->haveHardwareCursor) {
6774 This->bCursorVisible = bShow;
6775 if (bShow)
6776 SetCursor(This->hardwareCursor);
6777 else
6778 SetCursor(NULL);
6780 else
6782 if (This->cursorTexture)
6783 This->bCursorVisible = bShow;
6786 return oldVisible;
6789 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6791 IWineD3DResourceImpl *resource;
6792 TRACE("(%p) : state (%u)\n", This, This->state);
6794 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6795 switch (This->state) {
6796 case WINED3D_OK:
6797 return WINED3D_OK;
6798 case WINED3DERR_DEVICELOST:
6800 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6801 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6802 return WINED3DERR_DEVICENOTRESET;
6804 return WINED3DERR_DEVICELOST;
6806 case WINED3DERR_DRIVERINTERNALERROR:
6807 return WINED3DERR_DRIVERINTERNALERROR;
6810 /* Unknown state */
6811 return WINED3DERR_DRIVERINTERNALERROR;
6815 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6817 /** FIXME: Resource tracking needs to be done,
6818 * The closes we can do to this is set the priorities of all managed textures low
6819 * and then reset them.
6820 ***********************************************************/
6821 FIXME("(%p) : stub\n", This);
6822 return WINED3D_OK;
6825 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6827 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6829 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6830 if(surface->Flags & SFLAG_DIBSECTION) {
6831 /* Release the DC */
6832 SelectObject(surface->hDC, surface->dib.holdbitmap);
6833 DeleteDC(surface->hDC);
6834 /* Release the DIB section */
6835 DeleteObject(surface->dib.DIBsection);
6836 surface->dib.bitmap_data = NULL;
6837 surface->resource.allocatedMemory = NULL;
6838 surface->Flags &= ~SFLAG_DIBSECTION;
6840 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6841 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6842 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6843 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6844 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6845 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6846 } else {
6847 surface->pow2Width = surface->pow2Height = 1;
6848 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6849 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6851 surface->glRect.left = 0;
6852 surface->glRect.top = 0;
6853 surface->glRect.right = surface->pow2Width;
6854 surface->glRect.bottom = surface->pow2Height;
6856 if(surface->glDescription.textureName) {
6857 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6858 ENTER_GL();
6859 glDeleteTextures(1, &surface->glDescription.textureName);
6860 LEAVE_GL();
6861 surface->glDescription.textureName = 0;
6862 surface->Flags &= ~SFLAG_CLIENT;
6864 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6865 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6866 surface->Flags |= SFLAG_NONPOW2;
6867 } else {
6868 surface->Flags &= ~SFLAG_NONPOW2;
6870 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6871 surface->resource.allocatedMemory = NULL;
6872 surface->resource.heapMemory = NULL;
6873 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6874 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6875 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6876 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6877 } else {
6878 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6882 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6883 TRACE("Unloading resource %p\n", resource);
6884 IWineD3DResource_UnLoad(resource);
6885 IWineD3DResource_Release(resource);
6886 return S_OK;
6889 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6891 UINT i, count;
6892 WINED3DDISPLAYMODE m;
6893 HRESULT hr;
6895 /* All Windowed modes are supported, as is leaving the current mode */
6896 if(pp->Windowed) return TRUE;
6897 if(!pp->BackBufferWidth) return TRUE;
6898 if(!pp->BackBufferHeight) return TRUE;
6900 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6901 for(i = 0; i < count; i++) {
6902 memset(&m, 0, sizeof(m));
6903 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6904 if(FAILED(hr)) {
6905 ERR("EnumAdapterModes failed\n");
6907 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6908 /* Mode found, it is supported */
6909 return TRUE;
6912 /* Mode not found -> not supported */
6913 return FALSE;
6916 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6918 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6919 UINT i;
6920 IWineD3DBaseShaderImpl *shader;
6922 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6923 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6924 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6927 ENTER_GL();
6928 if(This->depth_blt_texture) {
6929 glDeleteTextures(1, &This->depth_blt_texture);
6930 This->depth_blt_texture = 0;
6932 if (This->depth_blt_rb) {
6933 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
6934 This->depth_blt_rb = 0;
6935 This->depth_blt_rb_w = 0;
6936 This->depth_blt_rb_h = 0;
6938 LEAVE_GL();
6940 This->blitter->free_private(iface);
6941 This->frag_pipe->free_private(iface);
6942 This->shader_backend->shader_free_private(iface);
6944 ENTER_GL();
6945 for (i = 0; i < GL_LIMITS(textures); i++) {
6946 /* Textures are recreated below */
6947 glDeleteTextures(1, &This->dummyTextureName[i]);
6948 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6949 This->dummyTextureName[i] = 0;
6951 LEAVE_GL();
6953 while(This->numContexts) {
6954 DestroyContext(This, This->contexts[0]);
6956 This->activeContext = NULL;
6957 HeapFree(GetProcessHeap(), 0, swapchain->context);
6958 swapchain->context = NULL;
6959 swapchain->num_contexts = 0;
6962 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6964 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6965 HRESULT hr;
6966 IWineD3DSurfaceImpl *target;
6968 /* Recreate the primary swapchain's context */
6969 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6970 if(swapchain->backBuffer) {
6971 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6972 } else {
6973 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6975 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
6976 &swapchain->presentParms);
6977 swapchain->num_contexts = 1;
6978 This->activeContext = swapchain->context[0];
6980 create_dummy_textures(This);
6982 hr = This->shader_backend->shader_alloc_private(iface);
6983 if(FAILED(hr)) {
6984 ERR("Failed to recreate shader private data\n");
6985 goto err_out;
6987 hr = This->frag_pipe->alloc_private(iface);
6988 if(FAILED(hr)) {
6989 TRACE("Fragment pipeline private data couldn't be allocated\n");
6990 goto err_out;
6992 hr = This->blitter->alloc_private(iface);
6993 if(FAILED(hr)) {
6994 TRACE("Blitter private data couldn't be allocated\n");
6995 goto err_out;
6998 return WINED3D_OK;
7000 err_out:
7001 This->blitter->free_private(iface);
7002 This->frag_pipe->free_private(iface);
7003 This->shader_backend->shader_free_private(iface);
7004 return hr;
7007 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7009 IWineD3DSwapChainImpl *swapchain;
7010 HRESULT hr;
7011 BOOL DisplayModeChanged = FALSE;
7012 WINED3DDISPLAYMODE mode;
7013 TRACE("(%p)\n", This);
7015 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7016 if(FAILED(hr)) {
7017 ERR("Failed to get the first implicit swapchain\n");
7018 return hr;
7021 if(!is_display_mode_supported(This, pPresentationParameters)) {
7022 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7023 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7024 pPresentationParameters->BackBufferHeight);
7025 return WINED3DERR_INVALIDCALL;
7028 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7029 * on an existing gl context, so there's no real need for recreation.
7031 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7033 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7035 TRACE("New params:\n");
7036 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7037 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7038 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7039 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7040 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7041 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7042 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7043 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7044 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7045 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7046 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7047 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7048 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7050 /* No special treatment of these parameters. Just store them */
7051 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7052 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7053 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7054 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7056 /* What to do about these? */
7057 if(pPresentationParameters->BackBufferCount != 0 &&
7058 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7059 ERR("Cannot change the back buffer count yet\n");
7061 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7062 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7063 ERR("Cannot change the back buffer format yet\n");
7065 if(pPresentationParameters->hDeviceWindow != NULL &&
7066 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7067 ERR("Cannot change the device window yet\n");
7069 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7070 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7071 return WINED3DERR_INVALIDCALL;
7074 /* Reset the depth stencil */
7075 if (pPresentationParameters->EnableAutoDepthStencil)
7076 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7077 else
7078 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7080 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7082 if(pPresentationParameters->Windowed) {
7083 mode.Width = swapchain->orig_width;
7084 mode.Height = swapchain->orig_height;
7085 mode.RefreshRate = 0;
7086 mode.Format = swapchain->presentParms.BackBufferFormat;
7087 } else {
7088 mode.Width = pPresentationParameters->BackBufferWidth;
7089 mode.Height = pPresentationParameters->BackBufferHeight;
7090 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7091 mode.Format = swapchain->presentParms.BackBufferFormat;
7094 /* Should Width == 800 && Height == 0 set 800x600? */
7095 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7096 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7097 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7099 UINT i;
7101 if(!pPresentationParameters->Windowed) {
7102 DisplayModeChanged = TRUE;
7104 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7105 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7107 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7108 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7109 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7111 if(This->auto_depth_stencil_buffer) {
7112 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7116 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7117 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7118 DisplayModeChanged) {
7120 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7122 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7123 if(swapchain->presentParms.Windowed) {
7124 /* switch from windowed to fs */
7125 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7126 pPresentationParameters->BackBufferWidth,
7127 pPresentationParameters->BackBufferHeight);
7128 } else {
7129 /* Fullscreen -> fullscreen mode change */
7130 MoveWindow(swapchain->win_handle, 0, 0,
7131 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7132 TRUE);
7134 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7135 /* Fullscreen -> windowed switch */
7136 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7138 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7139 } else if(!pPresentationParameters->Windowed) {
7140 DWORD style = This->style, exStyle = This->exStyle;
7141 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7142 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7143 * Reset to clear up their mess. Guild Wars also loses the device during that.
7145 This->style = 0;
7146 This->exStyle = 0;
7147 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7148 pPresentationParameters->BackBufferWidth,
7149 pPresentationParameters->BackBufferHeight);
7150 This->style = style;
7151 This->exStyle = exStyle;
7154 TRACE("Resetting stateblock\n");
7155 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7156 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7158 /* Note: No parent needed for initial internal stateblock */
7159 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7160 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7161 else TRACE("Created stateblock %p\n", This->stateBlock);
7162 This->updateStateBlock = This->stateBlock;
7163 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7165 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7166 if(FAILED(hr)) {
7167 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7170 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7171 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7173 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7174 * first use
7176 return hr;
7179 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7181 /** FIXME: always true at the moment **/
7182 if(!bEnableDialogs) {
7183 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7185 return WINED3D_OK;
7189 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7191 TRACE("(%p) : pParameters %p\n", This, pParameters);
7193 *pParameters = This->createParms;
7194 return WINED3D_OK;
7197 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7198 IWineD3DSwapChain *swapchain;
7200 TRACE("Relaying to swapchain\n");
7202 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7203 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7204 IWineD3DSwapChain_Release(swapchain);
7206 return;
7209 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7210 IWineD3DSwapChain *swapchain;
7212 TRACE("Relaying to swapchain\n");
7214 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7215 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7216 IWineD3DSwapChain_Release(swapchain);
7218 return;
7222 /** ********************************************************
7223 * Notification functions
7224 ** ********************************************************/
7225 /** This function must be called in the release of a resource when ref == 0,
7226 * the contents of resource must still be correct,
7227 * any handles to other resource held by the caller must be closed
7228 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7229 *****************************************************/
7230 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7233 TRACE("(%p) : Adding Resource %p\n", This, resource);
7234 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7237 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7238 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7240 TRACE("(%p) : Removing resource %p\n", This, resource);
7242 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7246 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7248 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7249 int counter;
7251 TRACE("(%p) : resource %p\n", This, resource);
7253 context_resource_released(iface, resource, type);
7255 switch (type) {
7256 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7257 case WINED3DRTYPE_SURFACE: {
7258 unsigned int i;
7260 /* Cleanup any FBO attachments if d3d is enabled */
7261 if(This->d3d_initialized) {
7262 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7263 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7265 TRACE("Last active render target destroyed\n");
7266 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7267 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7268 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7269 * and the lastActiveRenderTarget member shouldn't matter
7271 if(swapchain) {
7272 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7273 TRACE("Activating primary back buffer\n");
7274 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7275 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7276 /* Single buffering environment */
7277 TRACE("Activating primary front buffer\n");
7278 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7279 } else {
7280 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7281 /* Implicit render target destroyed, that means the device is being destroyed
7282 * whatever we set here, it shouldn't matter
7284 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7286 } else {
7287 /* May happen during ddraw uninitialization */
7288 TRACE("Render target set, but swapchain does not exist!\n");
7289 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7293 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7294 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7295 This->render_targets[i] = NULL;
7298 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7299 This->stencilBufferTarget = NULL;
7303 break;
7305 case WINED3DRTYPE_TEXTURE:
7306 case WINED3DRTYPE_CUBETEXTURE:
7307 case WINED3DRTYPE_VOLUMETEXTURE:
7308 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7309 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7310 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7311 This->stateBlock->textures[counter] = NULL;
7313 if (This->updateStateBlock != This->stateBlock ){
7314 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7315 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7316 This->updateStateBlock->textures[counter] = NULL;
7320 break;
7321 case WINED3DRTYPE_VOLUME:
7322 /* TODO: nothing really? */
7323 break;
7324 case WINED3DRTYPE_VERTEXBUFFER:
7325 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7327 int streamNumber;
7328 TRACE("Cleaning up stream pointers\n");
7330 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7331 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7332 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7334 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7335 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7336 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7337 This->updateStateBlock->streamSource[streamNumber] = 0;
7338 /* Set changed flag? */
7341 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) */
7342 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7343 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7344 This->stateBlock->streamSource[streamNumber] = 0;
7349 break;
7350 case WINED3DRTYPE_INDEXBUFFER:
7351 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7352 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7353 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7354 This->updateStateBlock->pIndexData = NULL;
7357 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7358 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7359 This->stateBlock->pIndexData = NULL;
7363 break;
7364 default:
7365 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7366 break;
7370 /* Remove the resource from the resourceStore */
7371 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7373 TRACE("Resource released\n");
7377 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7379 IWineD3DResourceImpl *resource, *cursor;
7380 HRESULT ret;
7381 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7383 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7384 TRACE("enumerating resource %p\n", resource);
7385 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7386 ret = pCallback((IWineD3DResource *) resource, pData);
7387 if(ret == S_FALSE) {
7388 TRACE("Canceling enumeration\n");
7389 break;
7392 return WINED3D_OK;
7395 /**********************************************************
7396 * IWineD3DDevice VTbl follows
7397 **********************************************************/
7399 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7401 /*** IUnknown methods ***/
7402 IWineD3DDeviceImpl_QueryInterface,
7403 IWineD3DDeviceImpl_AddRef,
7404 IWineD3DDeviceImpl_Release,
7405 /*** IWineD3DDevice methods ***/
7406 IWineD3DDeviceImpl_GetParent,
7407 /*** Creation methods**/
7408 IWineD3DDeviceImpl_CreateVertexBuffer,
7409 IWineD3DDeviceImpl_CreateIndexBuffer,
7410 IWineD3DDeviceImpl_CreateStateBlock,
7411 IWineD3DDeviceImpl_CreateSurface,
7412 IWineD3DDeviceImpl_CreateTexture,
7413 IWineD3DDeviceImpl_CreateVolumeTexture,
7414 IWineD3DDeviceImpl_CreateVolume,
7415 IWineD3DDeviceImpl_CreateCubeTexture,
7416 IWineD3DDeviceImpl_CreateQuery,
7417 IWineD3DDeviceImpl_CreateSwapChain,
7418 IWineD3DDeviceImpl_CreateVertexDeclaration,
7419 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7420 IWineD3DDeviceImpl_CreateVertexShader,
7421 IWineD3DDeviceImpl_CreatePixelShader,
7422 IWineD3DDeviceImpl_CreatePalette,
7423 /*** Odd functions **/
7424 IWineD3DDeviceImpl_Init3D,
7425 IWineD3DDeviceImpl_InitGDI,
7426 IWineD3DDeviceImpl_Uninit3D,
7427 IWineD3DDeviceImpl_UninitGDI,
7428 IWineD3DDeviceImpl_SetMultithreaded,
7429 IWineD3DDeviceImpl_EvictManagedResources,
7430 IWineD3DDeviceImpl_GetAvailableTextureMem,
7431 IWineD3DDeviceImpl_GetBackBuffer,
7432 IWineD3DDeviceImpl_GetCreationParameters,
7433 IWineD3DDeviceImpl_GetDeviceCaps,
7434 IWineD3DDeviceImpl_GetDirect3D,
7435 IWineD3DDeviceImpl_GetDisplayMode,
7436 IWineD3DDeviceImpl_SetDisplayMode,
7437 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7438 IWineD3DDeviceImpl_GetRasterStatus,
7439 IWineD3DDeviceImpl_GetSwapChain,
7440 IWineD3DDeviceImpl_Reset,
7441 IWineD3DDeviceImpl_SetDialogBoxMode,
7442 IWineD3DDeviceImpl_SetCursorProperties,
7443 IWineD3DDeviceImpl_SetCursorPosition,
7444 IWineD3DDeviceImpl_ShowCursor,
7445 IWineD3DDeviceImpl_TestCooperativeLevel,
7446 /*** Getters and setters **/
7447 IWineD3DDeviceImpl_SetClipPlane,
7448 IWineD3DDeviceImpl_GetClipPlane,
7449 IWineD3DDeviceImpl_SetClipStatus,
7450 IWineD3DDeviceImpl_GetClipStatus,
7451 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7452 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7453 IWineD3DDeviceImpl_SetDepthStencilSurface,
7454 IWineD3DDeviceImpl_GetDepthStencilSurface,
7455 IWineD3DDeviceImpl_SetGammaRamp,
7456 IWineD3DDeviceImpl_GetGammaRamp,
7457 IWineD3DDeviceImpl_SetIndices,
7458 IWineD3DDeviceImpl_GetIndices,
7459 IWineD3DDeviceImpl_SetBaseVertexIndex,
7460 IWineD3DDeviceImpl_GetBaseVertexIndex,
7461 IWineD3DDeviceImpl_SetLight,
7462 IWineD3DDeviceImpl_GetLight,
7463 IWineD3DDeviceImpl_SetLightEnable,
7464 IWineD3DDeviceImpl_GetLightEnable,
7465 IWineD3DDeviceImpl_SetMaterial,
7466 IWineD3DDeviceImpl_GetMaterial,
7467 IWineD3DDeviceImpl_SetNPatchMode,
7468 IWineD3DDeviceImpl_GetNPatchMode,
7469 IWineD3DDeviceImpl_SetPaletteEntries,
7470 IWineD3DDeviceImpl_GetPaletteEntries,
7471 IWineD3DDeviceImpl_SetPixelShader,
7472 IWineD3DDeviceImpl_GetPixelShader,
7473 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7474 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7475 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7476 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7477 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7478 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7479 IWineD3DDeviceImpl_SetRenderState,
7480 IWineD3DDeviceImpl_GetRenderState,
7481 IWineD3DDeviceImpl_SetRenderTarget,
7482 IWineD3DDeviceImpl_GetRenderTarget,
7483 IWineD3DDeviceImpl_SetFrontBackBuffers,
7484 IWineD3DDeviceImpl_SetSamplerState,
7485 IWineD3DDeviceImpl_GetSamplerState,
7486 IWineD3DDeviceImpl_SetScissorRect,
7487 IWineD3DDeviceImpl_GetScissorRect,
7488 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7489 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7490 IWineD3DDeviceImpl_SetStreamSource,
7491 IWineD3DDeviceImpl_GetStreamSource,
7492 IWineD3DDeviceImpl_SetStreamSourceFreq,
7493 IWineD3DDeviceImpl_GetStreamSourceFreq,
7494 IWineD3DDeviceImpl_SetTexture,
7495 IWineD3DDeviceImpl_GetTexture,
7496 IWineD3DDeviceImpl_SetTextureStageState,
7497 IWineD3DDeviceImpl_GetTextureStageState,
7498 IWineD3DDeviceImpl_SetTransform,
7499 IWineD3DDeviceImpl_GetTransform,
7500 IWineD3DDeviceImpl_SetVertexDeclaration,
7501 IWineD3DDeviceImpl_GetVertexDeclaration,
7502 IWineD3DDeviceImpl_SetVertexShader,
7503 IWineD3DDeviceImpl_GetVertexShader,
7504 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7505 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7506 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7507 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7508 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7509 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7510 IWineD3DDeviceImpl_SetViewport,
7511 IWineD3DDeviceImpl_GetViewport,
7512 IWineD3DDeviceImpl_MultiplyTransform,
7513 IWineD3DDeviceImpl_ValidateDevice,
7514 IWineD3DDeviceImpl_ProcessVertices,
7515 /*** State block ***/
7516 IWineD3DDeviceImpl_BeginStateBlock,
7517 IWineD3DDeviceImpl_EndStateBlock,
7518 /*** Scene management ***/
7519 IWineD3DDeviceImpl_BeginScene,
7520 IWineD3DDeviceImpl_EndScene,
7521 IWineD3DDeviceImpl_Present,
7522 IWineD3DDeviceImpl_Clear,
7523 /*** Drawing ***/
7524 IWineD3DDeviceImpl_DrawPrimitive,
7525 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7526 IWineD3DDeviceImpl_DrawPrimitiveUP,
7527 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7528 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7529 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7530 IWineD3DDeviceImpl_DrawRectPatch,
7531 IWineD3DDeviceImpl_DrawTriPatch,
7532 IWineD3DDeviceImpl_DeletePatch,
7533 IWineD3DDeviceImpl_ColorFill,
7534 IWineD3DDeviceImpl_UpdateTexture,
7535 IWineD3DDeviceImpl_UpdateSurface,
7536 IWineD3DDeviceImpl_GetFrontBufferData,
7537 /*** object tracking ***/
7538 IWineD3DDeviceImpl_ResourceReleased,
7539 IWineD3DDeviceImpl_EnumResources
7542 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7543 WINED3DRS_ALPHABLENDENABLE ,
7544 WINED3DRS_ALPHAFUNC ,
7545 WINED3DRS_ALPHAREF ,
7546 WINED3DRS_ALPHATESTENABLE ,
7547 WINED3DRS_BLENDOP ,
7548 WINED3DRS_COLORWRITEENABLE ,
7549 WINED3DRS_DESTBLEND ,
7550 WINED3DRS_DITHERENABLE ,
7551 WINED3DRS_FILLMODE ,
7552 WINED3DRS_FOGDENSITY ,
7553 WINED3DRS_FOGEND ,
7554 WINED3DRS_FOGSTART ,
7555 WINED3DRS_LASTPIXEL ,
7556 WINED3DRS_SHADEMODE ,
7557 WINED3DRS_SRCBLEND ,
7558 WINED3DRS_STENCILENABLE ,
7559 WINED3DRS_STENCILFAIL ,
7560 WINED3DRS_STENCILFUNC ,
7561 WINED3DRS_STENCILMASK ,
7562 WINED3DRS_STENCILPASS ,
7563 WINED3DRS_STENCILREF ,
7564 WINED3DRS_STENCILWRITEMASK ,
7565 WINED3DRS_STENCILZFAIL ,
7566 WINED3DRS_TEXTUREFACTOR ,
7567 WINED3DRS_WRAP0 ,
7568 WINED3DRS_WRAP1 ,
7569 WINED3DRS_WRAP2 ,
7570 WINED3DRS_WRAP3 ,
7571 WINED3DRS_WRAP4 ,
7572 WINED3DRS_WRAP5 ,
7573 WINED3DRS_WRAP6 ,
7574 WINED3DRS_WRAP7 ,
7575 WINED3DRS_ZENABLE ,
7576 WINED3DRS_ZFUNC ,
7577 WINED3DRS_ZWRITEENABLE
7580 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7581 WINED3DTSS_ALPHAARG0 ,
7582 WINED3DTSS_ALPHAARG1 ,
7583 WINED3DTSS_ALPHAARG2 ,
7584 WINED3DTSS_ALPHAOP ,
7585 WINED3DTSS_BUMPENVLOFFSET ,
7586 WINED3DTSS_BUMPENVLSCALE ,
7587 WINED3DTSS_BUMPENVMAT00 ,
7588 WINED3DTSS_BUMPENVMAT01 ,
7589 WINED3DTSS_BUMPENVMAT10 ,
7590 WINED3DTSS_BUMPENVMAT11 ,
7591 WINED3DTSS_COLORARG0 ,
7592 WINED3DTSS_COLORARG1 ,
7593 WINED3DTSS_COLORARG2 ,
7594 WINED3DTSS_COLOROP ,
7595 WINED3DTSS_RESULTARG ,
7596 WINED3DTSS_TEXCOORDINDEX ,
7597 WINED3DTSS_TEXTURETRANSFORMFLAGS
7600 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7601 WINED3DSAMP_ADDRESSU ,
7602 WINED3DSAMP_ADDRESSV ,
7603 WINED3DSAMP_ADDRESSW ,
7604 WINED3DSAMP_BORDERCOLOR ,
7605 WINED3DSAMP_MAGFILTER ,
7606 WINED3DSAMP_MINFILTER ,
7607 WINED3DSAMP_MIPFILTER ,
7608 WINED3DSAMP_MIPMAPLODBIAS ,
7609 WINED3DSAMP_MAXMIPLEVEL ,
7610 WINED3DSAMP_MAXANISOTROPY ,
7611 WINED3DSAMP_SRGBTEXTURE ,
7612 WINED3DSAMP_ELEMENTINDEX
7615 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7616 WINED3DRS_AMBIENT ,
7617 WINED3DRS_AMBIENTMATERIALSOURCE ,
7618 WINED3DRS_CLIPPING ,
7619 WINED3DRS_CLIPPLANEENABLE ,
7620 WINED3DRS_COLORVERTEX ,
7621 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7622 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7623 WINED3DRS_FOGDENSITY ,
7624 WINED3DRS_FOGEND ,
7625 WINED3DRS_FOGSTART ,
7626 WINED3DRS_FOGTABLEMODE ,
7627 WINED3DRS_FOGVERTEXMODE ,
7628 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7629 WINED3DRS_LIGHTING ,
7630 WINED3DRS_LOCALVIEWER ,
7631 WINED3DRS_MULTISAMPLEANTIALIAS ,
7632 WINED3DRS_MULTISAMPLEMASK ,
7633 WINED3DRS_NORMALIZENORMALS ,
7634 WINED3DRS_PATCHEDGESTYLE ,
7635 WINED3DRS_POINTSCALE_A ,
7636 WINED3DRS_POINTSCALE_B ,
7637 WINED3DRS_POINTSCALE_C ,
7638 WINED3DRS_POINTSCALEENABLE ,
7639 WINED3DRS_POINTSIZE ,
7640 WINED3DRS_POINTSIZE_MAX ,
7641 WINED3DRS_POINTSIZE_MIN ,
7642 WINED3DRS_POINTSPRITEENABLE ,
7643 WINED3DRS_RANGEFOGENABLE ,
7644 WINED3DRS_SPECULARMATERIALSOURCE ,
7645 WINED3DRS_TWEENFACTOR ,
7646 WINED3DRS_VERTEXBLEND ,
7647 WINED3DRS_CULLMODE ,
7648 WINED3DRS_FOGCOLOR
7651 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7652 WINED3DTSS_TEXCOORDINDEX ,
7653 WINED3DTSS_TEXTURETRANSFORMFLAGS
7656 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7657 WINED3DSAMP_DMAPOFFSET
7660 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7661 DWORD rep = This->StateTable[state].representative;
7662 DWORD idx;
7663 BYTE shift;
7664 UINT i;
7665 WineD3DContext *context;
7667 if(!rep) return;
7668 for(i = 0; i < This->numContexts; i++) {
7669 context = This->contexts[i];
7670 if(isStateDirty(context, rep)) continue;
7672 context->dirtyArray[context->numDirtyEntries++] = rep;
7673 idx = rep >> 5;
7674 shift = rep & 0x1f;
7675 context->isStateDirty[idx] |= (1 << shift);
7679 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7680 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7681 /* The drawable size of a pbuffer render target is the current pbuffer size
7683 *width = dev->pbufferWidth;
7684 *height = dev->pbufferHeight;
7687 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7688 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7690 *width = This->pow2Width;
7691 *height = This->pow2Height;
7694 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7695 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7696 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7697 * current context's drawable, which is the size of the back buffer of the swapchain
7698 * the active context belongs to. The back buffer of the swapchain is stored as the
7699 * surface the context belongs to.
7701 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7702 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;