push 014043c4937c940c54cd1214c96e33a3b3c8cf7d
[wine/hacks.git] / dlls / wined3d / device.c
blob4b3818a100ce89c8b5e5caa8da53f219954f3866
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-2007 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /* helper macros */
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
66 object->ref = 1; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
99 *pp##type = NULL; \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 WineD3DAdapterChangeGLRam(This, _size); \
104 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
105 if (object->resource.heapMemory == NULL && _size != 0) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
108 *pp##type = NULL; \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
112 *pp##type = (IWineD3D##type *) object; \
113 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
114 TRACE("(%p) : Created resource %p\n", This, object); \
117 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
118 _basetexture.levels = Levels; \
119 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
120 _basetexture.LOD = 0; \
121 _basetexture.dirty = TRUE; \
122 _basetexture.is_srgb = FALSE; \
123 _basetexture.srgb_mode_change_count = 0; \
126 /**********************************************************
127 * Global variable / Constants follow
128 **********************************************************/
129 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
139 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
140 if (IsEqualGUID(riid, &IID_IUnknown)
141 || IsEqualGUID(riid, &IID_IWineD3DBase)
142 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
143 IUnknown_AddRef(iface);
144 *ppobj = This;
145 return S_OK;
147 *ppobj = NULL;
148 return E_NOINTERFACE;
151 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 ULONG refCount = InterlockedIncrement(&This->ref);
155 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
156 return refCount;
159 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 ULONG refCount = InterlockedDecrement(&This->ref);
163 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
165 if (!refCount) {
166 if (This->fbo) {
167 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
169 if (This->src_fbo) {
170 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
172 if (This->dst_fbo) {
173 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
176 This->shader_backend->shader_free_private(iface);
178 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
180 /* TODO: Clean up all the surfaces and textures! */
181 /* NOTE: You must release the parent if the object was created via a callback
182 ** ***************************/
184 if (!list_empty(&This->resources)) {
185 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
186 dumpResources(&This->resources);
189 if(This->contexts) ERR("Context array not freed!\n");
190 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
191 This->haveHardwareCursor = FALSE;
193 IWineD3D_Release(This->wineD3D);
194 This->wineD3D = NULL;
195 HeapFree(GetProcessHeap(), 0, This);
196 TRACE("Freed device %p\n", This);
197 This = NULL;
199 return refCount;
202 /**********************************************************
203 * IWineD3DDevice implementation follows
204 **********************************************************/
205 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
207 *pParent = This->parent;
208 IUnknown_AddRef(This->parent);
209 return WINED3D_OK;
212 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
213 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
214 IUnknown *parent) {
215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
216 IWineD3DVertexBufferImpl *object;
217 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
218 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
219 BOOL conv;
221 if(Size == 0) {
222 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
223 *ppVertexBuffer = NULL;
224 return WINED3DERR_INVALIDCALL;
225 } else if(Pool == WINED3DPOOL_SCRATCH) {
226 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
227 * anyway, SCRATCH vertex buffers aren't useable anywhere
229 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
230 *ppVertexBuffer = NULL;
231 return WINED3DERR_INVALIDCALL;
234 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
236 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);
237 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
239 object->fvf = FVF;
241 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
242 * drawStridedFast (half-life 2).
244 * Basically converting the vertices in the buffer is quite expensive, and observations
245 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
246 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
248 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
249 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
250 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
251 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
252 * dx7 apps.
253 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
254 * more. In this call we can convert dx7 buffers too.
256 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
257 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
258 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
259 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
260 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
261 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
262 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
263 } else if(dxVersion <= 7 && conv) {
264 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
265 } else {
266 object->Flags |= VBFLAG_CREATEVBO;
268 return WINED3D_OK;
271 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
272 GLenum error, glUsage;
273 TRACE("Creating VBO for Index Buffer %p\n", object);
275 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
276 * restored on the next draw
278 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
280 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
281 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
282 ENTER_GL();
284 while(glGetError());
286 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
287 error = glGetError();
288 if(error != GL_NO_ERROR || object->vbo == 0) {
289 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
290 goto out;
293 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
294 error = glGetError();
295 if(error != GL_NO_ERROR) {
296 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
297 goto out;
300 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
301 * copy no readback will be needed
303 glUsage = GL_STATIC_DRAW_ARB;
304 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
305 error = glGetError();
306 if(error != GL_NO_ERROR) {
307 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
308 goto out;
310 LEAVE_GL();
311 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
312 return;
314 out:
315 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
316 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
317 LEAVE_GL();
318 object->vbo = 0;
321 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
322 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
323 HANDLE *sharedHandle, IUnknown *parent) {
324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
325 IWineD3DIndexBufferImpl *object;
326 TRACE("(%p) Creating index buffer\n", This);
328 /* Allocate the storage for the device */
329 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
331 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
332 CreateIndexBufferVBO(This, object);
335 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
336 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
337 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
339 return WINED3D_OK;
342 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
345 IWineD3DStateBlockImpl *object;
346 int i, j;
347 HRESULT temp_result;
349 D3DCREATEOBJECTINSTANCE(object, StateBlock)
350 object->blockType = Type;
352 for(i = 0; i < LIGHTMAP_SIZE; i++) {
353 list_init(&object->lightMap[i]);
356 /* Special case - Used during initialization to produce a placeholder stateblock
357 so other functions called can update a state block */
358 if (Type == WINED3DSBT_INIT) {
359 /* Don't bother increasing the reference count otherwise a device will never
360 be freed due to circular dependencies */
361 return WINED3D_OK;
364 temp_result = allocate_shader_constants(object);
365 if (WINED3D_OK != temp_result)
366 return temp_result;
368 /* Otherwise, might as well set the whole state block to the appropriate values */
369 if (This->stateBlock != NULL)
370 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
371 else
372 memset(object->streamFreq, 1, sizeof(object->streamFreq));
374 /* Reset the ref and type after kludging it */
375 object->wineD3DDevice = This;
376 object->ref = 1;
377 object->blockType = Type;
379 TRACE("Updating changed flags appropriate for type %d\n", Type);
381 if (Type == WINED3DSBT_ALL) {
383 TRACE("ALL => Pretend everything has changed\n");
384 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
386 /* Lights are not part of the changed / set structure */
387 for(j = 0; j < LIGHTMAP_SIZE; j++) {
388 struct list *e;
389 LIST_FOR_EACH(e, &object->lightMap[j]) {
390 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
391 light->changed = TRUE;
392 light->enabledChanged = TRUE;
395 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
396 object->contained_render_states[j - 1] = j;
398 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
399 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
400 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
401 object->contained_transform_states[j - 1] = j;
403 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
404 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
405 object->contained_vs_consts_f[j] = j;
407 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
408 for(j = 0; j < MAX_CONST_I; j++) {
409 object->contained_vs_consts_i[j] = j;
411 object->num_contained_vs_consts_i = MAX_CONST_I;
412 for(j = 0; j < MAX_CONST_B; j++) {
413 object->contained_vs_consts_b[j] = j;
415 object->num_contained_vs_consts_b = MAX_CONST_B;
416 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
417 object->contained_ps_consts_f[j] = j;
419 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
420 for(j = 0; j < MAX_CONST_I; j++) {
421 object->contained_ps_consts_i[j] = j;
423 object->num_contained_ps_consts_i = MAX_CONST_I;
424 for(j = 0; j < MAX_CONST_B; j++) {
425 object->contained_ps_consts_b[j] = j;
427 object->num_contained_ps_consts_b = MAX_CONST_B;
428 for(i = 0; i < MAX_TEXTURES; i++) {
429 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
430 object->contained_tss_states[object->num_contained_tss_states].stage = i;
431 object->contained_tss_states[object->num_contained_tss_states].state = j;
432 object->num_contained_tss_states++;
435 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
436 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
437 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
438 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
439 object->num_contained_sampler_states++;
443 for(i = 0; i < MAX_STREAMS; i++) {
444 if(object->streamSource[i]) {
445 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
448 if(object->pIndexData) {
449 IWineD3DIndexBuffer_AddRef(object->pIndexData);
451 if(object->vertexShader) {
452 IWineD3DVertexShader_AddRef(object->vertexShader);
454 if(object->pixelShader) {
455 IWineD3DPixelShader_AddRef(object->pixelShader);
458 } else if (Type == WINED3DSBT_PIXELSTATE) {
460 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
461 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
463 object->changed.pixelShader = TRUE;
465 /* Pixel Shader Constants */
466 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
467 object->contained_ps_consts_f[i] = i;
468 object->changed.pixelShaderConstantsF[i] = TRUE;
470 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
471 for (i = 0; i < MAX_CONST_B; ++i) {
472 object->contained_ps_consts_b[i] = i;
473 object->changed.pixelShaderConstantsB[i] = TRUE;
475 object->num_contained_ps_consts_b = MAX_CONST_B;
476 for (i = 0; i < MAX_CONST_I; ++i) {
477 object->contained_ps_consts_i[i] = i;
478 object->changed.pixelShaderConstantsI[i] = TRUE;
480 object->num_contained_ps_consts_i = MAX_CONST_I;
482 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
483 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
484 object->contained_render_states[i] = SavedPixelStates_R[i];
486 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
487 for (j = 0; j < MAX_TEXTURES; j++) {
488 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
489 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
490 object->contained_tss_states[object->num_contained_tss_states].stage = j;
491 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
492 object->num_contained_tss_states++;
495 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
496 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
497 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
498 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
499 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
500 object->num_contained_sampler_states++;
503 if(object->pixelShader) {
504 IWineD3DPixelShader_AddRef(object->pixelShader);
507 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
508 * on them. This makes releasing the buffer easier
510 for(i = 0; i < MAX_STREAMS; i++) {
511 object->streamSource[i] = NULL;
513 object->pIndexData = NULL;
514 object->vertexShader = NULL;
516 } else if (Type == WINED3DSBT_VERTEXSTATE) {
518 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
519 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
521 object->changed.vertexShader = TRUE;
523 /* Vertex Shader Constants */
524 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
525 object->changed.vertexShaderConstantsF[i] = TRUE;
526 object->contained_vs_consts_f[i] = i;
528 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
529 for (i = 0; i < MAX_CONST_B; ++i) {
530 object->changed.vertexShaderConstantsB[i] = TRUE;
531 object->contained_vs_consts_b[i] = i;
533 object->num_contained_vs_consts_b = MAX_CONST_B;
534 for (i = 0; i < MAX_CONST_I; ++i) {
535 object->changed.vertexShaderConstantsI[i] = TRUE;
536 object->contained_vs_consts_i[i] = i;
538 object->num_contained_vs_consts_i = MAX_CONST_I;
539 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
540 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
541 object->contained_render_states[i] = SavedVertexStates_R[i];
543 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
544 for (j = 0; j < MAX_TEXTURES; j++) {
545 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
546 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
547 object->contained_tss_states[object->num_contained_tss_states].stage = j;
548 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
549 object->num_contained_tss_states++;
552 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
553 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
554 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
555 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
556 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
557 object->num_contained_sampler_states++;
561 for(j = 0; j < LIGHTMAP_SIZE; j++) {
562 struct list *e;
563 LIST_FOR_EACH(e, &object->lightMap[j]) {
564 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
565 light->changed = TRUE;
566 light->enabledChanged = TRUE;
570 for(i = 0; i < MAX_STREAMS; i++) {
571 if(object->streamSource[i]) {
572 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
575 if(object->vertexShader) {
576 IWineD3DVertexShader_AddRef(object->vertexShader);
578 object->pIndexData = NULL;
579 object->pixelShader = NULL;
580 } else {
581 FIXME("Unrecognized state block type %d\n", Type);
584 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
585 return WINED3D_OK;
588 /* ************************************
589 MSDN:
590 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
592 Discard
593 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
595 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.
597 ******************************** */
599 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) {
600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
601 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
602 unsigned int Size = 1;
603 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
604 TRACE("(%p) Create surface\n",This);
606 /** FIXME: Check ranges on the inputs are valid
607 * MSDN
608 * MultisampleQuality
609 * [in] Quality level. The valid range is between zero and one less than the level
610 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
611 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
612 * values of paired render targets, depth stencil surfaces, and the MultiSample type
613 * must all match.
614 *******************************/
618 * TODO: Discard MSDN
619 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
621 * If this flag is set, the contents of the depth stencil buffer will be
622 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
623 * with a different depth surface.
625 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
626 ***************************/
628 if(MultisampleQuality > 0) {
629 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
630 MultisampleQuality=0;
633 /** FIXME: Check that the format is supported
634 * by the device.
635 *******************************/
637 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
638 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
639 * space!
640 *********************************/
641 if (WINED3DFMT_UNKNOWN == Format) {
642 Size = 0;
643 } else if (Format == WINED3DFMT_DXT1) {
644 /* DXT1 is half byte per pixel */
645 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
647 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
648 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
649 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
650 } else {
651 /* The pitch is a multiple of 4 bytes */
652 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
653 Size *= Height;
656 /** Create and initialise the surface resource **/
657 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
658 /* "Standalone" surface */
659 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
661 object->currentDesc.Width = Width;
662 object->currentDesc.Height = Height;
663 object->currentDesc.MultiSampleType = MultiSample;
664 object->currentDesc.MultiSampleQuality = MultisampleQuality;
665 object->glDescription.level = Level;
667 /* Flags */
668 object->Flags = 0;
669 object->Flags |= Discard ? SFLAG_DISCARD : 0;
670 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
671 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
674 if (WINED3DFMT_UNKNOWN != Format) {
675 object->bytesPerPixel = tableEntry->bpp;
676 } else {
677 object->bytesPerPixel = 0;
680 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
682 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
684 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
685 * this function is too deep to need to care about things like this.
686 * Levels need to be checked too, and possibly Type since they all affect what can be done.
687 * ****************************************/
688 switch(Pool) {
689 case WINED3DPOOL_SCRATCH:
690 if(!Lockable)
691 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
692 "which are mutually exclusive, setting lockable to TRUE\n");
693 Lockable = TRUE;
694 break;
695 case WINED3DPOOL_SYSTEMMEM:
696 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
697 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
698 case WINED3DPOOL_MANAGED:
699 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
700 "Usage of DYNAMIC which are mutually exclusive, not doing "
701 "anything just telling you.\n");
702 break;
703 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
704 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
705 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
706 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
707 break;
708 default:
709 FIXME("(%p) Unknown pool %d\n", This, Pool);
710 break;
713 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
714 FIXME("Trying to create a render target that isn't in the default pool\n");
717 /* mark the texture as dirty so that it gets loaded first time around*/
718 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
719 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
720 This, Width, Height, Format, debug_d3dformat(Format),
721 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
723 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
724 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
725 This->ddraw_primary = (IWineD3DSurface *) object;
727 /* Look at the implementation and set the correct Vtable */
728 switch(Impl) {
729 case SURFACE_OPENGL:
730 /* Check if a 3D adapter is available when creating gl surfaces */
731 if(!This->adapter) {
732 ERR("OpenGL surfaces are not available without opengl\n");
733 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
734 HeapFree(GetProcessHeap(), 0, object);
735 return WINED3DERR_NOTAVAILABLE;
737 break;
739 case SURFACE_GDI:
740 object->lpVtbl = &IWineGDISurface_Vtbl;
741 break;
743 default:
744 /* To be sure to catch this */
745 ERR("Unknown requested surface implementation %d!\n", Impl);
746 IWineD3DSurface_Release((IWineD3DSurface *) object);
747 return WINED3DERR_INVALIDCALL;
750 list_init(&object->renderbuffers);
752 /* Call the private setup routine */
753 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
757 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
758 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
759 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
760 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
763 IWineD3DTextureImpl *object;
764 unsigned int i;
765 UINT tmpW;
766 UINT tmpH;
767 HRESULT hr;
768 unsigned int pow2Width;
769 unsigned int pow2Height;
770 const GlPixelFormatDesc *glDesc;
771 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
774 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
775 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
776 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
778 /* TODO: It should only be possible to create textures for formats
779 that are reported as supported */
780 if (WINED3DFMT_UNKNOWN >= Format) {
781 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
782 return WINED3DERR_INVALIDCALL;
785 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
786 D3DINITIALIZEBASETEXTURE(object->baseTexture);
787 object->width = Width;
788 object->height = Height;
790 /** Non-power2 support **/
791 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
792 pow2Width = Width;
793 pow2Height = Height;
794 } else {
795 /* Find the nearest pow2 match */
796 pow2Width = pow2Height = 1;
797 while (pow2Width < Width) pow2Width <<= 1;
798 while (pow2Height < Height) pow2Height <<= 1;
800 if(pow2Width != Width || pow2Height != Height) {
801 if(Levels > 1) {
802 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
803 HeapFree(GetProcessHeap(), 0, object);
804 *ppTexture = NULL;
805 return WINED3DERR_INVALIDCALL;
806 } else {
807 Levels = 1;
812 /** FIXME: add support for real non-power-two if it's provided by the video card **/
813 /* Precalculated scaling for 'faked' non power of two texture coords.
814 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
815 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
816 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
818 if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
819 (Width != pow2Width || Height != pow2Height) &&
820 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
822 object->baseTexture.pow2Matrix[0] = (float)Width;
823 object->baseTexture.pow2Matrix[5] = (float)Height;
824 object->baseTexture.pow2Matrix[10] = 1.0;
825 object->baseTexture.pow2Matrix[15] = 1.0;
826 object->target = GL_TEXTURE_RECTANGLE_ARB;
827 } else {
828 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
829 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
830 object->baseTexture.pow2Matrix[10] = 1.0;
831 object->baseTexture.pow2Matrix[15] = 1.0;
832 object->target = GL_TEXTURE_2D;
834 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
836 /* Calculate levels for mip mapping */
837 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
838 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
839 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
840 return WINED3DERR_INVALIDCALL;
842 if(Levels > 1) {
843 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
844 return WINED3DERR_INVALIDCALL;
846 object->baseTexture.levels = 1;
847 } else if (Levels == 0) {
848 TRACE("calculating levels %d\n", object->baseTexture.levels);
849 object->baseTexture.levels++;
850 tmpW = Width;
851 tmpH = Height;
852 while (tmpW > 1 || tmpH > 1) {
853 tmpW = max(1, tmpW >> 1);
854 tmpH = max(1, tmpH >> 1);
855 object->baseTexture.levels++;
857 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
860 /* Generate all the surfaces */
861 tmpW = Width;
862 tmpH = Height;
863 for (i = 0; i < object->baseTexture.levels; i++)
865 /* use the callback to create the texture surface */
866 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
867 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
868 FIXME("Failed to create surface %p\n", object);
869 /* clean up */
870 object->surfaces[i] = NULL;
871 IWineD3DTexture_Release((IWineD3DTexture *)object);
873 *ppTexture = NULL;
874 return hr;
877 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
878 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
879 /* calculate the next mipmap level */
880 tmpW = max(1, tmpW >> 1);
881 tmpH = max(1, tmpH >> 1);
883 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
885 TRACE("(%p) : Created texture %p\n", This, object);
886 return WINED3D_OK;
889 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
890 UINT Width, UINT Height, UINT Depth,
891 UINT Levels, DWORD Usage,
892 WINED3DFORMAT Format, WINED3DPOOL Pool,
893 IWineD3DVolumeTexture **ppVolumeTexture,
894 HANDLE *pSharedHandle, IUnknown *parent,
895 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
898 IWineD3DVolumeTextureImpl *object;
899 unsigned int i;
900 UINT tmpW;
901 UINT tmpH;
902 UINT tmpD;
903 const GlPixelFormatDesc *glDesc;
905 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
907 /* TODO: It should only be possible to create textures for formats
908 that are reported as supported */
909 if (WINED3DFMT_UNKNOWN >= Format) {
910 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
911 return WINED3DERR_INVALIDCALL;
913 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
914 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
915 return WINED3DERR_INVALIDCALL;
918 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
919 D3DINITIALIZEBASETEXTURE(object->baseTexture);
921 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
922 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
924 object->width = Width;
925 object->height = Height;
926 object->depth = Depth;
928 /* Is NP2 support for volumes needed? */
929 object->baseTexture.pow2Matrix[ 0] = 1.0;
930 object->baseTexture.pow2Matrix[ 5] = 1.0;
931 object->baseTexture.pow2Matrix[10] = 1.0;
932 object->baseTexture.pow2Matrix[15] = 1.0;
934 /* Calculate levels for mip mapping */
935 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
936 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
937 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
938 return WINED3DERR_INVALIDCALL;
940 if(Levels > 1) {
941 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
942 return WINED3DERR_INVALIDCALL;
944 Levels = 1;
945 } else if (Levels == 0) {
946 object->baseTexture.levels++;
947 tmpW = Width;
948 tmpH = Height;
949 tmpD = Depth;
950 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
951 tmpW = max(1, tmpW >> 1);
952 tmpH = max(1, tmpH >> 1);
953 tmpD = max(1, tmpD >> 1);
954 object->baseTexture.levels++;
956 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
959 /* Generate all the surfaces */
960 tmpW = Width;
961 tmpH = Height;
962 tmpD = Depth;
964 for (i = 0; i < object->baseTexture.levels; i++)
966 HRESULT hr;
967 /* Create the volume */
968 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
969 &object->volumes[i], pSharedHandle);
971 if(FAILED(hr)) {
972 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
973 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
974 *ppVolumeTexture = NULL;
975 return hr;
978 /* Set its container to this object */
979 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
981 /* calculate the next mipmap level */
982 tmpW = max(1, tmpW >> 1);
983 tmpH = max(1, tmpH >> 1);
984 tmpD = max(1, tmpD >> 1);
986 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
988 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
989 TRACE("(%p) : Created volume texture %p\n", This, object);
990 return WINED3D_OK;
993 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
994 UINT Width, UINT Height, UINT Depth,
995 DWORD Usage,
996 WINED3DFORMAT Format, WINED3DPOOL Pool,
997 IWineD3DVolume** ppVolume,
998 HANDLE* pSharedHandle, IUnknown *parent) {
1000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1001 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1002 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1004 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1005 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1006 return WINED3DERR_INVALIDCALL;
1009 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1011 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1012 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1014 object->currentDesc.Width = Width;
1015 object->currentDesc.Height = Height;
1016 object->currentDesc.Depth = Depth;
1017 object->bytesPerPixel = formatDesc->bpp;
1019 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1020 object->lockable = TRUE;
1021 object->locked = FALSE;
1022 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1023 object->dirty = TRUE;
1025 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1028 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1029 UINT Levels, DWORD Usage,
1030 WINED3DFORMAT Format, WINED3DPOOL Pool,
1031 IWineD3DCubeTexture **ppCubeTexture,
1032 HANDLE *pSharedHandle, IUnknown *parent,
1033 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1036 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1037 unsigned int i, j;
1038 UINT tmpW;
1039 HRESULT hr;
1040 unsigned int pow2EdgeLength = EdgeLength;
1041 const GlPixelFormatDesc *glDesc;
1042 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1044 /* TODO: It should only be possible to create textures for formats
1045 that are reported as supported */
1046 if (WINED3DFMT_UNKNOWN >= Format) {
1047 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1048 return WINED3DERR_INVALIDCALL;
1051 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1052 WARN("(%p) : Tried to create not supported cube texture\n", This);
1053 return WINED3DERR_INVALIDCALL;
1056 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1057 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1059 TRACE("(%p) Create Cube Texture\n", This);
1061 /** Non-power2 support **/
1063 /* Find the nearest pow2 match */
1064 pow2EdgeLength = 1;
1065 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1067 object->edgeLength = EdgeLength;
1068 /* TODO: support for native non-power 2 */
1069 /* Precalculated scaling for 'faked' non power of two texture coords */
1070 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1071 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1072 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1073 object->baseTexture.pow2Matrix[15] = 1.0;
1075 /* Calculate levels for mip mapping */
1076 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1077 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1078 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1079 HeapFree(GetProcessHeap(), 0, object);
1080 *ppCubeTexture = NULL;
1082 return WINED3DERR_INVALIDCALL;
1084 if(Levels > 1) {
1085 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1086 HeapFree(GetProcessHeap(), 0, object);
1087 *ppCubeTexture = NULL;
1089 return WINED3DERR_INVALIDCALL;
1091 Levels = 1;
1092 } else if (Levels == 0) {
1093 object->baseTexture.levels++;
1094 tmpW = EdgeLength;
1095 while (tmpW > 1) {
1096 tmpW = max(1, tmpW >> 1);
1097 object->baseTexture.levels++;
1099 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1102 /* Generate all the surfaces */
1103 tmpW = EdgeLength;
1104 for (i = 0; i < object->baseTexture.levels; i++) {
1106 /* Create the 6 faces */
1107 for (j = 0; j < 6; j++) {
1109 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1110 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1112 if(hr!= WINED3D_OK) {
1113 /* clean up */
1114 int k;
1115 int l;
1116 for (l = 0; l < j; l++) {
1117 IWineD3DSurface_Release(object->surfaces[l][i]);
1119 for (k = 0; k < i; k++) {
1120 for (l = 0; l < 6; l++) {
1121 IWineD3DSurface_Release(object->surfaces[l][k]);
1125 FIXME("(%p) Failed to create surface\n",object);
1126 HeapFree(GetProcessHeap(),0,object);
1127 *ppCubeTexture = NULL;
1128 return hr;
1130 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1131 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1133 tmpW = max(1, tmpW >> 1);
1135 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1137 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1138 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1139 return WINED3D_OK;
1142 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1144 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1145 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1147 /* Just a check to see if we support this type of query */
1148 switch(Type) {
1149 case WINED3DQUERYTYPE_OCCLUSION:
1150 TRACE("(%p) occlusion query\n", This);
1151 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1152 hr = WINED3D_OK;
1153 else
1154 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1155 break;
1157 case WINED3DQUERYTYPE_EVENT:
1158 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1159 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1160 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1162 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1164 hr = WINED3D_OK;
1165 break;
1167 case WINED3DQUERYTYPE_VCACHE:
1168 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1169 case WINED3DQUERYTYPE_VERTEXSTATS:
1170 case WINED3DQUERYTYPE_TIMESTAMP:
1171 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1172 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1173 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1174 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1175 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1176 case WINED3DQUERYTYPE_PIXELTIMINGS:
1177 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1178 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1179 default:
1180 FIXME("(%p) Unhandled query type %d\n", This, Type);
1182 if(NULL == ppQuery || hr != WINED3D_OK) {
1183 return hr;
1186 D3DCREATEOBJECTINSTANCE(object, Query)
1187 object->type = Type;
1188 object->state = QUERY_CREATED;
1189 /* allocated the 'extended' data based on the type of query requested */
1190 switch(Type){
1191 case WINED3DQUERYTYPE_OCCLUSION:
1192 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1193 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1195 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1196 TRACE("(%p) Allocating data for an occlusion query\n", This);
1197 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1198 break;
1200 case WINED3DQUERYTYPE_EVENT:
1201 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1202 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1204 if(GL_SUPPORT(APPLE_FENCE)) {
1205 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1206 checkGLcall("glGenFencesAPPLE");
1207 } else if(GL_SUPPORT(NV_FENCE)) {
1208 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1209 checkGLcall("glGenFencesNV");
1211 break;
1213 case WINED3DQUERYTYPE_VCACHE:
1214 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1215 case WINED3DQUERYTYPE_VERTEXSTATS:
1216 case WINED3DQUERYTYPE_TIMESTAMP:
1217 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1218 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1219 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1220 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1221 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1222 case WINED3DQUERYTYPE_PIXELTIMINGS:
1223 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1224 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1225 default:
1226 object->extendedData = 0;
1227 FIXME("(%p) Unhandled query type %d\n",This , Type);
1229 TRACE("(%p) : Created Query %p\n", This, object);
1230 return WINED3D_OK;
1233 /*****************************************************************************
1234 * IWineD3DDeviceImpl_SetupFullscreenWindow
1236 * Helper function that modifies a HWND's Style and ExStyle for proper
1237 * fullscreen use.
1239 * Params:
1240 * iface: Pointer to the IWineD3DDevice interface
1241 * window: Window to setup
1243 *****************************************************************************/
1244 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1247 LONG style, exStyle;
1248 /* Don't do anything if an original style is stored.
1249 * That shouldn't happen
1251 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1252 if (This->style || This->exStyle) {
1253 ERR("(%p): Want to change the window parameters of HWND %p, but "
1254 "another style is stored for restoration afterwards\n", This, window);
1257 /* Get the parameters and save them */
1258 style = GetWindowLongW(window, GWL_STYLE);
1259 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1260 This->style = style;
1261 This->exStyle = exStyle;
1263 /* Filter out window decorations */
1264 style &= ~WS_CAPTION;
1265 style &= ~WS_THICKFRAME;
1266 exStyle &= ~WS_EX_WINDOWEDGE;
1267 exStyle &= ~WS_EX_CLIENTEDGE;
1269 /* Make sure the window is managed, otherwise we won't get keyboard input */
1270 style |= WS_POPUP | WS_SYSMENU;
1272 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1273 This->style, This->exStyle, style, exStyle);
1275 SetWindowLongW(window, GWL_STYLE, style);
1276 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1278 /* Inform the window about the update. */
1279 SetWindowPos(window, HWND_TOP, 0, 0,
1280 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1281 ShowWindow(window, SW_NORMAL);
1284 /*****************************************************************************
1285 * IWineD3DDeviceImpl_RestoreWindow
1287 * Helper function that restores a windows' properties when taking it out
1288 * of fullscreen mode
1290 * Params:
1291 * iface: Pointer to the IWineD3DDevice interface
1292 * window: Window to setup
1294 *****************************************************************************/
1295 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1298 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1299 * switch, do nothing
1301 if (!This->style && !This->exStyle) return;
1303 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1304 This, window, This->style, This->exStyle);
1306 SetWindowLongW(window, GWL_STYLE, This->style);
1307 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1309 /* Delete the old values */
1310 This->style = 0;
1311 This->exStyle = 0;
1313 /* Inform the window about the update */
1314 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1315 0, 0, 0, 0, /* Pos, Size, ignored */
1316 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1319 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1320 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1321 IUnknown* parent,
1322 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1323 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1326 HDC hDc;
1327 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1328 HRESULT hr = WINED3D_OK;
1329 IUnknown *bufferParent;
1330 BOOL displaymode_set = FALSE;
1331 WINED3DDISPLAYMODE Mode;
1332 const StaticPixelFormatDesc *formatDesc;
1334 TRACE("(%p) : Created Additional Swap Chain\n", This);
1336 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1337 * does a device hold a reference to a swap chain giving them a lifetime of the device
1338 * or does the swap chain notify the device of its destruction.
1339 *******************************/
1341 /* Check the params */
1342 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1343 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1344 return WINED3DERR_INVALIDCALL;
1345 } else if (pPresentationParameters->BackBufferCount > 1) {
1346 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");
1349 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1351 /*********************
1352 * Lookup the window Handle and the relating X window handle
1353 ********************/
1355 /* Setup hwnd we are using, plus which display this equates to */
1356 object->win_handle = pPresentationParameters->hDeviceWindow;
1357 if (!object->win_handle) {
1358 object->win_handle = This->createParms.hFocusWindow;
1360 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1362 hDc = GetDC(object->win_handle);
1363 TRACE("Using hDc %p\n", hDc);
1365 if (NULL == hDc) {
1366 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1367 return WINED3DERR_NOTAVAILABLE;
1370 /* Get info on the current display setup */
1371 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1372 object->orig_width = Mode.Width;
1373 object->orig_height = Mode.Height;
1374 object->orig_fmt = Mode.Format;
1375 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1377 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1378 * then the corresponding dimension of the client area of the hDeviceWindow
1379 * (or the focus window, if hDeviceWindow is NULL) is taken.
1380 **********************/
1382 if (pPresentationParameters->Windowed &&
1383 ((pPresentationParameters->BackBufferWidth == 0) ||
1384 (pPresentationParameters->BackBufferHeight == 0) ||
1385 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1387 RECT Rect;
1388 GetClientRect(object->win_handle, &Rect);
1390 if (pPresentationParameters->BackBufferWidth == 0) {
1391 pPresentationParameters->BackBufferWidth = Rect.right;
1392 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1394 if (pPresentationParameters->BackBufferHeight == 0) {
1395 pPresentationParameters->BackBufferHeight = Rect.bottom;
1396 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1398 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1399 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1400 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1404 /* Put the correct figures in the presentation parameters */
1405 TRACE("Copying across presentation parameters\n");
1406 object->presentParms = *pPresentationParameters;
1408 TRACE("calling rendertarget CB\n");
1409 hr = D3DCB_CreateRenderTarget(This->parent,
1410 parent,
1411 object->presentParms.BackBufferWidth,
1412 object->presentParms.BackBufferHeight,
1413 object->presentParms.BackBufferFormat,
1414 object->presentParms.MultiSampleType,
1415 object->presentParms.MultiSampleQuality,
1416 TRUE /* Lockable */,
1417 &object->frontBuffer,
1418 NULL /* pShared (always null)*/);
1419 if (object->frontBuffer != NULL) {
1420 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1421 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1422 } else {
1423 ERR("Failed to create the front buffer\n");
1424 goto error;
1427 /*********************
1428 * Windowed / Fullscreen
1429 *******************/
1432 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1433 * so we should really check to see if there is a fullscreen swapchain already
1434 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1435 **************************************/
1437 if (!pPresentationParameters->Windowed) {
1438 WINED3DDISPLAYMODE mode;
1441 /* Change the display settings */
1442 mode.Width = pPresentationParameters->BackBufferWidth;
1443 mode.Height = pPresentationParameters->BackBufferHeight;
1444 mode.Format = pPresentationParameters->BackBufferFormat;
1445 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1447 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1448 displaymode_set = TRUE;
1449 IWineD3DDevice_SetFullscreen(iface, TRUE);
1453 * Create an opengl context for the display visual
1454 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1455 * use different properties after that point in time. FIXME: How to handle when requested format
1456 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1457 * it chooses is identical to the one already being used!
1458 **********************************/
1459 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1461 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1462 if(!object->context)
1463 return E_OUTOFMEMORY;
1464 object->num_contexts = 1;
1466 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1467 if (!object->context[0]) {
1468 ERR("Failed to create a new context\n");
1469 hr = WINED3DERR_NOTAVAILABLE;
1470 goto error;
1471 } else {
1472 TRACE("Context created (HWND=%p, glContext=%p)\n",
1473 object->win_handle, object->context[0]->glCtx);
1476 /*********************
1477 * Create the back, front and stencil buffers
1478 *******************/
1479 if(object->presentParms.BackBufferCount > 0) {
1480 int i;
1482 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1483 if(!object->backBuffer) {
1484 ERR("Out of memory\n");
1485 hr = E_OUTOFMEMORY;
1486 goto error;
1489 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1490 TRACE("calling rendertarget CB\n");
1491 hr = D3DCB_CreateRenderTarget(This->parent,
1492 parent,
1493 object->presentParms.BackBufferWidth,
1494 object->presentParms.BackBufferHeight,
1495 object->presentParms.BackBufferFormat,
1496 object->presentParms.MultiSampleType,
1497 object->presentParms.MultiSampleQuality,
1498 TRUE /* Lockable */,
1499 &object->backBuffer[i],
1500 NULL /* pShared (always null)*/);
1501 if(hr == WINED3D_OK && object->backBuffer[i]) {
1502 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1503 } else {
1504 ERR("Cannot create new back buffer\n");
1505 goto error;
1507 ENTER_GL();
1508 glDrawBuffer(GL_BACK);
1509 checkGLcall("glDrawBuffer(GL_BACK)");
1510 LEAVE_GL();
1512 } else {
1513 object->backBuffer = NULL;
1515 /* Single buffering - draw to front buffer */
1516 ENTER_GL();
1517 glDrawBuffer(GL_FRONT);
1518 checkGLcall("glDrawBuffer(GL_FRONT)");
1519 LEAVE_GL();
1522 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1523 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1524 TRACE("Creating depth stencil buffer\n");
1525 if (This->auto_depth_stencil_buffer == NULL ) {
1526 hr = D3DCB_CreateDepthStencil(This->parent,
1527 parent,
1528 object->presentParms.BackBufferWidth,
1529 object->presentParms.BackBufferHeight,
1530 object->presentParms.AutoDepthStencilFormat,
1531 object->presentParms.MultiSampleType,
1532 object->presentParms.MultiSampleQuality,
1533 FALSE /* FIXME: Discard */,
1534 &This->auto_depth_stencil_buffer,
1535 NULL /* pShared (always null)*/ );
1536 if (This->auto_depth_stencil_buffer != NULL)
1537 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1540 /** TODO: A check on width, height and multisample types
1541 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1542 ****************************/
1543 object->wantsDepthStencilBuffer = TRUE;
1544 } else {
1545 object->wantsDepthStencilBuffer = FALSE;
1548 TRACE("Created swapchain %p\n", object);
1549 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1550 return WINED3D_OK;
1552 error:
1553 if (displaymode_set) {
1554 DEVMODEW devmode;
1555 RECT clip_rc;
1557 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1558 ClipCursor(NULL);
1560 /* Change the display settings */
1561 memset(&devmode, 0, sizeof(devmode));
1562 devmode.dmSize = sizeof(devmode);
1563 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1564 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1565 devmode.dmPelsWidth = object->orig_width;
1566 devmode.dmPelsHeight = object->orig_height;
1567 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1570 if (object->backBuffer) {
1571 int i;
1572 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1573 if(object->backBuffer[i]) {
1574 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1575 IUnknown_Release(bufferParent); /* once for the get parent */
1576 if (IUnknown_Release(bufferParent) > 0) {
1577 FIXME("(%p) Something's still holding the back buffer\n",This);
1581 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1582 object->backBuffer = NULL;
1584 if(object->context[0])
1585 DestroyContext(This, object->context[0]);
1586 if(object->frontBuffer) {
1587 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1588 IUnknown_Release(bufferParent); /* once for the get parent */
1589 if (IUnknown_Release(bufferParent) > 0) {
1590 FIXME("(%p) Something's still holding the front buffer\n",This);
1593 HeapFree(GetProcessHeap(), 0, object);
1594 return hr;
1597 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1598 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1600 TRACE("(%p)\n", This);
1602 return This->NumberOfSwapChains;
1605 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1607 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1609 if(iSwapChain < This->NumberOfSwapChains) {
1610 *pSwapChain = This->swapchains[iSwapChain];
1611 IWineD3DSwapChain_AddRef(*pSwapChain);
1612 TRACE("(%p) returning %p\n", This, *pSwapChain);
1613 return WINED3D_OK;
1614 } else {
1615 TRACE("Swapchain out of range\n");
1616 *pSwapChain = NULL;
1617 return WINED3DERR_INVALIDCALL;
1621 /*****
1622 * Vertex Declaration
1623 *****/
1624 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1625 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1627 IWineD3DVertexDeclarationImpl *object = NULL;
1628 HRESULT hr = WINED3D_OK;
1630 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1631 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1633 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1635 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1636 if(FAILED(hr)) {
1637 *ppVertexDeclaration = NULL;
1638 HeapFree(GetProcessHeap(), 0, object);
1641 return hr;
1644 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1645 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1647 unsigned int idx, idx2;
1648 unsigned int offset;
1649 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1650 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1651 BOOL has_blend_idx = has_blend &&
1652 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1653 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1654 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1655 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1656 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1657 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1658 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1660 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1661 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1663 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1664 WINED3DVERTEXELEMENT *elements = NULL;
1666 unsigned int size;
1667 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1668 if (has_blend_idx) num_blends--;
1670 /* Compute declaration size */
1671 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1672 has_psize + has_diffuse + has_specular + num_textures + 1;
1674 /* convert the declaration */
1675 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1676 if (!elements)
1677 return 0;
1679 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1680 idx = 0;
1681 if (has_pos) {
1682 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1683 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1684 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1686 else {
1687 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1688 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1690 elements[idx].UsageIndex = 0;
1691 idx++;
1693 if (has_blend && (num_blends > 0)) {
1694 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1695 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1696 else
1697 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1698 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1699 elements[idx].UsageIndex = 0;
1700 idx++;
1702 if (has_blend_idx) {
1703 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1704 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1705 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1706 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1707 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1708 else
1709 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1710 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1711 elements[idx].UsageIndex = 0;
1712 idx++;
1714 if (has_normal) {
1715 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1716 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1717 elements[idx].UsageIndex = 0;
1718 idx++;
1720 if (has_psize) {
1721 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1722 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1723 elements[idx].UsageIndex = 0;
1724 idx++;
1726 if (has_diffuse) {
1727 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1728 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1729 elements[idx].UsageIndex = 0;
1730 idx++;
1732 if (has_specular) {
1733 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1734 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1735 elements[idx].UsageIndex = 1;
1736 idx++;
1738 for (idx2 = 0; idx2 < num_textures; idx2++) {
1739 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1740 switch (numcoords) {
1741 case WINED3DFVF_TEXTUREFORMAT1:
1742 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1743 break;
1744 case WINED3DFVF_TEXTUREFORMAT2:
1745 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1746 break;
1747 case WINED3DFVF_TEXTUREFORMAT3:
1748 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1749 break;
1750 case WINED3DFVF_TEXTUREFORMAT4:
1751 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1752 break;
1754 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1755 elements[idx].UsageIndex = idx2;
1756 idx++;
1759 /* Now compute offsets, and initialize the rest of the fields */
1760 for (idx = 0, offset = 0; idx < size-1; idx++) {
1761 elements[idx].Stream = 0;
1762 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1763 elements[idx].Offset = offset;
1764 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1767 *ppVertexElements = elements;
1768 return size;
1771 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1772 WINED3DVERTEXELEMENT* elements = NULL;
1773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1774 unsigned int size;
1775 DWORD hr;
1777 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1778 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1780 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1781 HeapFree(GetProcessHeap(), 0, elements);
1782 if (hr != S_OK) return hr;
1784 return WINED3D_OK;
1787 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1788 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1789 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1790 HRESULT hr = WINED3D_OK;
1791 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1792 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1794 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1796 if (vertex_declaration) {
1797 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1800 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1802 if (WINED3D_OK != hr) {
1803 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1804 IWineD3DVertexShader_Release(*ppVertexShader);
1805 return WINED3DERR_INVALIDCALL;
1807 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1809 return WINED3D_OK;
1812 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1813 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1814 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1815 HRESULT hr = WINED3D_OK;
1817 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1818 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1819 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1820 if (WINED3D_OK == hr) {
1821 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1822 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1823 } else {
1824 WARN("(%p) : Failed to create pixel shader\n", This);
1827 return hr;
1830 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1832 IWineD3DPaletteImpl *object;
1833 HRESULT hr;
1834 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1836 /* Create the new object */
1837 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1838 if(!object) {
1839 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1840 return E_OUTOFMEMORY;
1843 object->lpVtbl = &IWineD3DPalette_Vtbl;
1844 object->ref = 1;
1845 object->Flags = Flags;
1846 object->parent = Parent;
1847 object->wineD3DDevice = This;
1848 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1850 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1852 if(!object->hpal) {
1853 HeapFree( GetProcessHeap(), 0, object);
1854 return E_OUTOFMEMORY;
1857 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1858 if(FAILED(hr)) {
1859 IWineD3DPalette_Release((IWineD3DPalette *) object);
1860 return hr;
1863 *Palette = (IWineD3DPalette *) object;
1865 return WINED3D_OK;
1868 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1869 HBITMAP hbm;
1870 BITMAP bm;
1871 HRESULT hr;
1872 HDC dcb = NULL, dcs = NULL;
1873 WINEDDCOLORKEY colorkey;
1875 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1876 if(hbm)
1878 GetObjectA(hbm, sizeof(BITMAP), &bm);
1879 dcb = CreateCompatibleDC(NULL);
1880 if(!dcb) goto out;
1881 SelectObject(dcb, hbm);
1883 else
1885 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1886 * couldn't be loaded
1888 memset(&bm, 0, sizeof(bm));
1889 bm.bmWidth = 32;
1890 bm.bmHeight = 32;
1893 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1894 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1895 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1896 if(FAILED(hr)) {
1897 ERR("Wine logo requested, but failed to create surface\n");
1898 goto out;
1901 if(dcb) {
1902 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1903 if(FAILED(hr)) goto out;
1904 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1905 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1907 colorkey.dwColorSpaceLowValue = 0;
1908 colorkey.dwColorSpaceHighValue = 0;
1909 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1910 } else {
1911 /* Fill the surface with a white color to show that wined3d is there */
1912 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1915 out:
1916 if(dcb) {
1917 DeleteDC(dcb);
1919 if(hbm) {
1920 DeleteObject(hbm);
1922 return;
1925 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1926 unsigned int i;
1927 /* Under DirectX you can have texture stage operations even if no texture is
1928 bound, whereas opengl will only do texture operations when a valid texture is
1929 bound. We emulate this by creating dummy textures and binding them to each
1930 texture stage, but disable all stages by default. Hence if a stage is enabled
1931 then the default texture will kick in until replaced by a SetTexture call */
1932 ENTER_GL();
1934 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1935 /* The dummy texture does not have client storage backing */
1936 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1937 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1939 for (i = 0; i < GL_LIMITS(textures); i++) {
1940 GLubyte white = 255;
1942 /* Make appropriate texture active */
1943 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1944 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1945 checkGLcall("glActiveTextureARB");
1946 } else if (i > 0) {
1947 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1950 /* Generate an opengl texture name */
1951 glGenTextures(1, &This->dummyTextureName[i]);
1952 checkGLcall("glGenTextures");
1953 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1955 /* Generate a dummy 2d texture (not using 1d because they cause many
1956 * DRI drivers fall back to sw) */
1957 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
1958 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1959 checkGLcall("glBindTexture");
1961 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1962 checkGLcall("glTexImage2D");
1964 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1965 /* Reenable because if supported it is enabled by default */
1966 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1967 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1970 LEAVE_GL();
1973 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1975 IWineD3DSwapChainImpl *swapchain = NULL;
1976 HRESULT hr;
1977 DWORD state;
1979 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1980 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1982 /* TODO: Test if OpenGL is compiled in and loaded */
1984 TRACE("(%p) : Creating stateblock\n", This);
1985 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1986 hr = IWineD3DDevice_CreateStateBlock(iface,
1987 WINED3DSBT_INIT,
1988 (IWineD3DStateBlock **)&This->stateBlock,
1989 NULL);
1990 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1991 WARN("Failed to create stateblock\n");
1992 goto err_out;
1994 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1995 This->updateStateBlock = This->stateBlock;
1996 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1998 hr = allocate_shader_constants(This->updateStateBlock);
1999 if (WINED3D_OK != hr) {
2000 goto err_out;
2003 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2004 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2005 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2007 /* Initialize the texture unit mapping to a 1:1 mapping */
2008 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2009 if (state < GL_LIMITS(fragment_samplers)) {
2010 This->texUnitMap[state] = state;
2011 This->rev_tex_unit_map[state] = state;
2012 } else {
2013 This->texUnitMap[state] = -1;
2014 This->rev_tex_unit_map[state] = -1;
2018 /* Setup the implicit swapchain */
2019 TRACE("Creating implicit swapchain\n");
2020 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2021 if (FAILED(hr) || !swapchain) {
2022 WARN("Failed to create implicit swapchain\n");
2023 goto err_out;
2026 This->NumberOfSwapChains = 1;
2027 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2028 if(!This->swapchains) {
2029 ERR("Out of memory!\n");
2030 goto err_out;
2032 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2034 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2035 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2036 This->render_targets[0] = swapchain->backBuffer[0];
2037 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2039 else {
2040 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2041 This->render_targets[0] = swapchain->frontBuffer;
2042 This->lastActiveRenderTarget = swapchain->frontBuffer;
2044 IWineD3DSurface_AddRef(This->render_targets[0]);
2045 This->activeContext = swapchain->context[0];
2046 This->lastThread = GetCurrentThreadId();
2048 /* Depth Stencil support */
2049 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2050 if (NULL != This->stencilBufferTarget) {
2051 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2054 /* Set up some starting GL setup */
2055 ENTER_GL();
2057 /* Setup all the devices defaults */
2058 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2059 create_dummy_textures(This);
2060 #if 0
2061 IWineD3DImpl_CheckGraphicsMemory();
2062 #endif
2064 { /* Set a default viewport */
2065 WINED3DVIEWPORT vp;
2066 vp.X = 0;
2067 vp.Y = 0;
2068 vp.Width = pPresentationParameters->BackBufferWidth;
2069 vp.Height = pPresentationParameters->BackBufferHeight;
2070 vp.MinZ = 0.0f;
2071 vp.MaxZ = 1.0f;
2072 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2075 /* Initialize the current view state */
2076 This->view_ident = 1;
2077 This->contexts[0]->last_was_rhw = 0;
2078 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2079 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2081 switch(wined3d_settings.offscreen_rendering_mode) {
2082 case ORM_FBO:
2083 case ORM_PBUFFER:
2084 This->offscreenBuffer = GL_BACK;
2085 break;
2087 case ORM_BACKBUFFER:
2089 if(GL_LIMITS(aux_buffers) > 0) {
2090 TRACE("Using auxilliary buffer for offscreen rendering\n");
2091 This->offscreenBuffer = GL_AUX0;
2092 } else {
2093 TRACE("Using back buffer for offscreen rendering\n");
2094 This->offscreenBuffer = GL_BACK;
2099 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2100 LEAVE_GL();
2102 /* Clear the screen */
2103 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2104 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2105 0x00, 1.0, 0);
2107 This->d3d_initialized = TRUE;
2109 if(wined3d_settings.logo) {
2110 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2112 return WINED3D_OK;
2114 err_out:
2115 HeapFree(GetProcessHeap(), 0, This->render_targets);
2116 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2117 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2118 HeapFree(GetProcessHeap(), 0, This->swapchains);
2119 This->NumberOfSwapChains = 0;
2120 if(swapchain) {
2121 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2123 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2124 if(This->stateBlock) {
2125 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2126 This->stateBlock = NULL;
2128 return hr;
2131 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2133 int sampler;
2134 UINT i;
2135 TRACE("(%p)\n", This);
2137 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2139 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2140 * it was created. Thus make sure a context is active for the glDelete* calls
2142 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2144 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2146 TRACE("Deleting high order patches\n");
2147 for(i = 0; i < PATCHMAP_SIZE; i++) {
2148 struct list *e1, *e2;
2149 struct WineD3DRectPatch *patch;
2150 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2151 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2152 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2156 /* Delete the palette conversion shader if it is around */
2157 if(This->paletteConversionShader) {
2158 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2159 This->paletteConversionShader = 0;
2162 /* Delete the pbuffer context if there is any */
2163 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2165 /* Delete the mouse cursor texture */
2166 if(This->cursorTexture) {
2167 ENTER_GL();
2168 glDeleteTextures(1, &This->cursorTexture);
2169 LEAVE_GL();
2170 This->cursorTexture = 0;
2173 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2174 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2176 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2177 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2180 /* Release the update stateblock */
2181 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2182 if(This->updateStateBlock != This->stateBlock)
2183 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2185 This->updateStateBlock = NULL;
2187 { /* because were not doing proper internal refcounts releasing the primary state block
2188 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2189 to set this->stateBlock = NULL; first */
2190 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2191 This->stateBlock = NULL;
2193 /* Release the stateblock */
2194 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2195 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2199 /* Release the buffers (with sanity checks)*/
2200 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2201 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2202 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2203 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2205 This->stencilBufferTarget = NULL;
2207 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2208 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2209 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2211 TRACE("Setting rendertarget to NULL\n");
2212 This->render_targets[0] = NULL;
2214 if (This->auto_depth_stencil_buffer) {
2215 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2216 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2218 This->auto_depth_stencil_buffer = NULL;
2221 for(i=0; i < This->NumberOfSwapChains; i++) {
2222 TRACE("Releasing the implicit swapchain %d\n", i);
2223 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2224 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2228 HeapFree(GetProcessHeap(), 0, This->swapchains);
2229 This->swapchains = NULL;
2230 This->NumberOfSwapChains = 0;
2232 HeapFree(GetProcessHeap(), 0, This->render_targets);
2233 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2234 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2235 This->render_targets = NULL;
2236 This->fbo_color_attachments = NULL;
2237 This->draw_buffers = NULL;
2240 This->d3d_initialized = FALSE;
2241 return WINED3D_OK;
2244 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2246 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2248 /* Setup the window for fullscreen mode */
2249 if(fullscreen && !This->ddraw_fullscreen) {
2250 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2251 } else if(!fullscreen && This->ddraw_fullscreen) {
2252 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2255 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2256 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2257 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2258 * separately.
2260 This->ddraw_fullscreen = fullscreen;
2263 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2264 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2265 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2267 * There is no way to deactivate thread safety once it is enabled.
2269 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2272 /*For now just store the flag(needed in case of ddraw) */
2273 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2275 return;
2278 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2279 DEVMODEW devmode;
2280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2281 LONG ret;
2282 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2283 RECT clip_rc;
2285 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2287 /* Resize the screen even without a window:
2288 * The app could have unset it with SetCooperativeLevel, but not called
2289 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2290 * but we don't have any hwnd
2293 memset(&devmode, 0, sizeof(devmode));
2294 devmode.dmSize = sizeof(devmode);
2295 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2296 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2297 devmode.dmPelsWidth = pMode->Width;
2298 devmode.dmPelsHeight = pMode->Height;
2300 devmode.dmDisplayFrequency = pMode->RefreshRate;
2301 if (pMode->RefreshRate != 0) {
2302 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2305 /* Only change the mode if necessary */
2306 if( (This->ddraw_width == pMode->Width) &&
2307 (This->ddraw_height == pMode->Height) &&
2308 (This->ddraw_format == pMode->Format) &&
2309 (pMode->RefreshRate == 0) ) {
2310 return WINED3D_OK;
2313 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2314 if (ret != DISP_CHANGE_SUCCESSFUL) {
2315 if(devmode.dmDisplayFrequency != 0) {
2316 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2317 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2318 devmode.dmDisplayFrequency = 0;
2319 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2321 if(ret != DISP_CHANGE_SUCCESSFUL) {
2322 return WINED3DERR_NOTAVAILABLE;
2326 /* Store the new values */
2327 This->ddraw_width = pMode->Width;
2328 This->ddraw_height = pMode->Height;
2329 This->ddraw_format = pMode->Format;
2331 /* Only do this with a window of course */
2332 if(This->ddraw_window)
2333 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2335 /* And finally clip mouse to our screen */
2336 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2337 ClipCursor(&clip_rc);
2339 return WINED3D_OK;
2342 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2344 *ppD3D= This->wineD3D;
2345 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2346 IWineD3D_AddRef(*ppD3D);
2347 return WINED3D_OK;
2350 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2353 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2354 (This->adapter->TextureRam/(1024*1024)),
2355 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2356 /* return simulated texture memory left */
2357 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2362 /*****
2363 * Get / Set FVF
2364 *****/
2365 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2368 /* Update the current state block */
2369 This->updateStateBlock->changed.fvf = TRUE;
2371 if(This->updateStateBlock->fvf == fvf) {
2372 TRACE("Application is setting the old fvf over, nothing to do\n");
2373 return WINED3D_OK;
2376 This->updateStateBlock->fvf = fvf;
2377 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2379 return WINED3D_OK;
2383 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2385 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2386 *pfvf = This->stateBlock->fvf;
2387 return WINED3D_OK;
2390 /*****
2391 * Get / Set Stream Source
2392 *****/
2393 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2395 IWineD3DVertexBuffer *oldSrc;
2397 if (StreamNumber >= MAX_STREAMS) {
2398 WARN("Stream out of range %d\n", StreamNumber);
2399 return WINED3DERR_INVALIDCALL;
2400 } else if(OffsetInBytes & 0x3) {
2401 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2402 return WINED3DERR_INVALIDCALL;
2405 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2406 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2408 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2410 if(oldSrc == pStreamData &&
2411 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2412 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2413 TRACE("Application is setting the old values over, nothing to do\n");
2414 return WINED3D_OK;
2417 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2418 if (pStreamData) {
2419 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2420 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2423 /* Handle recording of state blocks */
2424 if (This->isRecordingState) {
2425 TRACE("Recording... not performing anything\n");
2426 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2427 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2428 return WINED3D_OK;
2431 /* Need to do a getParent and pass the references up */
2432 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2433 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2434 so for now, just count internally */
2435 if (pStreamData != NULL) {
2436 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2437 InterlockedIncrement(&vbImpl->bindCount);
2438 IWineD3DVertexBuffer_AddRef(pStreamData);
2440 if (oldSrc != NULL) {
2441 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2442 IWineD3DVertexBuffer_Release(oldSrc);
2445 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2447 return WINED3D_OK;
2450 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2453 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2454 This->stateBlock->streamSource[StreamNumber],
2455 This->stateBlock->streamOffset[StreamNumber],
2456 This->stateBlock->streamStride[StreamNumber]);
2458 if (StreamNumber >= MAX_STREAMS) {
2459 WARN("Stream out of range %d\n", StreamNumber);
2460 return WINED3DERR_INVALIDCALL;
2462 *pStream = This->stateBlock->streamSource[StreamNumber];
2463 *pStride = This->stateBlock->streamStride[StreamNumber];
2464 if (pOffset) {
2465 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2468 if (*pStream != NULL) {
2469 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2471 return WINED3D_OK;
2474 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2476 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2477 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2479 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2480 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2482 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2483 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2485 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2486 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2487 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2490 return WINED3D_OK;
2493 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2494 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2496 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2497 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2499 TRACE("(%p) : returning %d\n", This, *Divider);
2501 return WINED3D_OK;
2504 /*****
2505 * Get / Set & Multiply Transform
2506 *****/
2507 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2510 /* Most of this routine, comments included copied from ddraw tree initially: */
2511 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2513 /* Handle recording of state blocks */
2514 if (This->isRecordingState) {
2515 TRACE("Recording... not performing anything\n");
2516 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2517 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2518 return WINED3D_OK;
2522 * If the new matrix is the same as the current one,
2523 * we cut off any further processing. this seems to be a reasonable
2524 * optimization because as was noticed, some apps (warcraft3 for example)
2525 * tend towards setting the same matrix repeatedly for some reason.
2527 * From here on we assume that the new matrix is different, wherever it matters.
2529 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2530 TRACE("The app is setting the same matrix over again\n");
2531 return WINED3D_OK;
2532 } else {
2533 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2537 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2538 where ViewMat = Camera space, WorldMat = world space.
2540 In OpenGL, camera and world space is combined into GL_MODELVIEW
2541 matrix. The Projection matrix stay projection matrix.
2544 /* Capture the times we can just ignore the change for now */
2545 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2546 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2547 /* Handled by the state manager */
2550 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2551 return WINED3D_OK;
2554 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2555 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2556 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2557 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2558 return WINED3D_OK;
2561 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2562 WINED3DMATRIX *mat = NULL;
2563 WINED3DMATRIX temp;
2565 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2566 * below means it will be recorded in a state block change, but it
2567 * works regardless where it is recorded.
2568 * If this is found to be wrong, change to StateBlock.
2570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2571 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2573 if (State < HIGHEST_TRANSFORMSTATE)
2575 mat = &This->updateStateBlock->transforms[State];
2576 } else {
2577 FIXME("Unhandled transform state!!\n");
2580 multiply_matrix(&temp, mat, pMatrix);
2582 /* Apply change via set transform - will reapply to eg. lights this way */
2583 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2586 /*****
2587 * Get / Set Light
2588 *****/
2589 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2590 you can reference any indexes you want as long as that number max are enabled at any
2591 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2592 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2593 but when recording, just build a chain pretty much of commands to be replayed. */
2595 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2596 float rho;
2597 PLIGHTINFOEL *object = NULL;
2598 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2599 struct list *e;
2601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2602 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2604 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2605 * the gl driver.
2607 if(!pLight) {
2608 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2609 return WINED3DERR_INVALIDCALL;
2612 switch(pLight->Type) {
2613 case WINED3DLIGHT_POINT:
2614 case WINED3DLIGHT_SPOT:
2615 case WINED3DLIGHT_PARALLELPOINT:
2616 case WINED3DLIGHT_GLSPOT:
2617 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2618 * most wanted
2620 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2621 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2622 return WINED3DERR_INVALIDCALL;
2624 break;
2626 case WINED3DLIGHT_DIRECTIONAL:
2627 /* Ignores attenuation */
2628 break;
2630 default:
2631 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2632 return WINED3DERR_INVALIDCALL;
2635 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2636 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2637 if(object->OriginalIndex == Index) break;
2638 object = NULL;
2641 if(!object) {
2642 TRACE("Adding new light\n");
2643 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2644 if(!object) {
2645 ERR("Out of memory error when allocating a light\n");
2646 return E_OUTOFMEMORY;
2648 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2649 object->glIndex = -1;
2650 object->OriginalIndex = Index;
2651 object->changed = TRUE;
2654 /* Initialize the object */
2655 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,
2656 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2657 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2658 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2659 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2660 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2661 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2663 /* Save away the information */
2664 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2666 switch (pLight->Type) {
2667 case WINED3DLIGHT_POINT:
2668 /* Position */
2669 object->lightPosn[0] = pLight->Position.x;
2670 object->lightPosn[1] = pLight->Position.y;
2671 object->lightPosn[2] = pLight->Position.z;
2672 object->lightPosn[3] = 1.0f;
2673 object->cutoff = 180.0f;
2674 /* FIXME: Range */
2675 break;
2677 case WINED3DLIGHT_DIRECTIONAL:
2678 /* Direction */
2679 object->lightPosn[0] = -pLight->Direction.x;
2680 object->lightPosn[1] = -pLight->Direction.y;
2681 object->lightPosn[2] = -pLight->Direction.z;
2682 object->lightPosn[3] = 0.0;
2683 object->exponent = 0.0f;
2684 object->cutoff = 180.0f;
2685 break;
2687 case WINED3DLIGHT_SPOT:
2688 /* Position */
2689 object->lightPosn[0] = pLight->Position.x;
2690 object->lightPosn[1] = pLight->Position.y;
2691 object->lightPosn[2] = pLight->Position.z;
2692 object->lightPosn[3] = 1.0;
2694 /* Direction */
2695 object->lightDirn[0] = pLight->Direction.x;
2696 object->lightDirn[1] = pLight->Direction.y;
2697 object->lightDirn[2] = pLight->Direction.z;
2698 object->lightDirn[3] = 1.0;
2701 * opengl-ish and d3d-ish spot lights use too different models for the
2702 * light "intensity" as a function of the angle towards the main light direction,
2703 * so we only can approximate very roughly.
2704 * however spot lights are rather rarely used in games (if ever used at all).
2705 * furthermore if still used, probably nobody pays attention to such details.
2707 if (pLight->Falloff == 0) {
2708 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2709 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2710 * will always be 1.0 for both of them, and we don't have to care for the
2711 * rest of the rather complex calculation
2713 object->exponent = 0;
2714 } else {
2715 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2716 if (rho < 0.0001) rho = 0.0001f;
2717 object->exponent = -0.3/log(cos(rho/2));
2719 if (object->exponent > 128.0) {
2720 object->exponent = 128.0;
2722 object->cutoff = pLight->Phi*90/M_PI;
2724 /* FIXME: Range */
2725 break;
2727 default:
2728 FIXME("Unrecognized light type %d\n", pLight->Type);
2731 /* Update the live definitions if the light is currently assigned a glIndex */
2732 if (object->glIndex != -1 && !This->isRecordingState) {
2733 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2735 return WINED3D_OK;
2738 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2739 PLIGHTINFOEL *lightInfo = NULL;
2740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2741 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2742 struct list *e;
2743 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2745 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2746 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2747 if(lightInfo->OriginalIndex == Index) break;
2748 lightInfo = NULL;
2751 if (lightInfo == NULL) {
2752 TRACE("Light information requested but light not defined\n");
2753 return WINED3DERR_INVALIDCALL;
2756 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2757 return WINED3D_OK;
2760 /*****
2761 * Get / Set Light Enable
2762 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2763 *****/
2764 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2765 PLIGHTINFOEL *lightInfo = NULL;
2766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2767 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2768 struct list *e;
2769 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2771 /* Tests show true = 128...not clear why */
2772 Enable = Enable? 128: 0;
2774 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2775 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2776 if(lightInfo->OriginalIndex == Index) break;
2777 lightInfo = NULL;
2779 TRACE("Found light: %p\n", lightInfo);
2781 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2782 if (lightInfo == NULL) {
2784 TRACE("Light enabled requested but light not defined, so defining one!\n");
2785 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2787 /* Search for it again! Should be fairly quick as near head of list */
2788 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2789 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2790 if(lightInfo->OriginalIndex == Index) break;
2791 lightInfo = NULL;
2793 if (lightInfo == NULL) {
2794 FIXME("Adding default lights has failed dismally\n");
2795 return WINED3DERR_INVALIDCALL;
2799 lightInfo->enabledChanged = TRUE;
2800 if(!Enable) {
2801 if(lightInfo->glIndex != -1) {
2802 if(!This->isRecordingState) {
2803 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2806 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2807 lightInfo->glIndex = -1;
2808 } else {
2809 TRACE("Light already disabled, nothing to do\n");
2811 lightInfo->enabled = FALSE;
2812 } else {
2813 lightInfo->enabled = TRUE;
2814 if (lightInfo->glIndex != -1) {
2815 /* nop */
2816 TRACE("Nothing to do as light was enabled\n");
2817 } else {
2818 int i;
2819 /* Find a free gl light */
2820 for(i = 0; i < This->maxConcurrentLights; i++) {
2821 if(This->stateBlock->activeLights[i] == NULL) {
2822 This->stateBlock->activeLights[i] = lightInfo;
2823 lightInfo->glIndex = i;
2824 break;
2827 if(lightInfo->glIndex == -1) {
2828 /* Our tests show that Windows returns D3D_OK in this situation, even with
2829 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2830 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2831 * as well for those lights.
2833 * TODO: Test how this affects rendering
2835 FIXME("Too many concurrently active lights\n");
2836 return WINED3D_OK;
2839 /* i == lightInfo->glIndex */
2840 if(!This->isRecordingState) {
2841 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2846 return WINED3D_OK;
2849 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2851 PLIGHTINFOEL *lightInfo = NULL;
2852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2853 struct list *e;
2854 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2855 TRACE("(%p) : for idx(%d)\n", This, Index);
2857 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2858 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2859 if(lightInfo->OriginalIndex == Index) break;
2860 lightInfo = NULL;
2863 if (lightInfo == NULL) {
2864 TRACE("Light enabled state requested but light not defined\n");
2865 return WINED3DERR_INVALIDCALL;
2867 /* true is 128 according to SetLightEnable */
2868 *pEnable = lightInfo->enabled ? 128 : 0;
2869 return WINED3D_OK;
2872 /*****
2873 * Get / Set Clip Planes
2874 *****/
2875 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2877 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2879 /* Validate Index */
2880 if (Index >= GL_LIMITS(clipplanes)) {
2881 TRACE("Application has requested clipplane this device doesn't support\n");
2882 return WINED3DERR_INVALIDCALL;
2885 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2887 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2888 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2889 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2890 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2891 TRACE("Application is setting old values over, nothing to do\n");
2892 return WINED3D_OK;
2895 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2896 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2897 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2898 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2900 /* Handle recording of state blocks */
2901 if (This->isRecordingState) {
2902 TRACE("Recording... not performing anything\n");
2903 return WINED3D_OK;
2906 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2908 return WINED3D_OK;
2911 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2913 TRACE("(%p) : for idx %d\n", This, Index);
2915 /* Validate Index */
2916 if (Index >= GL_LIMITS(clipplanes)) {
2917 TRACE("Application has requested clipplane this device doesn't support\n");
2918 return WINED3DERR_INVALIDCALL;
2921 pPlane[0] = This->stateBlock->clipplane[Index][0];
2922 pPlane[1] = This->stateBlock->clipplane[Index][1];
2923 pPlane[2] = This->stateBlock->clipplane[Index][2];
2924 pPlane[3] = This->stateBlock->clipplane[Index][3];
2925 return WINED3D_OK;
2928 /*****
2929 * Get / Set Clip Plane Status
2930 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2931 *****/
2932 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2934 FIXME("(%p) : stub\n", This);
2935 if (NULL == pClipStatus) {
2936 return WINED3DERR_INVALIDCALL;
2938 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2939 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2940 return WINED3D_OK;
2943 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2945 FIXME("(%p) : stub\n", This);
2946 if (NULL == pClipStatus) {
2947 return WINED3DERR_INVALIDCALL;
2949 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2950 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2951 return WINED3D_OK;
2954 /*****
2955 * Get / Set Material
2956 *****/
2957 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2960 This->updateStateBlock->changed.material = TRUE;
2961 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2963 /* Handle recording of state blocks */
2964 if (This->isRecordingState) {
2965 TRACE("Recording... not performing anything\n");
2966 return WINED3D_OK;
2969 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2970 return WINED3D_OK;
2973 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2975 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2976 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2977 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2978 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2979 pMaterial->Ambient.b, pMaterial->Ambient.a);
2980 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2981 pMaterial->Specular.b, pMaterial->Specular.a);
2982 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2983 pMaterial->Emissive.b, pMaterial->Emissive.a);
2984 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2986 return WINED3D_OK;
2989 /*****
2990 * Get / Set Indices
2991 *****/
2992 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2994 IWineD3DIndexBuffer *oldIdxs;
2996 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2997 oldIdxs = This->updateStateBlock->pIndexData;
2999 This->updateStateBlock->changed.indices = TRUE;
3000 This->updateStateBlock->pIndexData = pIndexData;
3002 /* Handle recording of state blocks */
3003 if (This->isRecordingState) {
3004 TRACE("Recording... not performing anything\n");
3005 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3006 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3007 return WINED3D_OK;
3010 if(oldIdxs != pIndexData) {
3011 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3012 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3013 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3015 return WINED3D_OK;
3018 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3021 *ppIndexData = This->stateBlock->pIndexData;
3023 /* up ref count on ppindexdata */
3024 if (*ppIndexData) {
3025 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3026 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3027 }else{
3028 TRACE("(%p) No index data set\n", This);
3030 TRACE("Returning %p\n", *ppIndexData);
3032 return WINED3D_OK;
3035 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3036 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3038 TRACE("(%p)->(%d)\n", This, BaseIndex);
3040 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3041 TRACE("Application is setting the old value over, nothing to do\n");
3042 return WINED3D_OK;
3045 This->updateStateBlock->baseVertexIndex = BaseIndex;
3047 if (This->isRecordingState) {
3048 TRACE("Recording... not performing anything\n");
3049 return WINED3D_OK;
3051 /* The base vertex index affects the stream sources */
3052 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3053 return WINED3D_OK;
3056 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3058 TRACE("(%p) : base_index %p\n", This, base_index);
3060 *base_index = This->stateBlock->baseVertexIndex;
3062 TRACE("Returning %u\n", *base_index);
3064 return WINED3D_OK;
3067 /*****
3068 * Get / Set Viewports
3069 *****/
3070 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3071 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3073 TRACE("(%p)\n", This);
3074 This->updateStateBlock->changed.viewport = TRUE;
3075 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3077 /* Handle recording of state blocks */
3078 if (This->isRecordingState) {
3079 TRACE("Recording... not performing anything\n");
3080 return WINED3D_OK;
3083 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3084 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3086 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3087 return WINED3D_OK;
3091 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3092 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3093 TRACE("(%p)\n", This);
3094 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3095 return WINED3D_OK;
3098 /*****
3099 * Get / Set Render States
3100 * TODO: Verify against dx9 definitions
3101 *****/
3102 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3105 DWORD oldValue = This->stateBlock->renderState[State];
3107 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3109 This->updateStateBlock->changed.renderState[State] = TRUE;
3110 This->updateStateBlock->renderState[State] = Value;
3112 /* Handle recording of state blocks */
3113 if (This->isRecordingState) {
3114 TRACE("Recording... not performing anything\n");
3115 return WINED3D_OK;
3118 /* Compared here and not before the assignment to allow proper stateblock recording */
3119 if(Value == oldValue) {
3120 TRACE("Application is setting the old value over, nothing to do\n");
3121 } else {
3122 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3125 return WINED3D_OK;
3128 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3130 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3131 *pValue = This->stateBlock->renderState[State];
3132 return WINED3D_OK;
3135 /*****
3136 * Get / Set Sampler States
3137 * TODO: Verify against dx9 definitions
3138 *****/
3140 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3142 DWORD oldValue;
3144 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3145 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3147 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3148 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3151 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3152 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3153 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3156 * SetSampler is designed to allow for more than the standard up to 8 textures
3157 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3158 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3160 * http://developer.nvidia.com/object/General_FAQ.html#t6
3162 * There are two new settings for GForce
3163 * the sampler one:
3164 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3165 * and the texture one:
3166 * GL_MAX_TEXTURE_COORDS_ARB.
3167 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3168 ******************/
3170 oldValue = This->stateBlock->samplerState[Sampler][Type];
3171 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3172 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3174 /* Handle recording of state blocks */
3175 if (This->isRecordingState) {
3176 TRACE("Recording... not performing anything\n");
3177 return WINED3D_OK;
3180 if(oldValue == Value) {
3181 TRACE("Application is setting the old value over, nothing to do\n");
3182 return WINED3D_OK;
3185 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3187 return WINED3D_OK;
3190 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3193 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3194 This, Sampler, debug_d3dsamplerstate(Type), Type);
3196 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3197 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3200 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3201 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3202 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3204 *Value = This->stateBlock->samplerState[Sampler][Type];
3205 TRACE("(%p) : Returning %#x\n", This, *Value);
3207 return WINED3D_OK;
3210 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3213 This->updateStateBlock->changed.scissorRect = TRUE;
3214 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3215 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3216 return WINED3D_OK;
3218 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3220 if(This->isRecordingState) {
3221 TRACE("Recording... not performing anything\n");
3222 return WINED3D_OK;
3225 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3227 return WINED3D_OK;
3230 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3233 *pRect = This->updateStateBlock->scissorRect;
3234 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3235 return WINED3D_OK;
3238 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3240 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3242 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3244 This->updateStateBlock->vertexDecl = pDecl;
3245 This->updateStateBlock->changed.vertexDecl = TRUE;
3247 if (This->isRecordingState) {
3248 TRACE("Recording... not performing anything\n");
3249 return WINED3D_OK;
3250 } else if(pDecl == oldDecl) {
3251 /* Checked after the assignment to allow proper stateblock recording */
3252 TRACE("Application is setting the old declaration over, nothing to do\n");
3253 return WINED3D_OK;
3256 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3257 return WINED3D_OK;
3260 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3263 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3265 *ppDecl = This->stateBlock->vertexDecl;
3266 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3267 return WINED3D_OK;
3270 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3272 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3274 This->updateStateBlock->vertexShader = pShader;
3275 This->updateStateBlock->changed.vertexShader = TRUE;
3277 if (This->isRecordingState) {
3278 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3279 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3280 TRACE("Recording... not performing anything\n");
3281 return WINED3D_OK;
3282 } else if(oldShader == pShader) {
3283 /* Checked here to allow proper stateblock recording */
3284 TRACE("App is setting the old shader over, nothing to do\n");
3285 return WINED3D_OK;
3288 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3289 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3290 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3292 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3294 return WINED3D_OK;
3297 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3300 if (NULL == ppShader) {
3301 return WINED3DERR_INVALIDCALL;
3303 *ppShader = This->stateBlock->vertexShader;
3304 if( NULL != *ppShader)
3305 IWineD3DVertexShader_AddRef(*ppShader);
3307 TRACE("(%p) : returning %p\n", This, *ppShader);
3308 return WINED3D_OK;
3311 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3312 IWineD3DDevice *iface,
3313 UINT start,
3314 CONST BOOL *srcData,
3315 UINT count) {
3317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3318 int i, cnt = min(count, MAX_CONST_B - start);
3320 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3321 iface, srcData, start, count);
3323 if (srcData == NULL || cnt < 0)
3324 return WINED3DERR_INVALIDCALL;
3326 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3327 for (i = 0; i < cnt; i++)
3328 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3330 for (i = start; i < cnt + start; ++i) {
3331 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3334 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3336 return WINED3D_OK;
3339 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3340 IWineD3DDevice *iface,
3341 UINT start,
3342 BOOL *dstData,
3343 UINT count) {
3345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3346 int cnt = min(count, MAX_CONST_B - start);
3348 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3349 iface, dstData, start, count);
3351 if (dstData == NULL || cnt < 0)
3352 return WINED3DERR_INVALIDCALL;
3354 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3355 return WINED3D_OK;
3358 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3359 IWineD3DDevice *iface,
3360 UINT start,
3361 CONST int *srcData,
3362 UINT count) {
3364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3365 int i, cnt = min(count, MAX_CONST_I - start);
3367 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3368 iface, srcData, start, count);
3370 if (srcData == NULL || cnt < 0)
3371 return WINED3DERR_INVALIDCALL;
3373 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3374 for (i = 0; i < cnt; i++)
3375 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3376 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3378 for (i = start; i < cnt + start; ++i) {
3379 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3382 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3384 return WINED3D_OK;
3387 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3388 IWineD3DDevice *iface,
3389 UINT start,
3390 int *dstData,
3391 UINT count) {
3393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3394 int cnt = min(count, MAX_CONST_I - start);
3396 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3397 iface, dstData, start, count);
3399 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3400 return WINED3DERR_INVALIDCALL;
3402 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3403 return WINED3D_OK;
3406 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3407 IWineD3DDevice *iface,
3408 UINT start,
3409 CONST float *srcData,
3410 UINT count) {
3412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3413 int i;
3415 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3416 iface, srcData, start, count);
3418 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3419 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3420 return WINED3DERR_INVALIDCALL;
3422 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3423 if(TRACE_ON(d3d)) {
3424 for (i = 0; i < count; i++)
3425 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3426 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3429 for (i = start; i < count + start; ++i) {
3430 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3431 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3432 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3433 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3434 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3436 ptr->idx[ptr->count++] = i;
3437 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3441 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3443 return WINED3D_OK;
3446 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3447 IWineD3DDevice *iface,
3448 UINT start,
3449 float *dstData,
3450 UINT count) {
3452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3453 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3455 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3456 iface, dstData, start, count);
3458 if (dstData == NULL || cnt < 0)
3459 return WINED3DERR_INVALIDCALL;
3461 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3462 return WINED3D_OK;
3465 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3466 DWORD i;
3467 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3468 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3472 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3473 int i = This->rev_tex_unit_map[unit];
3474 int j = This->texUnitMap[stage];
3476 This->texUnitMap[stage] = unit;
3477 if (i != -1 && i != stage) {
3478 This->texUnitMap[i] = -1;
3481 This->rev_tex_unit_map[unit] = stage;
3482 if (j != -1 && j != unit) {
3483 This->rev_tex_unit_map[j] = -1;
3487 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3488 int i;
3490 for (i = 0; i < MAX_TEXTURES; ++i) {
3491 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3492 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3493 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3494 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3495 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3496 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3497 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3498 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3500 if (color_op == WINED3DTOP_DISABLE) {
3501 /* Not used, and disable higher stages */
3502 while (i < MAX_TEXTURES) {
3503 This->fixed_function_usage_map[i] = FALSE;
3504 ++i;
3506 break;
3509 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3510 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3511 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3512 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3513 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3514 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3515 This->fixed_function_usage_map[i] = TRUE;
3516 } else {
3517 This->fixed_function_usage_map[i] = FALSE;
3520 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3521 This->fixed_function_usage_map[i+1] = TRUE;
3526 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3527 int i, tex;
3529 device_update_fixed_function_usage_map(This);
3531 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3532 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3533 if (!This->fixed_function_usage_map[i]) continue;
3535 if (This->texUnitMap[i] != i) {
3536 device_map_stage(This, i, i);
3537 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3538 markTextureStagesDirty(This, i);
3541 return;
3544 /* Now work out the mapping */
3545 tex = 0;
3546 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3547 if (!This->fixed_function_usage_map[i]) continue;
3549 if (This->texUnitMap[i] != tex) {
3550 device_map_stage(This, i, tex);
3551 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3552 markTextureStagesDirty(This, i);
3555 ++tex;
3559 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3560 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3561 int i;
3563 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3564 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3565 device_map_stage(This, i, i);
3566 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3567 if (i < MAX_TEXTURES) {
3568 markTextureStagesDirty(This, i);
3574 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3575 int current_mapping = This->rev_tex_unit_map[unit];
3577 if (current_mapping == -1) {
3578 /* Not currently used */
3579 return TRUE;
3582 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3583 /* Used by a fragment sampler */
3585 if (!pshader_sampler_tokens) {
3586 /* No pixel shader, check fixed function */
3587 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3590 /* Pixel shader, check the shader's sampler map */
3591 return !pshader_sampler_tokens[current_mapping];
3594 /* Used by a vertex sampler */
3595 return !vshader_sampler_tokens[current_mapping];
3598 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3599 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3600 DWORD *pshader_sampler_tokens = NULL;
3601 int start = GL_LIMITS(combined_samplers) - 1;
3602 int i;
3604 if (ps) {
3605 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3607 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3608 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3609 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3612 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3613 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3614 if (vshader_sampler_tokens[i]) {
3615 if (This->texUnitMap[vsampler_idx] != -1) {
3616 /* Already mapped somewhere */
3617 continue;
3620 while (start >= 0) {
3621 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3622 device_map_stage(This, vsampler_idx, start);
3623 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3625 --start;
3626 break;
3629 --start;
3635 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3636 BOOL vs = use_vs(This);
3637 BOOL ps = use_ps(This);
3639 * Rules are:
3640 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3641 * that would be really messy and require shader recompilation
3642 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3643 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3645 if (ps) {
3646 device_map_psamplers(This);
3647 } else {
3648 device_map_fixed_function_samplers(This);
3651 if (vs) {
3652 device_map_vsamplers(This, ps);
3656 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3658 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3659 This->updateStateBlock->pixelShader = pShader;
3660 This->updateStateBlock->changed.pixelShader = TRUE;
3662 /* Handle recording of state blocks */
3663 if (This->isRecordingState) {
3664 TRACE("Recording... not performing anything\n");
3667 if (This->isRecordingState) {
3668 TRACE("Recording... not performing anything\n");
3669 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3670 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3671 return WINED3D_OK;
3674 if(pShader == oldShader) {
3675 TRACE("App is setting the old pixel shader over, nothing to do\n");
3676 return WINED3D_OK;
3679 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3680 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3682 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3683 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3685 return WINED3D_OK;
3688 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3691 if (NULL == ppShader) {
3692 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3693 return WINED3DERR_INVALIDCALL;
3696 *ppShader = This->stateBlock->pixelShader;
3697 if (NULL != *ppShader) {
3698 IWineD3DPixelShader_AddRef(*ppShader);
3700 TRACE("(%p) : returning %p\n", This, *ppShader);
3701 return WINED3D_OK;
3704 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3705 IWineD3DDevice *iface,
3706 UINT start,
3707 CONST BOOL *srcData,
3708 UINT count) {
3710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3711 int i, cnt = min(count, MAX_CONST_B - start);
3713 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3714 iface, srcData, start, count);
3716 if (srcData == NULL || cnt < 0)
3717 return WINED3DERR_INVALIDCALL;
3719 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3720 for (i = 0; i < cnt; i++)
3721 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3723 for (i = start; i < cnt + start; ++i) {
3724 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3727 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3729 return WINED3D_OK;
3732 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3733 IWineD3DDevice *iface,
3734 UINT start,
3735 BOOL *dstData,
3736 UINT count) {
3738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3739 int cnt = min(count, MAX_CONST_B - start);
3741 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3742 iface, dstData, start, count);
3744 if (dstData == NULL || cnt < 0)
3745 return WINED3DERR_INVALIDCALL;
3747 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3748 return WINED3D_OK;
3751 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3752 IWineD3DDevice *iface,
3753 UINT start,
3754 CONST int *srcData,
3755 UINT count) {
3757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3758 int i, cnt = min(count, MAX_CONST_I - start);
3760 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3761 iface, srcData, start, count);
3763 if (srcData == NULL || cnt < 0)
3764 return WINED3DERR_INVALIDCALL;
3766 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3767 for (i = 0; i < cnt; i++)
3768 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3769 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3771 for (i = start; i < cnt + start; ++i) {
3772 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3775 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3777 return WINED3D_OK;
3780 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3781 IWineD3DDevice *iface,
3782 UINT start,
3783 int *dstData,
3784 UINT count) {
3786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3787 int cnt = min(count, MAX_CONST_I - start);
3789 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3790 iface, dstData, start, count);
3792 if (dstData == NULL || cnt < 0)
3793 return WINED3DERR_INVALIDCALL;
3795 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3796 return WINED3D_OK;
3799 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3800 IWineD3DDevice *iface,
3801 UINT start,
3802 CONST float *srcData,
3803 UINT count) {
3805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3806 int i;
3808 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3809 iface, srcData, start, count);
3811 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3812 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3813 return WINED3DERR_INVALIDCALL;
3815 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3816 if(TRACE_ON(d3d)) {
3817 for (i = 0; i < count; i++)
3818 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3819 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3822 for (i = start; i < count + start; ++i) {
3823 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3824 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3825 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3826 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3827 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3829 ptr->idx[ptr->count++] = i;
3830 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3834 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3836 return WINED3D_OK;
3839 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3840 IWineD3DDevice *iface,
3841 UINT start,
3842 float *dstData,
3843 UINT count) {
3845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3846 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3848 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3849 iface, dstData, start, count);
3851 if (dstData == NULL || cnt < 0)
3852 return WINED3DERR_INVALIDCALL;
3854 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3855 return WINED3D_OK;
3858 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3859 static HRESULT
3860 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3861 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3862 unsigned int i;
3863 DWORD DestFVF = dest->fvf;
3864 WINED3DVIEWPORT vp;
3865 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3866 BOOL doClip;
3867 int numTextures;
3869 if (lpStrideData->u.s.normal.lpData) {
3870 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3873 if (lpStrideData->u.s.position.lpData == NULL) {
3874 ERR("Source has no position mask\n");
3875 return WINED3DERR_INVALIDCALL;
3878 /* We might access VBOs from this code, so hold the lock */
3879 ENTER_GL();
3881 if (dest->resource.allocatedMemory == NULL) {
3882 /* This may happen if we do direct locking into a vbo. Unlikely,
3883 * but theoretically possible(ddraw processvertices test)
3885 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3886 if(!dest->resource.allocatedMemory) {
3887 LEAVE_GL();
3888 ERR("Out of memory\n");
3889 return E_OUTOFMEMORY;
3891 if(dest->vbo) {
3892 void *src;
3893 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3894 checkGLcall("glBindBufferARB");
3895 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3896 if(src) {
3897 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3899 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3900 checkGLcall("glUnmapBufferARB");
3904 /* Get a pointer into the destination vbo(create one if none exists) and
3905 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3907 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3908 dest->Flags |= VBFLAG_CREATEVBO;
3909 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
3912 if(dest->vbo) {
3913 unsigned char extrabytes = 0;
3914 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3915 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3916 * this may write 4 extra bytes beyond the area that should be written
3918 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3919 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3920 if(!dest_conv_addr) {
3921 ERR("Out of memory\n");
3922 /* Continue without storing converted vertices */
3924 dest_conv = dest_conv_addr;
3927 /* Should I clip?
3928 * a) WINED3DRS_CLIPPING is enabled
3929 * b) WINED3DVOP_CLIP is passed
3931 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3932 static BOOL warned = FALSE;
3934 * The clipping code is not quite correct. Some things need
3935 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3936 * so disable clipping for now.
3937 * (The graphics in Half-Life are broken, and my processvertices
3938 * test crashes with IDirect3DDevice3)
3939 doClip = TRUE;
3941 doClip = FALSE;
3942 if(!warned) {
3943 warned = TRUE;
3944 FIXME("Clipping is broken and disabled for now\n");
3946 } else doClip = FALSE;
3947 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3949 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3950 WINED3DTS_VIEW,
3951 &view_mat);
3952 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3953 WINED3DTS_PROJECTION,
3954 &proj_mat);
3955 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3956 WINED3DTS_WORLDMATRIX(0),
3957 &world_mat);
3959 TRACE("View mat:\n");
3960 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);
3961 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);
3962 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);
3963 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);
3965 TRACE("Proj mat:\n");
3966 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);
3967 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);
3968 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);
3969 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);
3971 TRACE("World mat:\n");
3972 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);
3973 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);
3974 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);
3975 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);
3977 /* Get the viewport */
3978 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3979 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3980 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3982 multiply_matrix(&mat,&view_mat,&world_mat);
3983 multiply_matrix(&mat,&proj_mat,&mat);
3985 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3987 for (i = 0; i < dwCount; i+= 1) {
3988 unsigned int tex_index;
3990 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3991 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3992 /* The position first */
3993 float *p =
3994 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3995 float x, y, z, rhw;
3996 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3998 /* Multiplication with world, view and projection matrix */
3999 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);
4000 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);
4001 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);
4002 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);
4004 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4006 /* WARNING: The following things are taken from d3d7 and were not yet checked
4007 * against d3d8 or d3d9!
4010 /* Clipping conditions: From msdn
4012 * A vertex is clipped if it does not match the following requirements
4013 * -rhw < x <= rhw
4014 * -rhw < y <= rhw
4015 * 0 < z <= rhw
4016 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4018 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4019 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4023 if( !doClip ||
4024 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4025 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4026 ( rhw > eps ) ) ) {
4028 /* "Normal" viewport transformation (not clipped)
4029 * 1) The values are divided by rhw
4030 * 2) The y axis is negative, so multiply it with -1
4031 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4032 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4033 * 4) Multiply x with Width/2 and add Width/2
4034 * 5) The same for the height
4035 * 6) Add the viewpoint X and Y to the 2D coordinates and
4036 * The minimum Z value to z
4037 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4039 * Well, basically it's simply a linear transformation into viewport
4040 * coordinates
4043 x /= rhw;
4044 y /= rhw;
4045 z /= rhw;
4047 y *= -1;
4049 x *= vp.Width / 2;
4050 y *= vp.Height / 2;
4051 z *= vp.MaxZ - vp.MinZ;
4053 x += vp.Width / 2 + vp.X;
4054 y += vp.Height / 2 + vp.Y;
4055 z += vp.MinZ;
4057 rhw = 1 / rhw;
4058 } else {
4059 /* That vertex got clipped
4060 * Contrary to OpenGL it is not dropped completely, it just
4061 * undergoes a different calculation.
4063 TRACE("Vertex got clipped\n");
4064 x += rhw;
4065 y += rhw;
4067 x /= 2;
4068 y /= 2;
4070 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4071 * outside of the main vertex buffer memory. That needs some more
4072 * investigation...
4076 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4079 ( (float *) dest_ptr)[0] = x;
4080 ( (float *) dest_ptr)[1] = y;
4081 ( (float *) dest_ptr)[2] = z;
4082 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4084 dest_ptr += 3 * sizeof(float);
4086 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4087 dest_ptr += sizeof(float);
4090 if(dest_conv) {
4091 float w = 1 / rhw;
4092 ( (float *) dest_conv)[0] = x * w;
4093 ( (float *) dest_conv)[1] = y * w;
4094 ( (float *) dest_conv)[2] = z * w;
4095 ( (float *) dest_conv)[3] = w;
4097 dest_conv += 3 * sizeof(float);
4099 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4100 dest_conv += sizeof(float);
4104 if (DestFVF & WINED3DFVF_PSIZE) {
4105 dest_ptr += sizeof(DWORD);
4106 if(dest_conv) dest_conv += sizeof(DWORD);
4108 if (DestFVF & WINED3DFVF_NORMAL) {
4109 float *normal =
4110 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4111 /* AFAIK this should go into the lighting information */
4112 FIXME("Didn't expect the destination to have a normal\n");
4113 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4114 if(dest_conv) {
4115 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4119 if (DestFVF & WINED3DFVF_DIFFUSE) {
4120 DWORD *color_d =
4121 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4122 if(!color_d) {
4123 static BOOL warned = FALSE;
4125 if(!warned) {
4126 ERR("No diffuse color in source, but destination has one\n");
4127 warned = TRUE;
4130 *( (DWORD *) dest_ptr) = 0xffffffff;
4131 dest_ptr += sizeof(DWORD);
4133 if(dest_conv) {
4134 *( (DWORD *) dest_conv) = 0xffffffff;
4135 dest_conv += sizeof(DWORD);
4138 else {
4139 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4140 if(dest_conv) {
4141 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4142 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4143 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4144 dest_conv += sizeof(DWORD);
4149 if (DestFVF & WINED3DFVF_SPECULAR) {
4150 /* What's the color value in the feedback buffer? */
4151 DWORD *color_s =
4152 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4153 if(!color_s) {
4154 static BOOL warned = FALSE;
4156 if(!warned) {
4157 ERR("No specular color in source, but destination has one\n");
4158 warned = TRUE;
4161 *( (DWORD *) dest_ptr) = 0xFF000000;
4162 dest_ptr += sizeof(DWORD);
4164 if(dest_conv) {
4165 *( (DWORD *) dest_conv) = 0xFF000000;
4166 dest_conv += sizeof(DWORD);
4169 else {
4170 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4171 if(dest_conv) {
4172 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4173 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4174 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4175 dest_conv += sizeof(DWORD);
4180 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4181 float *tex_coord =
4182 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4183 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4184 if(!tex_coord) {
4185 ERR("No source texture, but destination requests one\n");
4186 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4187 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4189 else {
4190 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4191 if(dest_conv) {
4192 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4198 if(dest_conv) {
4199 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4200 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4201 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4202 dwCount * get_flexible_vertex_size(DestFVF),
4203 dest_conv_addr));
4204 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4205 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4208 LEAVE_GL();
4210 return WINED3D_OK;
4212 #undef copy_and_next
4214 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4216 WineDirect3DVertexStridedData strided;
4217 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4218 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4220 if(pVertexDecl) {
4221 ERR("Output vertex declaration not implemented yet\n");
4224 /* Need any context to write to the vbo. */
4225 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4227 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4228 * control the streamIsUP flag, thus restore it afterwards.
4230 This->stateBlock->streamIsUP = FALSE;
4231 memset(&strided, 0, sizeof(strided));
4232 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4233 This->stateBlock->streamIsUP = streamWasUP;
4235 if(vbo || SrcStartIndex) {
4236 unsigned int i;
4237 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4238 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4240 * Also get the start index in, but only loop over all elements if there's something to add at all.
4242 #define FIXSRC(type) \
4243 if(strided.u.s.type.VBO) { \
4244 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4245 strided.u.s.type.VBO = 0; \
4246 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4247 ENTER_GL(); \
4248 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4249 vb->vbo = 0; \
4250 LEAVE_GL(); \
4252 if(strided.u.s.type.lpData) { \
4253 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4255 FIXSRC(position);
4256 FIXSRC(blendWeights);
4257 FIXSRC(blendMatrixIndices);
4258 FIXSRC(normal);
4259 FIXSRC(pSize);
4260 FIXSRC(diffuse);
4261 FIXSRC(specular);
4262 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4263 FIXSRC(texCoords[i]);
4265 FIXSRC(position2);
4266 FIXSRC(normal2);
4267 FIXSRC(tangent);
4268 FIXSRC(binormal);
4269 FIXSRC(tessFactor);
4270 FIXSRC(fog);
4271 FIXSRC(depth);
4272 FIXSRC(sample);
4273 #undef FIXSRC
4276 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4279 /*****
4280 * Get / Set Texture Stage States
4281 * TODO: Verify against dx9 definitions
4282 *****/
4283 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4285 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4287 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4289 if (Stage >= MAX_TEXTURES) {
4290 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4291 return WINED3D_OK;
4294 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4295 This->updateStateBlock->textureState[Stage][Type] = Value;
4297 if (This->isRecordingState) {
4298 TRACE("Recording... not performing anything\n");
4299 return WINED3D_OK;
4302 /* Checked after the assignments to allow proper stateblock recording */
4303 if(oldValue == Value) {
4304 TRACE("App is setting the old value over, nothing to do\n");
4305 return WINED3D_OK;
4308 if(Stage > This->stateBlock->lowest_disabled_stage &&
4309 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4310 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4311 * Changes in other states are important on disabled stages too
4313 return WINED3D_OK;
4316 if(Type == WINED3DTSS_COLOROP) {
4317 int i;
4319 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4320 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4321 * they have to be disabled
4323 * The current stage is dirtified below.
4325 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4326 TRACE("Additionally dirtifying stage %d\n", i);
4327 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4329 This->stateBlock->lowest_disabled_stage = Stage;
4330 TRACE("New lowest disabled: %d\n", Stage);
4331 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4332 /* Previously disabled stage enabled. Stages above it may need enabling
4333 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4334 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4336 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4339 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4340 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4341 break;
4343 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4344 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4346 This->stateBlock->lowest_disabled_stage = i;
4347 TRACE("New lowest disabled: %d\n", i);
4349 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4350 /* TODO: Built a stage -> texture unit mapping for register combiners */
4354 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4356 return WINED3D_OK;
4359 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4361 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4362 *pValue = This->updateStateBlock->textureState[Stage][Type];
4363 return WINED3D_OK;
4366 /*****
4367 * Get / Set Texture
4368 *****/
4369 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4370 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4371 IWineD3DBaseTexture *oldTexture;
4373 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4375 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4376 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4379 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4380 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4381 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4384 oldTexture = This->updateStateBlock->textures[Stage];
4386 if(pTexture != NULL) {
4387 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4389 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4390 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4391 return WINED3DERR_INVALIDCALL;
4393 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4396 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4397 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4399 This->updateStateBlock->changed.textures[Stage] = TRUE;
4400 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4401 This->updateStateBlock->textures[Stage] = pTexture;
4403 /* Handle recording of state blocks */
4404 if (This->isRecordingState) {
4405 TRACE("Recording... not performing anything\n");
4406 return WINED3D_OK;
4409 if(oldTexture == pTexture) {
4410 TRACE("App is setting the same texture again, nothing to do\n");
4411 return WINED3D_OK;
4414 /** NOTE: MSDN says that setTexture increases the reference count,
4415 * and that the application must set the texture back to null (or have a leaky application),
4416 * This means we should pass the refcount up to the parent
4417 *******************************/
4418 if (NULL != This->updateStateBlock->textures[Stage]) {
4419 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4420 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4422 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4423 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4424 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4425 * so the COLOROP and ALPHAOP have to be dirtified.
4427 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4428 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4430 if(bindCount == 1) {
4431 new->baseTexture.sampler = Stage;
4433 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4437 if (NULL != oldTexture) {
4438 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4439 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4441 IWineD3DBaseTexture_Release(oldTexture);
4442 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4443 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4444 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4447 if(bindCount && old->baseTexture.sampler == Stage) {
4448 int i;
4449 /* Have to do a search for the other sampler(s) where the texture is bound to
4450 * Shouldn't happen as long as apps bind a texture only to one stage
4452 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4453 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4454 if(This->updateStateBlock->textures[i] == oldTexture) {
4455 old->baseTexture.sampler = i;
4456 break;
4462 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4464 return WINED3D_OK;
4467 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4470 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4472 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4473 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4476 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4477 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4478 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4481 *ppTexture=This->stateBlock->textures[Stage];
4482 if (*ppTexture)
4483 IWineD3DBaseTexture_AddRef(*ppTexture);
4485 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4487 return WINED3D_OK;
4490 /*****
4491 * Get Back Buffer
4492 *****/
4493 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4494 IWineD3DSurface **ppBackBuffer) {
4495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4496 IWineD3DSwapChain *swapChain;
4497 HRESULT hr;
4499 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4501 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4502 if (hr == WINED3D_OK) {
4503 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4504 IWineD3DSwapChain_Release(swapChain);
4505 } else {
4506 *ppBackBuffer = NULL;
4508 return hr;
4511 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4513 WARN("(%p) : stub, calling idirect3d for now\n", This);
4514 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4517 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4519 IWineD3DSwapChain *swapChain;
4520 HRESULT hr;
4522 if(iSwapChain > 0) {
4523 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4524 if (hr == WINED3D_OK) {
4525 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4526 IWineD3DSwapChain_Release(swapChain);
4527 } else {
4528 FIXME("(%p) Error getting display mode\n", This);
4530 } else {
4531 /* Don't read the real display mode,
4532 but return the stored mode instead. X11 can't change the color
4533 depth, and some apps are pretty angry if they SetDisplayMode from
4534 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4536 Also don't relay to the swapchain because with ddraw it's possible
4537 that there isn't a swapchain at all */
4538 pMode->Width = This->ddraw_width;
4539 pMode->Height = This->ddraw_height;
4540 pMode->Format = This->ddraw_format;
4541 pMode->RefreshRate = 0;
4542 hr = WINED3D_OK;
4545 return hr;
4548 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4550 TRACE("(%p)->(%p)\n", This, hWnd);
4552 if(This->ddraw_fullscreen) {
4553 if(This->ddraw_window && This->ddraw_window != hWnd) {
4554 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4556 if(hWnd && This->ddraw_window != hWnd) {
4557 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4561 This->ddraw_window = hWnd;
4562 return WINED3D_OK;
4565 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4566 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4567 TRACE("(%p)->(%p)\n", This, hWnd);
4569 *hWnd = This->ddraw_window;
4570 return WINED3D_OK;
4573 /*****
4574 * Stateblock related functions
4575 *****/
4577 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4579 IWineD3DStateBlockImpl *object;
4580 HRESULT temp_result;
4581 int i;
4583 TRACE("(%p)\n", This);
4585 if (This->isRecordingState) {
4586 return WINED3DERR_INVALIDCALL;
4589 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4590 if (NULL == object ) {
4591 FIXME("(%p)Error allocating memory for stateblock\n", This);
4592 return E_OUTOFMEMORY;
4594 TRACE("(%p) created object %p\n", This, object);
4595 object->wineD3DDevice= This;
4596 /** FIXME: object->parent = parent; **/
4597 object->parent = NULL;
4598 object->blockType = WINED3DSBT_RECORDED;
4599 object->ref = 1;
4600 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4602 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4603 list_init(&object->lightMap[i]);
4606 temp_result = allocate_shader_constants(object);
4607 if (WINED3D_OK != temp_result)
4608 return temp_result;
4610 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4611 This->updateStateBlock = object;
4612 This->isRecordingState = TRUE;
4614 TRACE("(%p) recording stateblock %p\n",This , object);
4615 return WINED3D_OK;
4618 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4620 unsigned int i, j;
4621 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4623 if (!This->isRecordingState) {
4624 FIXME("(%p) not recording! returning error\n", This);
4625 *ppStateBlock = NULL;
4626 return WINED3DERR_INVALIDCALL;
4629 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4630 if(object->changed.renderState[i]) {
4631 object->contained_render_states[object->num_contained_render_states] = i;
4632 object->num_contained_render_states++;
4635 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4636 if(object->changed.transform[i]) {
4637 object->contained_transform_states[object->num_contained_transform_states] = i;
4638 object->num_contained_transform_states++;
4641 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4642 if(object->changed.vertexShaderConstantsF[i]) {
4643 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4644 object->num_contained_vs_consts_f++;
4647 for(i = 0; i < MAX_CONST_I; i++) {
4648 if(object->changed.vertexShaderConstantsI[i]) {
4649 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4650 object->num_contained_vs_consts_i++;
4653 for(i = 0; i < MAX_CONST_B; i++) {
4654 if(object->changed.vertexShaderConstantsB[i]) {
4655 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4656 object->num_contained_vs_consts_b++;
4659 for(i = 0; i < MAX_CONST_I; i++) {
4660 if(object->changed.pixelShaderConstantsI[i]) {
4661 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4662 object->num_contained_ps_consts_i++;
4665 for(i = 0; i < MAX_CONST_B; i++) {
4666 if(object->changed.pixelShaderConstantsB[i]) {
4667 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4668 object->num_contained_ps_consts_b++;
4671 for(i = 0; i < MAX_TEXTURES; i++) {
4672 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4673 if(object->changed.textureState[i][j]) {
4674 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4675 object->contained_tss_states[object->num_contained_tss_states].state = j;
4676 object->num_contained_tss_states++;
4680 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4681 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4682 if(object->changed.samplerState[i][j]) {
4683 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4684 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4685 object->num_contained_sampler_states++;
4690 *ppStateBlock = (IWineD3DStateBlock*) object;
4691 This->isRecordingState = FALSE;
4692 This->updateStateBlock = This->stateBlock;
4693 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4694 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4695 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4696 return WINED3D_OK;
4699 /*****
4700 * Scene related functions
4701 *****/
4702 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4703 /* At the moment we have no need for any functionality at the beginning
4704 of a scene */
4705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4706 TRACE("(%p)\n", This);
4708 if(This->inScene) {
4709 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4710 return WINED3DERR_INVALIDCALL;
4712 This->inScene = TRUE;
4713 return WINED3D_OK;
4716 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4718 TRACE("(%p)\n", This);
4720 if(!This->inScene) {
4721 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4722 return WINED3DERR_INVALIDCALL;
4725 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4726 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4727 ENTER_GL();
4728 glFlush();
4729 checkGLcall("glFlush");
4730 LEAVE_GL();
4732 This->inScene = FALSE;
4733 return WINED3D_OK;
4736 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4737 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4738 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4740 IWineD3DSwapChain *swapChain = NULL;
4741 int i;
4742 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4744 TRACE("(%p) Presenting the frame\n", This);
4746 for(i = 0 ; i < swapchains ; i ++) {
4748 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4749 TRACE("presentinng chain %d, %p\n", i, swapChain);
4750 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4751 IWineD3DSwapChain_Release(swapChain);
4754 return WINED3D_OK;
4757 /* Not called from the VTable (internal subroutine) */
4758 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4759 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4760 float Z, DWORD Stencil) {
4761 GLbitfield glMask = 0;
4762 unsigned int i;
4763 WINED3DRECT curRect;
4764 RECT vp_rect;
4765 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4766 UINT drawable_width, drawable_height;
4767 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4769 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4770 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4771 * for the cleared parts, and the untouched parts.
4773 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4774 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4775 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4776 * checking all this if the dest surface is in the drawable anyway.
4778 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4779 while(1) {
4780 if(vp->X != 0 || vp->Y != 0 ||
4781 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4782 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4783 break;
4785 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4786 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4787 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4788 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4789 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4790 break;
4792 if(Count > 0 && pRects && (
4793 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4794 pRects[0].x2 < target->currentDesc.Width ||
4795 pRects[0].y2 < target->currentDesc.Height)) {
4796 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4797 break;
4799 break;
4803 target->get_drawable_size(target, &drawable_width, &drawable_height);
4805 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4806 ENTER_GL();
4808 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4809 apply_fbo_state((IWineD3DDevice *) This);
4812 /* Only set the values up once, as they are not changing */
4813 if (Flags & WINED3DCLEAR_STENCIL) {
4814 glClearStencil(Stencil);
4815 checkGLcall("glClearStencil");
4816 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4817 glStencilMask(0xFFFFFFFF);
4820 if (Flags & WINED3DCLEAR_ZBUFFER) {
4821 glDepthMask(GL_TRUE);
4822 glClearDepth(Z);
4823 checkGLcall("glClearDepth");
4824 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4825 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4827 if(This->depth_copy_state == WINED3D_DCS_COPY) {
4828 if(vp->X != 0 || vp->Y != 0 ||
4829 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4830 depth_copy((IWineD3DDevice *) This);
4832 else if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4833 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4834 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4835 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4836 depth_copy((IWineD3DDevice *) This);
4838 else if(Count > 0 && pRects && (
4839 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4840 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4841 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4842 depth_copy((IWineD3DDevice *) This);
4845 This->depth_copy_state = WINED3D_DCS_INITIAL;
4848 if (Flags & WINED3DCLEAR_TARGET) {
4849 TRACE("Clearing screen with glClear to color %x\n", Color);
4850 glClearColor(D3DCOLOR_R(Color),
4851 D3DCOLOR_G(Color),
4852 D3DCOLOR_B(Color),
4853 D3DCOLOR_A(Color));
4854 checkGLcall("glClearColor");
4856 /* Clear ALL colors! */
4857 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4858 glMask = glMask | GL_COLOR_BUFFER_BIT;
4861 vp_rect.left = vp->X;
4862 vp_rect.top = vp->Y;
4863 vp_rect.right = vp->X + vp->Width;
4864 vp_rect.bottom = vp->Y + vp->Height;
4865 if (!(Count > 0 && pRects)) {
4866 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4867 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4869 if(This->render_offscreen) {
4870 glScissor(vp_rect.left, vp_rect.top,
4871 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4872 } else {
4873 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4874 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4876 checkGLcall("glScissor");
4877 glClear(glMask);
4878 checkGLcall("glClear");
4879 } else {
4880 /* Now process each rect in turn */
4881 for (i = 0; i < Count; i++) {
4882 /* Note gl uses lower left, width/height */
4883 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
4884 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4885 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4887 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4888 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4889 curRect.x1, (target->currentDesc.Height - curRect.y2),
4890 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4892 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4893 * The rectangle is not cleared, no error is returned, but further rectanlges are
4894 * still cleared if they are valid
4896 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4897 TRACE("Rectangle with negative dimensions, ignoring\n");
4898 continue;
4901 if(This->render_offscreen) {
4902 glScissor(curRect.x1, curRect.y1,
4903 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4904 } else {
4905 glScissor(curRect.x1, drawable_height - curRect.y2,
4906 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4908 checkGLcall("glScissor");
4910 glClear(glMask);
4911 checkGLcall("glClear");
4915 /* Restore the old values (why..?) */
4916 if (Flags & WINED3DCLEAR_STENCIL) {
4917 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4919 if (Flags & WINED3DCLEAR_TARGET) {
4920 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4921 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4922 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4923 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4924 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4926 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4927 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4929 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
4930 /* TODO: Move the fbo logic into ModifyLocation() */
4931 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4932 target->Flags |= SFLAG_INTEXTURE;
4935 LEAVE_GL();
4937 return WINED3D_OK;
4940 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4941 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4943 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4945 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4946 Count, pRects, Flags, Color, Z, Stencil);
4948 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4949 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4950 /* TODO: What about depth stencil buffers without stencil bits? */
4951 return WINED3DERR_INVALIDCALL;
4954 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4957 /*****
4958 * Drawing functions
4959 *****/
4960 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4961 UINT PrimitiveCount) {
4963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4965 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4966 debug_d3dprimitivetype(PrimitiveType),
4967 StartVertex, PrimitiveCount);
4969 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4970 if(This->stateBlock->streamIsUP) {
4971 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4972 This->stateBlock->streamIsUP = FALSE;
4975 if(This->stateBlock->loadBaseVertexIndex != 0) {
4976 This->stateBlock->loadBaseVertexIndex = 0;
4977 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4979 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4980 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4981 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4982 return WINED3D_OK;
4985 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4986 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4987 WINED3DPRIMITIVETYPE PrimitiveType,
4988 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4991 UINT idxStride = 2;
4992 IWineD3DIndexBuffer *pIB;
4993 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4994 GLuint vbo;
4996 pIB = This->stateBlock->pIndexData;
4997 if (!pIB) {
4998 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4999 * without an index buffer set. (The first time at least...)
5000 * D3D8 simply dies, but I doubt it can do much harm to return
5001 * D3DERR_INVALIDCALL there as well. */
5002 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5003 return WINED3DERR_INVALIDCALL;
5006 if(This->stateBlock->streamIsUP) {
5007 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5008 This->stateBlock->streamIsUP = FALSE;
5010 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5012 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5013 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5014 minIndex, NumVertices, startIndex, primCount);
5016 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5017 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5018 idxStride = 2;
5019 } else {
5020 idxStride = 4;
5023 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5024 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5025 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5028 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5029 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5031 return WINED3D_OK;
5034 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5035 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5036 UINT VertexStreamZeroStride) {
5037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5038 IWineD3DVertexBuffer *vb;
5040 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5041 debug_d3dprimitivetype(PrimitiveType),
5042 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5044 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5045 vb = This->stateBlock->streamSource[0];
5046 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5047 if(vb) IWineD3DVertexBuffer_Release(vb);
5048 This->stateBlock->streamOffset[0] = 0;
5049 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5050 This->stateBlock->streamIsUP = TRUE;
5051 This->stateBlock->loadBaseVertexIndex = 0;
5053 /* TODO: Only mark dirty if drawing from a different UP address */
5054 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5056 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5057 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5059 /* MSDN specifies stream zero settings must be set to NULL */
5060 This->stateBlock->streamStride[0] = 0;
5061 This->stateBlock->streamSource[0] = NULL;
5063 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5064 * the new stream sources or use UP drawing again
5066 return WINED3D_OK;
5069 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5070 UINT MinVertexIndex, UINT NumVertices,
5071 UINT PrimitiveCount, CONST void* pIndexData,
5072 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5073 UINT VertexStreamZeroStride) {
5074 int idxStride;
5075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5076 IWineD3DVertexBuffer *vb;
5077 IWineD3DIndexBuffer *ib;
5079 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5080 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5081 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5082 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5084 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5085 idxStride = 2;
5086 } else {
5087 idxStride = 4;
5090 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5091 vb = This->stateBlock->streamSource[0];
5092 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5093 if(vb) IWineD3DVertexBuffer_Release(vb);
5094 This->stateBlock->streamIsUP = TRUE;
5095 This->stateBlock->streamOffset[0] = 0;
5096 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5098 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5099 This->stateBlock->baseVertexIndex = 0;
5100 This->stateBlock->loadBaseVertexIndex = 0;
5101 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5102 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5103 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5105 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5107 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5108 This->stateBlock->streamSource[0] = NULL;
5109 This->stateBlock->streamStride[0] = 0;
5110 ib = This->stateBlock->pIndexData;
5111 if(ib) {
5112 IWineD3DIndexBuffer_Release(ib);
5113 This->stateBlock->pIndexData = NULL;
5115 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5116 * SetStreamSource to specify a vertex buffer
5119 return WINED3D_OK;
5122 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5125 /* Mark the state dirty until we have nicer tracking
5126 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5127 * that value.
5129 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5130 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5131 This->stateBlock->baseVertexIndex = 0;
5132 This->up_strided = DrawPrimStrideData;
5133 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5134 This->up_strided = NULL;
5135 return WINED3D_OK;
5138 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5140 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5142 /* Mark the state dirty until we have nicer tracking
5143 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5144 * that value.
5146 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5147 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5148 This->stateBlock->streamIsUP = TRUE;
5149 This->stateBlock->baseVertexIndex = 0;
5150 This->up_strided = DrawPrimStrideData;
5151 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5152 This->up_strided = NULL;
5153 return WINED3D_OK;
5156 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5157 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5158 * not callable by the app directly no parameter validation checks are needed here.
5160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5161 WINED3DLOCKED_BOX src;
5162 WINED3DLOCKED_BOX dst;
5163 HRESULT hr;
5164 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5166 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5167 * dirtification to improve loading performance.
5169 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5170 if(FAILED(hr)) return hr;
5171 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5172 if(FAILED(hr)) {
5173 IWineD3DVolume_UnlockBox(pSourceVolume);
5174 return hr;
5177 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5179 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5180 if(FAILED(hr)) {
5181 IWineD3DVolume_UnlockBox(pSourceVolume);
5182 } else {
5183 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5185 return hr;
5188 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5189 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5191 HRESULT hr = WINED3D_OK;
5192 WINED3DRESOURCETYPE sourceType;
5193 WINED3DRESOURCETYPE destinationType;
5194 int i ,levels;
5196 /* TODO: think about moving the code into IWineD3DBaseTexture */
5198 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5200 /* verify that the source and destination textures aren't NULL */
5201 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5202 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5203 This, pSourceTexture, pDestinationTexture);
5204 hr = WINED3DERR_INVALIDCALL;
5207 if (pSourceTexture == pDestinationTexture) {
5208 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5209 This, pSourceTexture, pDestinationTexture);
5210 hr = WINED3DERR_INVALIDCALL;
5212 /* Verify that the source and destination textures are the same type */
5213 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5214 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5216 if (sourceType != destinationType) {
5217 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5218 This);
5219 hr = WINED3DERR_INVALIDCALL;
5222 /* check that both textures have the identical numbers of levels */
5223 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5224 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5225 hr = WINED3DERR_INVALIDCALL;
5228 if (WINED3D_OK == hr) {
5230 /* Make sure that the destination texture is loaded */
5231 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5233 /* Update every surface level of the texture */
5234 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5236 switch (sourceType) {
5237 case WINED3DRTYPE_TEXTURE:
5239 IWineD3DSurface *srcSurface;
5240 IWineD3DSurface *destSurface;
5242 for (i = 0 ; i < levels ; ++i) {
5243 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5244 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5245 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5246 IWineD3DSurface_Release(srcSurface);
5247 IWineD3DSurface_Release(destSurface);
5248 if (WINED3D_OK != hr) {
5249 WARN("(%p) : Call to update surface failed\n", This);
5250 return hr;
5254 break;
5255 case WINED3DRTYPE_CUBETEXTURE:
5257 IWineD3DSurface *srcSurface;
5258 IWineD3DSurface *destSurface;
5259 WINED3DCUBEMAP_FACES faceType;
5261 for (i = 0 ; i < levels ; ++i) {
5262 /* Update each cube face */
5263 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5264 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5265 if (WINED3D_OK != hr) {
5266 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5267 } else {
5268 TRACE("Got srcSurface %p\n", srcSurface);
5270 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5271 if (WINED3D_OK != hr) {
5272 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5273 } else {
5274 TRACE("Got desrSurface %p\n", destSurface);
5276 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5277 IWineD3DSurface_Release(srcSurface);
5278 IWineD3DSurface_Release(destSurface);
5279 if (WINED3D_OK != hr) {
5280 WARN("(%p) : Call to update surface failed\n", This);
5281 return hr;
5286 break;
5288 case WINED3DRTYPE_VOLUMETEXTURE:
5290 IWineD3DVolume *srcVolume = NULL;
5291 IWineD3DVolume *destVolume = NULL;
5293 for (i = 0 ; i < levels ; ++i) {
5294 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5295 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5296 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5297 IWineD3DVolume_Release(srcVolume);
5298 IWineD3DVolume_Release(destVolume);
5299 if (WINED3D_OK != hr) {
5300 WARN("(%p) : Call to update volume failed\n", This);
5301 return hr;
5305 break;
5307 default:
5308 FIXME("(%p) : Unsupported source and destination type\n", This);
5309 hr = WINED3DERR_INVALIDCALL;
5313 return hr;
5316 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5317 IWineD3DSwapChain *swapChain;
5318 HRESULT hr;
5319 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5320 if(hr == WINED3D_OK) {
5321 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5322 IWineD3DSwapChain_Release(swapChain);
5324 return hr;
5327 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5329 /* return a sensible default */
5330 *pNumPasses = 1;
5331 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5332 FIXME("(%p) : stub\n", This);
5333 return WINED3D_OK;
5336 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5338 int j;
5339 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5340 if (PaletteNumber >= MAX_PALETTES) {
5341 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5342 return WINED3DERR_INVALIDCALL;
5344 for (j = 0; j < 256; ++j) {
5345 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5346 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5347 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5348 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5350 TRACE("(%p) : returning\n", This);
5351 return WINED3D_OK;
5354 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5356 int j;
5357 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5358 if (PaletteNumber >= MAX_PALETTES) {
5359 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5360 return WINED3DERR_INVALIDCALL;
5362 for (j = 0; j < 256; ++j) {
5363 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5364 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5365 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5366 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5368 TRACE("(%p) : returning\n", This);
5369 return WINED3D_OK;
5372 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5374 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5375 if (PaletteNumber >= MAX_PALETTES) {
5376 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5377 return WINED3DERR_INVALIDCALL;
5379 /*TODO: stateblocks */
5380 This->currentPalette = PaletteNumber;
5381 TRACE("(%p) : returning\n", This);
5382 return WINED3D_OK;
5385 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5387 if (PaletteNumber == NULL) {
5388 WARN("(%p) : returning Invalid Call\n", This);
5389 return WINED3DERR_INVALIDCALL;
5391 /*TODO: stateblocks */
5392 *PaletteNumber = This->currentPalette;
5393 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5394 return WINED3D_OK;
5397 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5399 static BOOL showFixmes = TRUE;
5400 if (showFixmes) {
5401 FIXME("(%p) : stub\n", This);
5402 showFixmes = FALSE;
5405 This->softwareVertexProcessing = bSoftware;
5406 return WINED3D_OK;
5410 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5411 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5412 static BOOL showFixmes = TRUE;
5413 if (showFixmes) {
5414 FIXME("(%p) : stub\n", This);
5415 showFixmes = FALSE;
5417 return This->softwareVertexProcessing;
5421 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5423 IWineD3DSwapChain *swapChain;
5424 HRESULT hr;
5426 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5428 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5429 if(hr == WINED3D_OK){
5430 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5431 IWineD3DSwapChain_Release(swapChain);
5432 }else{
5433 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5435 return hr;
5439 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5441 static BOOL showfixmes = TRUE;
5442 if(nSegments != 0.0f) {
5443 if( showfixmes) {
5444 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5445 showfixmes = FALSE;
5448 return WINED3D_OK;
5451 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5453 static BOOL showfixmes = TRUE;
5454 if( showfixmes) {
5455 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5456 showfixmes = FALSE;
5458 return 0.0f;
5461 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5463 /** TODO: remove casts to IWineD3DSurfaceImpl
5464 * NOTE: move code to surface to accomplish this
5465 ****************************************/
5466 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5467 int srcWidth, srcHeight;
5468 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5469 WINED3DFORMAT destFormat, srcFormat;
5470 UINT destSize;
5471 int srcLeft, destLeft, destTop;
5472 WINED3DPOOL srcPool, destPool;
5473 int offset = 0;
5474 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5475 glDescriptor *glDescription = NULL;
5476 GLenum dummy;
5477 int bpp;
5478 CONVERT_TYPES convert = NO_CONVERSION;
5480 WINED3DSURFACE_DESC winedesc;
5482 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5483 memset(&winedesc, 0, sizeof(winedesc));
5484 winedesc.Width = &srcSurfaceWidth;
5485 winedesc.Height = &srcSurfaceHeight;
5486 winedesc.Pool = &srcPool;
5487 winedesc.Format = &srcFormat;
5489 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5491 winedesc.Width = &destSurfaceWidth;
5492 winedesc.Height = &destSurfaceHeight;
5493 winedesc.Pool = &destPool;
5494 winedesc.Format = &destFormat;
5495 winedesc.Size = &destSize;
5497 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5499 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5500 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5501 return WINED3DERR_INVALIDCALL;
5504 /* This call loads the opengl surface directly, instead of copying the surface to the
5505 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5506 * copy in sysmem and use regular surface loading.
5508 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5509 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5510 if(convert != NO_CONVERSION) {
5511 return IWineD3DSurface_BltFast(pDestinationSurface,
5512 pDestPoint ? pDestPoint->x : 0,
5513 pDestPoint ? pDestPoint->y : 0,
5514 pSourceSurface, (RECT *) pSourceRect, 0);
5517 if (destFormat == WINED3DFMT_UNKNOWN) {
5518 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5519 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5521 /* Get the update surface description */
5522 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5525 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5527 ENTER_GL();
5529 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5530 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5531 checkGLcall("glActiveTextureARB");
5534 /* Make sure the surface is loaded and up to date */
5535 IWineD3DSurface_PreLoad(pDestinationSurface);
5537 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5539 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5540 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5541 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5542 srcLeft = pSourceRect ? pSourceRect->left : 0;
5543 destLeft = pDestPoint ? pDestPoint->x : 0;
5544 destTop = pDestPoint ? pDestPoint->y : 0;
5547 /* This function doesn't support compressed textures
5548 the pitch is just bytesPerPixel * width */
5549 if(srcWidth != srcSurfaceWidth || srcLeft ){
5550 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5551 offset += srcLeft * pSrcSurface->bytesPerPixel;
5552 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5554 /* TODO DXT formats */
5556 if(pSourceRect != NULL && pSourceRect->top != 0){
5557 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5559 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5560 ,This
5561 ,glDescription->level
5562 ,destLeft
5563 ,destTop
5564 ,srcWidth
5565 ,srcHeight
5566 ,glDescription->glFormat
5567 ,glDescription->glType
5568 ,IWineD3DSurface_GetData(pSourceSurface)
5571 /* Sanity check */
5572 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5574 /* need to lock the surface to get the data */
5575 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5578 /* TODO: Cube and volume support */
5579 if(rowoffset != 0){
5580 /* not a whole row so we have to do it a line at a time */
5581 int j;
5583 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5584 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5586 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5588 glTexSubImage2D(glDescription->target
5589 ,glDescription->level
5590 ,destLeft
5592 ,srcWidth
5594 ,glDescription->glFormat
5595 ,glDescription->glType
5596 ,data /* could be quicker using */
5598 data += rowoffset;
5601 } else { /* Full width, so just write out the whole texture */
5603 if (WINED3DFMT_DXT1 == destFormat ||
5604 WINED3DFMT_DXT2 == destFormat ||
5605 WINED3DFMT_DXT3 == destFormat ||
5606 WINED3DFMT_DXT4 == destFormat ||
5607 WINED3DFMT_DXT5 == destFormat) {
5608 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5609 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5610 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5611 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5612 } if (destFormat != srcFormat) {
5613 FIXME("Updating mixed format compressed texture is not curretly support\n");
5614 } else {
5615 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5616 glDescription->level,
5617 glDescription->glFormatInternal,
5618 srcWidth,
5619 srcHeight,
5621 destSize,
5622 IWineD3DSurface_GetData(pSourceSurface));
5624 } else {
5625 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5629 } else {
5630 glTexSubImage2D(glDescription->target
5631 ,glDescription->level
5632 ,destLeft
5633 ,destTop
5634 ,srcWidth
5635 ,srcHeight
5636 ,glDescription->glFormat
5637 ,glDescription->glType
5638 ,IWineD3DSurface_GetData(pSourceSurface)
5642 checkGLcall("glTexSubImage2D");
5644 LEAVE_GL();
5646 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5647 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5649 return WINED3D_OK;
5652 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5654 struct WineD3DRectPatch *patch;
5655 unsigned int i;
5656 struct list *e;
5657 BOOL found;
5658 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5660 if(!(Handle || pRectPatchInfo)) {
5661 /* TODO: Write a test for the return value, thus the FIXME */
5662 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5663 return WINED3DERR_INVALIDCALL;
5666 if(Handle) {
5667 i = PATCHMAP_HASHFUNC(Handle);
5668 found = FALSE;
5669 LIST_FOR_EACH(e, &This->patches[i]) {
5670 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5671 if(patch->Handle == Handle) {
5672 found = TRUE;
5673 break;
5677 if(!found) {
5678 TRACE("Patch does not exist. Creating a new one\n");
5679 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5680 patch->Handle = Handle;
5681 list_add_head(&This->patches[i], &patch->entry);
5682 } else {
5683 TRACE("Found existing patch %p\n", patch);
5685 } else {
5686 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5687 * attributes we have to tesselate, read back, and draw. This needs a patch
5688 * management structure instance. Create one.
5690 * A possible improvement is to check if a vertex shader is used, and if not directly
5691 * draw the patch.
5693 FIXME("Drawing an uncached patch. This is slow\n");
5694 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5697 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5698 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5699 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5700 HRESULT hr;
5701 TRACE("Tesselation density or patch info changed, retesselating\n");
5703 if(pRectPatchInfo) {
5704 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5706 patch->numSegs[0] = pNumSegs[0];
5707 patch->numSegs[1] = pNumSegs[1];
5708 patch->numSegs[2] = pNumSegs[2];
5709 patch->numSegs[3] = pNumSegs[3];
5711 hr = tesselate_rectpatch(This, patch);
5712 if(FAILED(hr)) {
5713 WARN("Patch tesselation failed\n");
5715 /* Do not release the handle to store the params of the patch */
5716 if(!Handle) {
5717 HeapFree(GetProcessHeap(), 0, patch);
5719 return hr;
5723 This->currentPatch = patch;
5724 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5725 This->currentPatch = NULL;
5727 /* Destroy uncached patches */
5728 if(!Handle) {
5729 HeapFree(GetProcessHeap(), 0, patch->mem);
5730 HeapFree(GetProcessHeap(), 0, patch);
5732 return WINED3D_OK;
5735 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5737 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5738 FIXME("(%p) : Stub\n", This);
5739 return WINED3D_OK;
5742 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5744 int i;
5745 struct WineD3DRectPatch *patch;
5746 struct list *e;
5747 TRACE("(%p) Handle(%d)\n", This, Handle);
5749 i = PATCHMAP_HASHFUNC(Handle);
5750 LIST_FOR_EACH(e, &This->patches[i]) {
5751 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5752 if(patch->Handle == Handle) {
5753 TRACE("Deleting patch %p\n", patch);
5754 list_remove(&patch->entry);
5755 HeapFree(GetProcessHeap(), 0, patch->mem);
5756 HeapFree(GetProcessHeap(), 0, patch);
5757 return WINED3D_OK;
5761 /* TODO: Write a test for the return value */
5762 FIXME("Attempt to destroy nonexistent patch\n");
5763 return WINED3DERR_INVALIDCALL;
5766 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5767 HRESULT hr;
5768 IWineD3DSwapChain *swapchain;
5770 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5771 if (SUCCEEDED(hr)) {
5772 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5773 return swapchain;
5776 return NULL;
5779 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5782 if (!*fbo) {
5783 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5784 checkGLcall("glGenFramebuffersEXT()");
5786 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5787 checkGLcall("glBindFramebuffer()");
5790 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5791 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5792 IWineD3DBaseTextureImpl *texture_impl;
5793 GLenum texttarget, target;
5794 GLint old_binding;
5796 texttarget = surface_impl->glDescription.target;
5797 if(texttarget == GL_TEXTURE_2D) {
5798 target = GL_TEXTURE_2D;
5799 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5800 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
5801 target = GL_TEXTURE_RECTANGLE_ARB;
5802 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5803 } else {
5804 target = GL_TEXTURE_CUBE_MAP_ARB;
5805 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5808 IWineD3DSurface_PreLoad(surface);
5810 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5811 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5812 glBindTexture(target, old_binding);
5814 /* Update base texture states array */
5815 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5816 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5817 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5818 if (texture_impl->baseTexture.bindCount) {
5819 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5822 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5825 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5826 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5828 checkGLcall("attach_surface_fbo");
5831 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5833 IWineD3DSwapChain *swapchain;
5835 swapchain = get_swapchain(surface);
5836 if (swapchain) {
5837 GLenum buffer;
5839 TRACE("Surface %p is onscreen\n", surface);
5841 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5842 buffer = surface_get_gl_buffer(surface, swapchain);
5843 glDrawBuffer(buffer);
5844 checkGLcall("glDrawBuffer()");
5845 } else {
5846 TRACE("Surface %p is offscreen\n", surface);
5847 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5848 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5851 if (rect) {
5852 glEnable(GL_SCISSOR_TEST);
5853 if(!swapchain) {
5854 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5855 } else {
5856 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5857 rect->x2 - rect->x1, rect->y2 - rect->y1);
5859 checkGLcall("glScissor");
5860 } else {
5861 glDisable(GL_SCISSOR_TEST);
5863 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5865 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5866 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5868 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5869 glClear(GL_COLOR_BUFFER_BIT);
5870 checkGLcall("glClear");
5872 if (This->render_offscreen) {
5873 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5874 } else {
5875 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5876 checkGLcall("glBindFramebuffer()");
5879 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5880 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5881 glDrawBuffer(GL_BACK);
5882 checkGLcall("glDrawBuffer()");
5886 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5887 unsigned int r, g, b, a;
5888 DWORD ret;
5890 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
5891 destfmt == WINED3DFMT_R8G8B8)
5892 return color;
5894 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5896 a = (color & 0xff000000) >> 24;
5897 r = (color & 0x00ff0000) >> 16;
5898 g = (color & 0x0000ff00) >> 8;
5899 b = (color & 0x000000ff) >> 0;
5901 switch(destfmt)
5903 case WINED3DFMT_R5G6B5:
5904 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5905 r = (r * 32) / 256;
5906 g = (g * 64) / 256;
5907 b = (b * 32) / 256;
5908 ret = r << 11;
5909 ret |= g << 5;
5910 ret |= b;
5911 TRACE("Returning %08x\n", ret);
5912 return ret;
5914 case WINED3DFMT_X1R5G5B5:
5915 case WINED3DFMT_A1R5G5B5:
5916 a = (a * 2) / 256;
5917 r = (r * 32) / 256;
5918 g = (g * 32) / 256;
5919 b = (b * 32) / 256;
5920 ret = a << 15;
5921 ret |= r << 10;
5922 ret |= g << 5;
5923 ret |= b << 0;
5924 TRACE("Returning %08x\n", ret);
5925 return ret;
5927 case WINED3DFMT_A8:
5928 TRACE("Returning %08x\n", a);
5929 return a;
5931 case WINED3DFMT_X4R4G4B4:
5932 case WINED3DFMT_A4R4G4B4:
5933 a = (a * 16) / 256;
5934 r = (r * 16) / 256;
5935 g = (g * 16) / 256;
5936 b = (b * 16) / 256;
5937 ret = a << 12;
5938 ret |= r << 8;
5939 ret |= g << 4;
5940 ret |= b << 0;
5941 TRACE("Returning %08x\n", ret);
5942 return ret;
5944 case WINED3DFMT_R3G3B2:
5945 r = (r * 8) / 256;
5946 g = (g * 8) / 256;
5947 b = (b * 4) / 256;
5948 ret = r << 5;
5949 ret |= g << 2;
5950 ret |= b << 0;
5951 TRACE("Returning %08x\n", ret);
5952 return ret;
5954 case WINED3DFMT_X8B8G8R8:
5955 case WINED3DFMT_A8B8G8R8:
5956 ret = a << 24;
5957 ret |= b << 16;
5958 ret |= g << 8;
5959 ret |= r << 0;
5960 TRACE("Returning %08x\n", ret);
5961 return ret;
5963 case WINED3DFMT_A2R10G10B10:
5964 a = (a * 4) / 256;
5965 r = (r * 1024) / 256;
5966 g = (g * 1024) / 256;
5967 b = (b * 1024) / 256;
5968 ret = a << 30;
5969 ret |= r << 20;
5970 ret |= g << 10;
5971 ret |= b << 0;
5972 TRACE("Returning %08x\n", ret);
5973 return ret;
5975 case WINED3DFMT_A2B10G10R10:
5976 a = (a * 4) / 256;
5977 r = (r * 1024) / 256;
5978 g = (g * 1024) / 256;
5979 b = (b * 1024) / 256;
5980 ret = a << 30;
5981 ret |= b << 20;
5982 ret |= g << 10;
5983 ret |= r << 0;
5984 TRACE("Returning %08x\n", ret);
5985 return ret;
5987 default:
5988 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5989 return 0;
5993 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5995 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5996 WINEDDBLTFX BltFx;
5997 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5999 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6000 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6001 return WINED3DERR_INVALIDCALL;
6004 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6005 color_fill_fbo(iface, pSurface, pRect, color);
6006 return WINED3D_OK;
6007 } else {
6008 /* Just forward this to the DirectDraw blitting engine */
6009 memset(&BltFx, 0, sizeof(BltFx));
6010 BltFx.dwSize = sizeof(BltFx);
6011 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6012 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6016 /* rendertarget and depth stencil functions */
6017 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6020 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6021 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6022 return WINED3DERR_INVALIDCALL;
6025 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6026 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6027 /* Note inc ref on returned surface */
6028 if(*ppRenderTarget != NULL)
6029 IWineD3DSurface_AddRef(*ppRenderTarget);
6030 return WINED3D_OK;
6033 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6035 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6036 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6037 IWineD3DSwapChainImpl *Swapchain;
6038 HRESULT hr;
6040 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6042 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6043 if(hr != WINED3D_OK) {
6044 ERR("Can't get the swapchain\n");
6045 return hr;
6048 /* Make sure to release the swapchain */
6049 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6051 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6052 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6053 return WINED3DERR_INVALIDCALL;
6055 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6056 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6057 return WINED3DERR_INVALIDCALL;
6060 if(Swapchain->frontBuffer != Front) {
6061 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6063 if(Swapchain->frontBuffer)
6064 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6065 Swapchain->frontBuffer = Front;
6067 if(Swapchain->frontBuffer) {
6068 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6072 if(Back && !Swapchain->backBuffer) {
6073 /* We need memory for the back buffer array - only one back buffer this way */
6074 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6075 if(!Swapchain->backBuffer) {
6076 ERR("Out of memory\n");
6077 return E_OUTOFMEMORY;
6081 if(Swapchain->backBuffer[0] != Back) {
6082 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6084 /* What to do about the context here in the case of multithreading? Not sure.
6085 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6087 ENTER_GL();
6088 if(!Swapchain->backBuffer[0]) {
6089 /* GL was told to draw to the front buffer at creation,
6090 * undo that
6092 glDrawBuffer(GL_BACK);
6093 checkGLcall("glDrawBuffer(GL_BACK)");
6094 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6095 Swapchain->presentParms.BackBufferCount = 1;
6096 } else if (!Back) {
6097 /* That makes problems - disable for now */
6098 /* glDrawBuffer(GL_FRONT); */
6099 checkGLcall("glDrawBuffer(GL_FRONT)");
6100 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6101 Swapchain->presentParms.BackBufferCount = 0;
6103 LEAVE_GL();
6105 if(Swapchain->backBuffer[0])
6106 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6107 Swapchain->backBuffer[0] = Back;
6109 if(Swapchain->backBuffer[0]) {
6110 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6111 } else {
6112 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6113 Swapchain->backBuffer = NULL;
6118 return WINED3D_OK;
6121 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6123 *ppZStencilSurface = This->stencilBufferTarget;
6124 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6126 if(*ppZStencilSurface != NULL) {
6127 /* Note inc ref on returned surface */
6128 IWineD3DSurface_AddRef(*ppZStencilSurface);
6129 return WINED3D_OK;
6130 } else {
6131 return WINED3DERR_NOTFOUND;
6135 /* TODO: Handle stencil attachments */
6136 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6138 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6140 TRACE("Set depth stencil to %p\n", depth_stencil);
6142 if (depth_stencil_impl) {
6143 if (depth_stencil_impl->current_renderbuffer) {
6144 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6145 checkGLcall("glFramebufferRenderbufferEXT()");
6146 } else {
6147 IWineD3DBaseTextureImpl *texture_impl;
6148 GLenum texttarget, target;
6149 GLint old_binding = 0;
6151 texttarget = depth_stencil_impl->glDescription.target;
6152 if(texttarget == GL_TEXTURE_2D) {
6153 target = GL_TEXTURE_2D;
6154 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6155 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6156 target = GL_TEXTURE_RECTANGLE_ARB;
6157 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6158 } else {
6159 target = GL_TEXTURE_CUBE_MAP_ARB;
6160 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6163 IWineD3DSurface_PreLoad(depth_stencil);
6165 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6166 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6167 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6168 glBindTexture(target, old_binding);
6170 /* Update base texture states array */
6171 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6172 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6173 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6174 if (texture_impl->baseTexture.bindCount) {
6175 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6178 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6181 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6182 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6183 checkGLcall("glFramebufferTexture2DEXT()");
6185 } else {
6186 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6187 checkGLcall("glFramebufferTexture2DEXT()");
6191 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6193 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6195 TRACE("Set render target %u to %p\n", idx, render_target);
6197 if (rtimpl) {
6198 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6199 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6200 } else {
6201 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6202 checkGLcall("glFramebufferTexture2DEXT()");
6204 This->draw_buffers[idx] = GL_NONE;
6208 static void check_fbo_status(IWineD3DDevice *iface) {
6209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6210 GLenum status;
6212 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6213 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6214 TRACE("FBO complete\n");
6215 } else {
6216 IWineD3DSurfaceImpl *attachment;
6217 int i;
6218 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6220 /* Dump the FBO attachments */
6221 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6222 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6223 if (attachment) {
6224 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6225 attachment->pow2Width, attachment->pow2Height);
6228 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6229 if (attachment) {
6230 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6231 attachment->pow2Width, attachment->pow2Height);
6236 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6238 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6239 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6241 if (!ds_impl) return FALSE;
6243 if (ds_impl->current_renderbuffer) {
6244 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6245 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6248 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6249 rt_impl->pow2Height != ds_impl->pow2Height);
6252 void apply_fbo_state(IWineD3DDevice *iface) {
6253 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6254 unsigned int i;
6256 if (This->render_offscreen) {
6257 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6259 /* Apply render targets */
6260 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6261 IWineD3DSurface *render_target = This->render_targets[i];
6262 if (This->fbo_color_attachments[i] != render_target) {
6263 set_render_target_fbo(iface, i, render_target);
6264 This->fbo_color_attachments[i] = render_target;
6268 /* Apply depth targets */
6269 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6270 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6271 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6273 if (This->stencilBufferTarget) {
6274 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6276 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6277 This->fbo_depth_attachment = This->stencilBufferTarget;
6280 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6281 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6282 checkGLcall("glDrawBuffers()");
6283 } else {
6284 glDrawBuffer(This->draw_buffers[0]);
6285 checkGLcall("glDrawBuffer()");
6287 } else {
6288 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6291 check_fbo_status(iface);
6294 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6295 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6297 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6298 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6299 GLenum gl_filter;
6301 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6302 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6303 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6304 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6306 switch (filter) {
6307 case WINED3DTEXF_LINEAR:
6308 gl_filter = GL_LINEAR;
6309 break;
6311 default:
6312 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6313 case WINED3DTEXF_NONE:
6314 case WINED3DTEXF_POINT:
6315 gl_filter = GL_NEAREST;
6316 break;
6319 /* Attach src surface to src fbo */
6320 src_swapchain = get_swapchain(src_surface);
6321 if (src_swapchain) {
6322 GLenum buffer;
6324 TRACE("Source surface %p is onscreen\n", src_surface);
6325 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6326 /* Make sure the drawable is up to date. In the offscreen case
6327 * attach_surface_fbo() implicitly takes care of this. */
6328 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6330 ENTER_GL();
6331 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6332 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6333 glReadBuffer(buffer);
6334 checkGLcall("glReadBuffer()");
6336 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6337 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6338 } else {
6339 TRACE("Source surface %p is offscreen\n", src_surface);
6340 ENTER_GL();
6341 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6342 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6343 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6344 checkGLcall("glReadBuffer()");
6346 LEAVE_GL();
6348 /* Attach dst surface to dst fbo */
6349 dst_swapchain = get_swapchain(dst_surface);
6350 if (dst_swapchain) {
6351 GLenum buffer;
6353 TRACE("Destination surface %p is onscreen\n", dst_surface);
6354 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6355 /* Make sure the drawable is up to date. In the offscreen case
6356 * attach_surface_fbo() implicitly takes care of this. */
6357 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6359 ENTER_GL();
6360 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6361 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6362 glDrawBuffer(buffer);
6363 checkGLcall("glDrawBuffer()");
6365 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6366 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6367 } else {
6368 TRACE("Destination surface %p is offscreen\n", dst_surface);
6370 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6371 if(!src_swapchain) {
6372 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6375 ENTER_GL();
6376 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6377 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6378 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6379 checkGLcall("glDrawBuffer()");
6381 glDisable(GL_SCISSOR_TEST);
6382 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6384 if (flip) {
6385 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6386 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6387 checkGLcall("glBlitFramebuffer()");
6388 } else {
6389 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6390 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6391 checkGLcall("glBlitFramebuffer()");
6394 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6396 if (This->render_offscreen) {
6397 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6398 } else {
6399 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6400 checkGLcall("glBindFramebuffer()");
6403 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6404 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6405 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6406 glDrawBuffer(GL_BACK);
6407 checkGLcall("glDrawBuffer()");
6409 LEAVE_GL();
6412 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6414 WINED3DVIEWPORT viewport;
6416 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6418 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6419 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6420 This, RenderTargetIndex, GL_LIMITS(buffers));
6421 return WINED3DERR_INVALIDCALL;
6424 /* MSDN says that null disables the render target
6425 but a device must always be associated with a render target
6426 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6428 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6429 FIXME("Trying to set render target 0 to NULL\n");
6430 return WINED3DERR_INVALIDCALL;
6432 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6433 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);
6434 return WINED3DERR_INVALIDCALL;
6437 /* If we are trying to set what we already have, don't bother */
6438 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6439 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6440 return WINED3D_OK;
6442 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6443 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6444 This->render_targets[RenderTargetIndex] = pRenderTarget;
6446 /* Render target 0 is special */
6447 if(RenderTargetIndex == 0) {
6448 /* Finally, reset the viewport as the MSDN states. */
6449 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6450 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6451 viewport.X = 0;
6452 viewport.Y = 0;
6453 viewport.MaxZ = 1.0f;
6454 viewport.MinZ = 0.0f;
6455 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6456 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6457 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6459 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6461 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6462 * ctx properly.
6463 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6464 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6466 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6468 return WINED3D_OK;
6471 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6473 HRESULT hr = WINED3D_OK;
6474 IWineD3DSurface *tmp;
6476 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6478 if (pNewZStencil == This->stencilBufferTarget) {
6479 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6480 } else {
6481 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6482 * depending on the renter target implementation being used.
6483 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6484 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6485 * stencil buffer and incur an extra memory overhead
6486 ******************************************************/
6488 tmp = This->stencilBufferTarget;
6489 This->stencilBufferTarget = pNewZStencil;
6490 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6491 /* should we be calling the parent or the wined3d surface? */
6492 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6493 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6494 hr = WINED3D_OK;
6496 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6497 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6498 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6499 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6500 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6504 return hr;
6507 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6508 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6510 /* TODO: the use of Impl is deprecated. */
6511 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6512 WINED3DLOCKED_RECT lockedRect;
6514 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6516 /* some basic validation checks */
6517 if(This->cursorTexture) {
6518 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6519 ENTER_GL();
6520 glDeleteTextures(1, &This->cursorTexture);
6521 LEAVE_GL();
6522 This->cursorTexture = 0;
6525 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6526 This->haveHardwareCursor = TRUE;
6527 else
6528 This->haveHardwareCursor = FALSE;
6530 if(pCursorBitmap) {
6531 WINED3DLOCKED_RECT rect;
6533 /* MSDN: Cursor must be A8R8G8B8 */
6534 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6535 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6536 return WINED3DERR_INVALIDCALL;
6539 /* MSDN: Cursor must be smaller than the display mode */
6540 if(pSur->currentDesc.Width > This->ddraw_width ||
6541 pSur->currentDesc.Height > This->ddraw_height) {
6542 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);
6543 return WINED3DERR_INVALIDCALL;
6546 if (!This->haveHardwareCursor) {
6547 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6549 /* Do not store the surface's pointer because the application may
6550 * release it after setting the cursor image. Windows doesn't
6551 * addref the set surface, so we can't do this either without
6552 * creating circular refcount dependencies. Copy out the gl texture
6553 * instead.
6555 This->cursorWidth = pSur->currentDesc.Width;
6556 This->cursorHeight = pSur->currentDesc.Height;
6557 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6559 const GlPixelFormatDesc *glDesc;
6560 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6561 char *mem, *bits = (char *)rect.pBits;
6562 GLint intfmt = glDesc->glInternal;
6563 GLint format = glDesc->glFormat;
6564 GLint type = glDesc->glType;
6565 INT height = This->cursorHeight;
6566 INT width = This->cursorWidth;
6567 INT bpp = tableEntry->bpp;
6568 INT i;
6570 /* Reformat the texture memory (pitch and width can be
6571 * different) */
6572 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6573 for(i = 0; i < height; i++)
6574 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6575 IWineD3DSurface_UnlockRect(pCursorBitmap);
6576 ENTER_GL();
6578 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6579 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6580 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6583 /* Make sure that a proper texture unit is selected */
6584 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6585 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6586 checkGLcall("glActiveTextureARB");
6588 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6589 /* Create a new cursor texture */
6590 glGenTextures(1, &This->cursorTexture);
6591 checkGLcall("glGenTextures");
6592 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6593 checkGLcall("glBindTexture");
6594 /* Copy the bitmap memory into the cursor texture */
6595 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6596 HeapFree(GetProcessHeap(), 0, mem);
6597 checkGLcall("glTexImage2D");
6599 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6600 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6601 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6604 LEAVE_GL();
6606 else
6608 FIXME("A cursor texture was not returned.\n");
6609 This->cursorTexture = 0;
6612 else
6614 /* Draw a hardware cursor */
6615 ICONINFO cursorInfo;
6616 HCURSOR cursor;
6617 /* Create and clear maskBits because it is not needed for
6618 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6619 * chunks. */
6620 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6621 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6622 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6623 WINED3DLOCK_NO_DIRTY_UPDATE |
6624 WINED3DLOCK_READONLY
6626 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6627 pSur->currentDesc.Height);
6629 cursorInfo.fIcon = FALSE;
6630 cursorInfo.xHotspot = XHotSpot;
6631 cursorInfo.yHotspot = YHotSpot;
6632 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6633 pSur->currentDesc.Height, 1,
6634 1, &maskBits);
6635 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6636 pSur->currentDesc.Height, 1,
6637 32, lockedRect.pBits);
6638 IWineD3DSurface_UnlockRect(pCursorBitmap);
6639 /* Create our cursor and clean up. */
6640 cursor = CreateIconIndirect(&cursorInfo);
6641 SetCursor(cursor);
6642 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6643 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6644 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6645 This->hardwareCursor = cursor;
6646 HeapFree(GetProcessHeap(), 0, maskBits);
6650 This->xHotSpot = XHotSpot;
6651 This->yHotSpot = YHotSpot;
6652 return WINED3D_OK;
6655 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6657 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6659 This->xScreenSpace = XScreenSpace;
6660 This->yScreenSpace = YScreenSpace;
6662 return;
6666 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6668 BOOL oldVisible = This->bCursorVisible;
6669 POINT pt;
6671 TRACE("(%p) : visible(%d)\n", This, bShow);
6674 * When ShowCursor is first called it should make the cursor appear at the OS's last
6675 * known cursor position. Because of this, some applications just repetitively call
6676 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6678 GetCursorPos(&pt);
6679 This->xScreenSpace = pt.x;
6680 This->yScreenSpace = pt.y;
6682 if (This->haveHardwareCursor) {
6683 This->bCursorVisible = bShow;
6684 if (bShow)
6685 SetCursor(This->hardwareCursor);
6686 else
6687 SetCursor(NULL);
6689 else
6691 if (This->cursorTexture)
6692 This->bCursorVisible = bShow;
6695 return oldVisible;
6698 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6700 IWineD3DResourceImpl *resource;
6701 TRACE("(%p) : state (%u)\n", This, This->state);
6703 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6704 switch (This->state) {
6705 case WINED3D_OK:
6706 return WINED3D_OK;
6707 case WINED3DERR_DEVICELOST:
6709 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6710 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6711 return WINED3DERR_DEVICENOTRESET;
6713 return WINED3DERR_DEVICELOST;
6715 case WINED3DERR_DRIVERINTERNALERROR:
6716 return WINED3DERR_DRIVERINTERNALERROR;
6719 /* Unknown state */
6720 return WINED3DERR_DRIVERINTERNALERROR;
6724 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6726 /** FIXME: Resource tracking needs to be done,
6727 * The closes we can do to this is set the priorities of all managed textures low
6728 * and then reset them.
6729 ***********************************************************/
6730 FIXME("(%p) : stub\n", This);
6731 return WINED3D_OK;
6734 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6735 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6737 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6738 if(surface->Flags & SFLAG_DIBSECTION) {
6739 /* Release the DC */
6740 SelectObject(surface->hDC, surface->dib.holdbitmap);
6741 DeleteDC(surface->hDC);
6742 /* Release the DIB section */
6743 DeleteObject(surface->dib.DIBsection);
6744 surface->dib.bitmap_data = NULL;
6745 surface->resource.allocatedMemory = NULL;
6746 surface->Flags &= ~SFLAG_DIBSECTION;
6748 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6749 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6750 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE)) {
6751 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6752 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6753 } else {
6754 surface->pow2Width = surface->pow2Height = 1;
6755 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6756 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6758 surface->glRect.left = 0;
6759 surface->glRect.top = 0;
6760 surface->glRect.right = surface->pow2Width;
6761 surface->glRect.bottom = surface->pow2Height;
6763 if(surface->glDescription.textureName) {
6764 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6765 ENTER_GL();
6766 glDeleteTextures(1, &surface->glDescription.textureName);
6767 LEAVE_GL();
6768 surface->glDescription.textureName = 0;
6769 surface->Flags &= ~SFLAG_CLIENT;
6771 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6772 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6773 surface->Flags |= SFLAG_NONPOW2;
6774 } else {
6775 surface->Flags &= ~SFLAG_NONPOW2;
6777 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6778 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6781 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6782 TRACE("Unloading resource %p\n", resource);
6783 IWineD3DResource_UnLoad(resource);
6784 IWineD3DResource_Release(resource);
6785 return S_OK;
6788 static void reset_fbo_state(IWineD3DDevice *iface) {
6789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6790 unsigned int i;
6792 ENTER_GL();
6793 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6794 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
6796 if (This->fbo) {
6797 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
6798 This->fbo = 0;
6800 if (This->src_fbo) {
6801 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
6802 This->src_fbo = 0;
6804 if (This->dst_fbo) {
6805 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
6806 This->dst_fbo = 0;
6808 checkGLcall("Tear down fbos\n");
6809 LEAVE_GL();
6811 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6812 This->fbo_color_attachments[i] = NULL;
6814 This->fbo_depth_attachment = NULL;
6817 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
6818 UINT i, count;
6819 WINED3DDISPLAYMODE m;
6820 HRESULT hr;
6822 /* All Windowed modes are supported, as is leaving the current mode */
6823 if(pp->Windowed) return TRUE;
6824 if(!pp->BackBufferWidth) return TRUE;
6825 if(!pp->BackBufferHeight) return TRUE;
6827 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6828 for(i = 0; i < count; i++) {
6829 memset(&m, 0, sizeof(m));
6830 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6831 if(FAILED(hr)) {
6832 ERR("EnumAdapterModes failed\n");
6834 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6835 /* Mode found, it is supported */
6836 return TRUE;
6839 /* Mode not found -> not supported */
6840 return FALSE;
6843 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6845 IWineD3DSwapChainImpl *swapchain;
6846 HRESULT hr;
6847 BOOL DisplayModeChanged = FALSE;
6848 WINED3DDISPLAYMODE mode;
6849 IWineD3DBaseShaderImpl *shader;
6850 IWineD3DSurfaceImpl *target;
6851 UINT i;
6852 TRACE("(%p)\n", This);
6854 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6855 if(FAILED(hr)) {
6856 ERR("Failed to get the first implicit swapchain\n");
6857 return hr;
6860 if(!is_display_mode_supported(This, pPresentationParameters)) {
6861 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6862 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6863 pPresentationParameters->BackBufferHeight);
6864 return WINED3DERR_INVALIDCALL;
6867 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6868 * on an existing gl context, so there's no real need for recreation.
6870 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6872 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6874 TRACE("New params:\n");
6875 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6876 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6877 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6878 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6879 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6880 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6881 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6882 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6883 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6884 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6885 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6886 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6887 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6889 /* No special treatment of these parameters. Just store them */
6890 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6891 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6892 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6893 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6895 /* What to do about these? */
6896 if(pPresentationParameters->BackBufferCount != 0 &&
6897 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6898 ERR("Cannot change the back buffer count yet\n");
6900 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6901 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6902 ERR("Cannot change the back buffer format yet\n");
6904 if(pPresentationParameters->hDeviceWindow != NULL &&
6905 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6906 ERR("Cannot change the device window yet\n");
6908 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6909 ERR("What do do about a changed auto depth stencil parameter?\n");
6912 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6913 reset_fbo_state((IWineD3DDevice *) This);
6916 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6917 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6918 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6921 ENTER_GL();
6922 if(This->depth_blt_texture) {
6923 glDeleteTextures(1, &This->depth_blt_texture);
6924 This->depth_blt_texture = 0;
6926 This->shader_backend->shader_destroy_depth_blt(iface);
6928 for (i = 0; i < GL_LIMITS(textures); i++) {
6929 /* Textures are recreated below */
6930 glDeleteTextures(1, &This->dummyTextureName[i]);
6931 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6932 This->dummyTextureName[i] = 0;
6934 LEAVE_GL();
6936 while(This->numContexts) {
6937 DestroyContext(This, This->contexts[0]);
6939 This->activeContext = NULL;
6940 HeapFree(GetProcessHeap(), 0, swapchain->context);
6941 swapchain->context = NULL;
6942 swapchain->num_contexts = 0;
6944 if(pPresentationParameters->Windowed) {
6945 mode.Width = swapchain->orig_width;
6946 mode.Height = swapchain->orig_height;
6947 mode.RefreshRate = 0;
6948 mode.Format = swapchain->presentParms.BackBufferFormat;
6949 } else {
6950 mode.Width = pPresentationParameters->BackBufferWidth;
6951 mode.Height = pPresentationParameters->BackBufferHeight;
6952 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6953 mode.Format = swapchain->presentParms.BackBufferFormat;
6955 SetWindowLongA(swapchain->win_handle, GWL_STYLE, WS_POPUP);
6956 SetWindowPos(swapchain->win_handle, HWND_TOP, 0, 0,
6957 pPresentationParameters->BackBufferWidth,
6958 pPresentationParameters->BackBufferHeight, SWP_SHOWWINDOW | SWP_FRAMECHANGED);
6961 /* Should Width == 800 && Height == 0 set 800x600? */
6962 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6963 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6964 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6966 WINED3DVIEWPORT vp;
6967 int i;
6969 vp.X = 0;
6970 vp.Y = 0;
6971 vp.Width = pPresentationParameters->BackBufferWidth;
6972 vp.Height = pPresentationParameters->BackBufferHeight;
6973 vp.MinZ = 0;
6974 vp.MaxZ = 1;
6976 if(!pPresentationParameters->Windowed) {
6977 DisplayModeChanged = TRUE;
6979 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6980 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6982 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6983 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6984 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6986 if(This->auto_depth_stencil_buffer) {
6987 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6991 /* Now set the new viewport */
6992 IWineD3DDevice_SetViewport(iface, &vp);
6995 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6996 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6997 DisplayModeChanged) {
6999 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
7000 if(!pPresentationParameters->Windowed) {
7001 IWineD3DDevice_SetFullscreen(iface, TRUE);
7004 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7006 /* Switching out of fullscreen mode? First set the original res, then change the window */
7007 if(pPresentationParameters->Windowed) {
7008 IWineD3DDevice_SetFullscreen(iface, FALSE);
7010 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7011 } else if(!pPresentationParameters->Windowed) {
7012 DWORD style = This->style, exStyle = This->exStyle;
7013 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7014 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7015 * Reset to clear up their mess. Guild Wars also loses the device during that.
7017 This->style = 0;
7018 This->exStyle = 0;
7019 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
7020 This->style = style;
7021 This->exStyle = exStyle;
7024 /* Recreate the primary swapchain's context */
7025 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7026 if(swapchain->backBuffer) {
7027 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7028 } else {
7029 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7031 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7032 &swapchain->presentParms);
7033 swapchain->num_contexts = 1;
7034 This->activeContext = swapchain->context[0];
7036 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7037 if(FAILED(hr)) {
7038 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7040 create_dummy_textures(This);
7042 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7043 * first use
7046 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7047 return WINED3D_OK;
7050 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7052 /** FIXME: always true at the moment **/
7053 if(!bEnableDialogs) {
7054 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7056 return WINED3D_OK;
7060 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7062 TRACE("(%p) : pParameters %p\n", This, pParameters);
7064 *pParameters = This->createParms;
7065 return WINED3D_OK;
7068 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7069 IWineD3DSwapChain *swapchain;
7070 HRESULT hrc = WINED3D_OK;
7072 TRACE("Relaying to swapchain\n");
7074 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7075 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7076 IWineD3DSwapChain_Release(swapchain);
7078 return;
7081 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7082 IWineD3DSwapChain *swapchain;
7083 HRESULT hrc = WINED3D_OK;
7085 TRACE("Relaying to swapchain\n");
7087 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7088 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7089 IWineD3DSwapChain_Release(swapchain);
7091 return;
7095 /** ********************************************************
7096 * Notification functions
7097 ** ********************************************************/
7098 /** This function must be called in the release of a resource when ref == 0,
7099 * the contents of resource must still be correct,
7100 * any handles to other resource held by the caller must be closed
7101 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7102 *****************************************************/
7103 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7106 TRACE("(%p) : Adding Resource %p\n", This, resource);
7107 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7110 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7113 TRACE("(%p) : Removing resource %p\n", This, resource);
7115 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7119 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7121 int counter;
7123 TRACE("(%p) : resource %p\n", This, resource);
7124 switch(IWineD3DResource_GetType(resource)){
7125 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7126 case WINED3DRTYPE_SURFACE: {
7127 unsigned int i;
7129 /* Cleanup any FBO attachments if d3d is enabled */
7130 if(This->d3d_initialized) {
7131 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7132 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7134 TRACE("Last active render target destroyed\n");
7135 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7136 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7137 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7138 * and the lastActiveRenderTarget member shouldn't matter
7140 if(swapchain) {
7141 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7142 TRACE("Activating primary back buffer\n");
7143 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7144 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7145 /* Single buffering environment */
7146 TRACE("Activating primary front buffer\n");
7147 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7148 } else {
7149 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7150 /* Implicit render target destroyed, that means the device is being destroyed
7151 * whatever we set here, it shouldn't matter
7153 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7155 } else {
7156 /* May happen during ddraw uninitialization */
7157 TRACE("Render target set, but swapchain does not exist!\n");
7158 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7162 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7163 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7164 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7165 set_render_target_fbo(iface, i, NULL);
7166 This->fbo_color_attachments[i] = NULL;
7169 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7170 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7171 set_depth_stencil_fbo(iface, NULL);
7172 This->fbo_depth_attachment = NULL;
7176 break;
7178 case WINED3DRTYPE_TEXTURE:
7179 case WINED3DRTYPE_CUBETEXTURE:
7180 case WINED3DRTYPE_VOLUMETEXTURE:
7181 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7182 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7183 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7184 This->stateBlock->textures[counter] = NULL;
7186 if (This->updateStateBlock != This->stateBlock ){
7187 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7188 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7189 This->updateStateBlock->textures[counter] = NULL;
7193 break;
7194 case WINED3DRTYPE_VOLUME:
7195 /* TODO: nothing really? */
7196 break;
7197 case WINED3DRTYPE_VERTEXBUFFER:
7198 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7200 int streamNumber;
7201 TRACE("Cleaning up stream pointers\n");
7203 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7204 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7205 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7207 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7208 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7209 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7210 This->updateStateBlock->streamSource[streamNumber] = 0;
7211 /* Set changed flag? */
7214 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) */
7215 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7216 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7217 This->stateBlock->streamSource[streamNumber] = 0;
7220 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7221 else { /* This shouldn't happen */
7222 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7224 #endif
7228 break;
7229 case WINED3DRTYPE_INDEXBUFFER:
7230 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7231 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7232 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7233 This->updateStateBlock->pIndexData = NULL;
7236 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7237 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7238 This->stateBlock->pIndexData = NULL;
7242 break;
7243 default:
7244 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7245 break;
7249 /* Remove the resource from the resourceStore */
7250 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7252 TRACE("Resource released\n");
7256 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7258 IWineD3DResourceImpl *resource, *cursor;
7259 HRESULT ret;
7260 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7262 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7263 TRACE("enumerating resource %p\n", resource);
7264 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7265 ret = pCallback((IWineD3DResource *) resource, pData);
7266 if(ret == S_FALSE) {
7267 TRACE("Canceling enumeration\n");
7268 break;
7271 return WINED3D_OK;
7274 /**********************************************************
7275 * IWineD3DDevice VTbl follows
7276 **********************************************************/
7278 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7280 /*** IUnknown methods ***/
7281 IWineD3DDeviceImpl_QueryInterface,
7282 IWineD3DDeviceImpl_AddRef,
7283 IWineD3DDeviceImpl_Release,
7284 /*** IWineD3DDevice methods ***/
7285 IWineD3DDeviceImpl_GetParent,
7286 /*** Creation methods**/
7287 IWineD3DDeviceImpl_CreateVertexBuffer,
7288 IWineD3DDeviceImpl_CreateIndexBuffer,
7289 IWineD3DDeviceImpl_CreateStateBlock,
7290 IWineD3DDeviceImpl_CreateSurface,
7291 IWineD3DDeviceImpl_CreateTexture,
7292 IWineD3DDeviceImpl_CreateVolumeTexture,
7293 IWineD3DDeviceImpl_CreateVolume,
7294 IWineD3DDeviceImpl_CreateCubeTexture,
7295 IWineD3DDeviceImpl_CreateQuery,
7296 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7297 IWineD3DDeviceImpl_CreateVertexDeclaration,
7298 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7299 IWineD3DDeviceImpl_CreateVertexShader,
7300 IWineD3DDeviceImpl_CreatePixelShader,
7301 IWineD3DDeviceImpl_CreatePalette,
7302 /*** Odd functions **/
7303 IWineD3DDeviceImpl_Init3D,
7304 IWineD3DDeviceImpl_Uninit3D,
7305 IWineD3DDeviceImpl_SetFullscreen,
7306 IWineD3DDeviceImpl_SetMultithreaded,
7307 IWineD3DDeviceImpl_EvictManagedResources,
7308 IWineD3DDeviceImpl_GetAvailableTextureMem,
7309 IWineD3DDeviceImpl_GetBackBuffer,
7310 IWineD3DDeviceImpl_GetCreationParameters,
7311 IWineD3DDeviceImpl_GetDeviceCaps,
7312 IWineD3DDeviceImpl_GetDirect3D,
7313 IWineD3DDeviceImpl_GetDisplayMode,
7314 IWineD3DDeviceImpl_SetDisplayMode,
7315 IWineD3DDeviceImpl_GetHWND,
7316 IWineD3DDeviceImpl_SetHWND,
7317 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7318 IWineD3DDeviceImpl_GetRasterStatus,
7319 IWineD3DDeviceImpl_GetSwapChain,
7320 IWineD3DDeviceImpl_Reset,
7321 IWineD3DDeviceImpl_SetDialogBoxMode,
7322 IWineD3DDeviceImpl_SetCursorProperties,
7323 IWineD3DDeviceImpl_SetCursorPosition,
7324 IWineD3DDeviceImpl_ShowCursor,
7325 IWineD3DDeviceImpl_TestCooperativeLevel,
7326 /*** Getters and setters **/
7327 IWineD3DDeviceImpl_SetClipPlane,
7328 IWineD3DDeviceImpl_GetClipPlane,
7329 IWineD3DDeviceImpl_SetClipStatus,
7330 IWineD3DDeviceImpl_GetClipStatus,
7331 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7332 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7333 IWineD3DDeviceImpl_SetDepthStencilSurface,
7334 IWineD3DDeviceImpl_GetDepthStencilSurface,
7335 IWineD3DDeviceImpl_SetFVF,
7336 IWineD3DDeviceImpl_GetFVF,
7337 IWineD3DDeviceImpl_SetGammaRamp,
7338 IWineD3DDeviceImpl_GetGammaRamp,
7339 IWineD3DDeviceImpl_SetIndices,
7340 IWineD3DDeviceImpl_GetIndices,
7341 IWineD3DDeviceImpl_SetBaseVertexIndex,
7342 IWineD3DDeviceImpl_GetBaseVertexIndex,
7343 IWineD3DDeviceImpl_SetLight,
7344 IWineD3DDeviceImpl_GetLight,
7345 IWineD3DDeviceImpl_SetLightEnable,
7346 IWineD3DDeviceImpl_GetLightEnable,
7347 IWineD3DDeviceImpl_SetMaterial,
7348 IWineD3DDeviceImpl_GetMaterial,
7349 IWineD3DDeviceImpl_SetNPatchMode,
7350 IWineD3DDeviceImpl_GetNPatchMode,
7351 IWineD3DDeviceImpl_SetPaletteEntries,
7352 IWineD3DDeviceImpl_GetPaletteEntries,
7353 IWineD3DDeviceImpl_SetPixelShader,
7354 IWineD3DDeviceImpl_GetPixelShader,
7355 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7356 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7357 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7358 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7359 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7360 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7361 IWineD3DDeviceImpl_SetRenderState,
7362 IWineD3DDeviceImpl_GetRenderState,
7363 IWineD3DDeviceImpl_SetRenderTarget,
7364 IWineD3DDeviceImpl_GetRenderTarget,
7365 IWineD3DDeviceImpl_SetFrontBackBuffers,
7366 IWineD3DDeviceImpl_SetSamplerState,
7367 IWineD3DDeviceImpl_GetSamplerState,
7368 IWineD3DDeviceImpl_SetScissorRect,
7369 IWineD3DDeviceImpl_GetScissorRect,
7370 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7371 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7372 IWineD3DDeviceImpl_SetStreamSource,
7373 IWineD3DDeviceImpl_GetStreamSource,
7374 IWineD3DDeviceImpl_SetStreamSourceFreq,
7375 IWineD3DDeviceImpl_GetStreamSourceFreq,
7376 IWineD3DDeviceImpl_SetTexture,
7377 IWineD3DDeviceImpl_GetTexture,
7378 IWineD3DDeviceImpl_SetTextureStageState,
7379 IWineD3DDeviceImpl_GetTextureStageState,
7380 IWineD3DDeviceImpl_SetTransform,
7381 IWineD3DDeviceImpl_GetTransform,
7382 IWineD3DDeviceImpl_SetVertexDeclaration,
7383 IWineD3DDeviceImpl_GetVertexDeclaration,
7384 IWineD3DDeviceImpl_SetVertexShader,
7385 IWineD3DDeviceImpl_GetVertexShader,
7386 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7387 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7388 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7389 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7390 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7391 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7392 IWineD3DDeviceImpl_SetViewport,
7393 IWineD3DDeviceImpl_GetViewport,
7394 IWineD3DDeviceImpl_MultiplyTransform,
7395 IWineD3DDeviceImpl_ValidateDevice,
7396 IWineD3DDeviceImpl_ProcessVertices,
7397 /*** State block ***/
7398 IWineD3DDeviceImpl_BeginStateBlock,
7399 IWineD3DDeviceImpl_EndStateBlock,
7400 /*** Scene management ***/
7401 IWineD3DDeviceImpl_BeginScene,
7402 IWineD3DDeviceImpl_EndScene,
7403 IWineD3DDeviceImpl_Present,
7404 IWineD3DDeviceImpl_Clear,
7405 /*** Drawing ***/
7406 IWineD3DDeviceImpl_DrawPrimitive,
7407 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7408 IWineD3DDeviceImpl_DrawPrimitiveUP,
7409 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7410 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7411 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7412 IWineD3DDeviceImpl_DrawRectPatch,
7413 IWineD3DDeviceImpl_DrawTriPatch,
7414 IWineD3DDeviceImpl_DeletePatch,
7415 IWineD3DDeviceImpl_ColorFill,
7416 IWineD3DDeviceImpl_UpdateTexture,
7417 IWineD3DDeviceImpl_UpdateSurface,
7418 IWineD3DDeviceImpl_GetFrontBufferData,
7419 /*** object tracking ***/
7420 IWineD3DDeviceImpl_ResourceReleased,
7421 IWineD3DDeviceImpl_EnumResources
7425 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7426 WINED3DRS_ALPHABLENDENABLE ,
7427 WINED3DRS_ALPHAFUNC ,
7428 WINED3DRS_ALPHAREF ,
7429 WINED3DRS_ALPHATESTENABLE ,
7430 WINED3DRS_BLENDOP ,
7431 WINED3DRS_COLORWRITEENABLE ,
7432 WINED3DRS_DESTBLEND ,
7433 WINED3DRS_DITHERENABLE ,
7434 WINED3DRS_FILLMODE ,
7435 WINED3DRS_FOGDENSITY ,
7436 WINED3DRS_FOGEND ,
7437 WINED3DRS_FOGSTART ,
7438 WINED3DRS_LASTPIXEL ,
7439 WINED3DRS_SHADEMODE ,
7440 WINED3DRS_SRCBLEND ,
7441 WINED3DRS_STENCILENABLE ,
7442 WINED3DRS_STENCILFAIL ,
7443 WINED3DRS_STENCILFUNC ,
7444 WINED3DRS_STENCILMASK ,
7445 WINED3DRS_STENCILPASS ,
7446 WINED3DRS_STENCILREF ,
7447 WINED3DRS_STENCILWRITEMASK ,
7448 WINED3DRS_STENCILZFAIL ,
7449 WINED3DRS_TEXTUREFACTOR ,
7450 WINED3DRS_WRAP0 ,
7451 WINED3DRS_WRAP1 ,
7452 WINED3DRS_WRAP2 ,
7453 WINED3DRS_WRAP3 ,
7454 WINED3DRS_WRAP4 ,
7455 WINED3DRS_WRAP5 ,
7456 WINED3DRS_WRAP6 ,
7457 WINED3DRS_WRAP7 ,
7458 WINED3DRS_ZENABLE ,
7459 WINED3DRS_ZFUNC ,
7460 WINED3DRS_ZWRITEENABLE
7463 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7464 WINED3DTSS_ADDRESSW ,
7465 WINED3DTSS_ALPHAARG0 ,
7466 WINED3DTSS_ALPHAARG1 ,
7467 WINED3DTSS_ALPHAARG2 ,
7468 WINED3DTSS_ALPHAOP ,
7469 WINED3DTSS_BUMPENVLOFFSET ,
7470 WINED3DTSS_BUMPENVLSCALE ,
7471 WINED3DTSS_BUMPENVMAT00 ,
7472 WINED3DTSS_BUMPENVMAT01 ,
7473 WINED3DTSS_BUMPENVMAT10 ,
7474 WINED3DTSS_BUMPENVMAT11 ,
7475 WINED3DTSS_COLORARG0 ,
7476 WINED3DTSS_COLORARG1 ,
7477 WINED3DTSS_COLORARG2 ,
7478 WINED3DTSS_COLOROP ,
7479 WINED3DTSS_RESULTARG ,
7480 WINED3DTSS_TEXCOORDINDEX ,
7481 WINED3DTSS_TEXTURETRANSFORMFLAGS
7484 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7485 WINED3DSAMP_ADDRESSU ,
7486 WINED3DSAMP_ADDRESSV ,
7487 WINED3DSAMP_ADDRESSW ,
7488 WINED3DSAMP_BORDERCOLOR ,
7489 WINED3DSAMP_MAGFILTER ,
7490 WINED3DSAMP_MINFILTER ,
7491 WINED3DSAMP_MIPFILTER ,
7492 WINED3DSAMP_MIPMAPLODBIAS ,
7493 WINED3DSAMP_MAXMIPLEVEL ,
7494 WINED3DSAMP_MAXANISOTROPY ,
7495 WINED3DSAMP_SRGBTEXTURE ,
7496 WINED3DSAMP_ELEMENTINDEX
7499 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7500 WINED3DRS_AMBIENT ,
7501 WINED3DRS_AMBIENTMATERIALSOURCE ,
7502 WINED3DRS_CLIPPING ,
7503 WINED3DRS_CLIPPLANEENABLE ,
7504 WINED3DRS_COLORVERTEX ,
7505 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7506 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7507 WINED3DRS_FOGDENSITY ,
7508 WINED3DRS_FOGEND ,
7509 WINED3DRS_FOGSTART ,
7510 WINED3DRS_FOGTABLEMODE ,
7511 WINED3DRS_FOGVERTEXMODE ,
7512 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7513 WINED3DRS_LIGHTING ,
7514 WINED3DRS_LOCALVIEWER ,
7515 WINED3DRS_MULTISAMPLEANTIALIAS ,
7516 WINED3DRS_MULTISAMPLEMASK ,
7517 WINED3DRS_NORMALIZENORMALS ,
7518 WINED3DRS_PATCHEDGESTYLE ,
7519 WINED3DRS_POINTSCALE_A ,
7520 WINED3DRS_POINTSCALE_B ,
7521 WINED3DRS_POINTSCALE_C ,
7522 WINED3DRS_POINTSCALEENABLE ,
7523 WINED3DRS_POINTSIZE ,
7524 WINED3DRS_POINTSIZE_MAX ,
7525 WINED3DRS_POINTSIZE_MIN ,
7526 WINED3DRS_POINTSPRITEENABLE ,
7527 WINED3DRS_RANGEFOGENABLE ,
7528 WINED3DRS_SPECULARMATERIALSOURCE ,
7529 WINED3DRS_TWEENFACTOR ,
7530 WINED3DRS_VERTEXBLEND ,
7531 WINED3DRS_CULLMODE ,
7532 WINED3DRS_FOGCOLOR
7535 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7536 WINED3DTSS_TEXCOORDINDEX ,
7537 WINED3DTSS_TEXTURETRANSFORMFLAGS
7540 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7541 WINED3DSAMP_DMAPOFFSET
7544 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7545 DWORD rep = StateTable[state].representative;
7546 DWORD idx;
7547 BYTE shift;
7548 UINT i;
7549 WineD3DContext *context;
7551 if(!rep) return;
7552 for(i = 0; i < This->numContexts; i++) {
7553 context = This->contexts[i];
7554 if(isStateDirty(context, rep)) continue;
7556 context->dirtyArray[context->numDirtyEntries++] = rep;
7557 idx = rep >> 5;
7558 shift = rep & 0x1f;
7559 context->isStateDirty[idx] |= (1 << shift);
7563 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7564 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7565 /* The drawable size of a pbuffer render target is the current pbuffer size
7567 *width = dev->pbufferWidth;
7568 *height = dev->pbufferHeight;
7571 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7572 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7574 *width = This->pow2Width;
7575 *height = This->pow2Height;
7578 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7579 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7580 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7581 * current context's drawable, which is the size of the back buffer of the swapchain
7582 * the active context belongs to. The back buffer of the swapchain is stored as the
7583 * surface the context belongs to.
7585 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7586 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;