mscoree: Add missing interfaces.
[wine/multimedia.git] / dlls / wined3d / device.c
blobee27abf337f93db7b9a372ee0a7838765f0e139c
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 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
178 /* TODO: Clean up all the surfaces and textures! */
179 /* NOTE: You must release the parent if the object was created via a callback
180 ** ***************************/
182 if (!list_empty(&This->resources)) {
183 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
184 dumpResources(&This->resources);
187 if(This->contexts) ERR("Context array not freed!\n");
188 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
189 This->haveHardwareCursor = FALSE;
191 IWineD3D_Release(This->wineD3D);
192 This->wineD3D = NULL;
193 HeapFree(GetProcessHeap(), 0, This);
194 TRACE("Freed device %p\n", This);
195 This = NULL;
197 return refCount;
200 /**********************************************************
201 * IWineD3DDevice implementation follows
202 **********************************************************/
203 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
205 *pParent = This->parent;
206 IUnknown_AddRef(This->parent);
207 return WINED3D_OK;
210 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
211 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
212 IUnknown *parent) {
213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
214 IWineD3DVertexBufferImpl *object;
215 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
216 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
217 BOOL conv;
219 if(Size == 0) {
220 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
221 *ppVertexBuffer = NULL;
222 return WINED3DERR_INVALIDCALL;
223 } else if(Pool == WINED3DPOOL_SCRATCH) {
224 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
225 * anyway, SCRATCH vertex buffers aren't useable anywhere
227 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
228 *ppVertexBuffer = NULL;
229 return WINED3DERR_INVALIDCALL;
232 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
234 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);
235 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
237 object->fvf = FVF;
239 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
240 * drawStridedFast (half-life 2).
242 * Basically converting the vertices in the buffer is quite expensive, and observations
243 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
244 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
246 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
247 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
248 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
249 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
250 * dx7 apps.
251 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
252 * more. In this call we can convert dx7 buffers too.
254 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
255 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
256 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
257 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
258 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
259 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
260 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
261 } else if(dxVersion <= 7 && conv) {
262 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
263 } else {
264 object->Flags |= VBFLAG_CREATEVBO;
266 return WINED3D_OK;
269 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
270 GLenum error, glUsage;
271 TRACE("Creating VBO for Index Buffer %p\n", object);
273 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
274 * restored on the next draw
276 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
278 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
279 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
280 ENTER_GL();
282 while(glGetError());
284 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
285 error = glGetError();
286 if(error != GL_NO_ERROR || object->vbo == 0) {
287 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
288 goto out;
291 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
292 error = glGetError();
293 if(error != GL_NO_ERROR) {
294 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
295 goto out;
298 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
299 * copy no readback will be needed
301 glUsage = GL_STATIC_DRAW_ARB;
302 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
303 error = glGetError();
304 if(error != GL_NO_ERROR) {
305 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
306 goto out;
308 LEAVE_GL();
309 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
310 return;
312 out:
313 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
314 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
315 LEAVE_GL();
316 object->vbo = 0;
319 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
320 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
321 HANDLE *sharedHandle, IUnknown *parent) {
322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
323 IWineD3DIndexBufferImpl *object;
324 TRACE("(%p) Creating index buffer\n", This);
326 /* Allocate the storage for the device */
327 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
329 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
330 CreateIndexBufferVBO(This, object);
333 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
334 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
335 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
337 return WINED3D_OK;
340 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
343 IWineD3DStateBlockImpl *object;
344 int i, j;
345 HRESULT temp_result;
347 D3DCREATEOBJECTINSTANCE(object, StateBlock)
348 object->blockType = Type;
350 for(i = 0; i < LIGHTMAP_SIZE; i++) {
351 list_init(&object->lightMap[i]);
354 /* Special case - Used during initialization to produce a placeholder stateblock
355 so other functions called can update a state block */
356 if (Type == WINED3DSBT_INIT) {
357 /* Don't bother increasing the reference count otherwise a device will never
358 be freed due to circular dependencies */
359 return WINED3D_OK;
362 temp_result = allocate_shader_constants(object);
363 if (WINED3D_OK != temp_result)
364 return temp_result;
366 /* Otherwise, might as well set the whole state block to the appropriate values */
367 if (This->stateBlock != NULL)
368 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
369 else
370 memset(object->streamFreq, 1, sizeof(object->streamFreq));
372 /* Reset the ref and type after kludging it */
373 object->wineD3DDevice = This;
374 object->ref = 1;
375 object->blockType = Type;
377 TRACE("Updating changed flags appropriate for type %d\n", Type);
379 if (Type == WINED3DSBT_ALL) {
381 TRACE("ALL => Pretend everything has changed\n");
382 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
384 /* Lights are not part of the changed / set structure */
385 for(j = 0; j < LIGHTMAP_SIZE; j++) {
386 struct list *e;
387 LIST_FOR_EACH(e, &object->lightMap[j]) {
388 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
389 light->changed = TRUE;
390 light->enabledChanged = TRUE;
393 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
394 object->contained_render_states[j - 1] = j;
396 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
397 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
398 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
399 object->contained_transform_states[j - 1] = j;
401 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
402 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
403 object->contained_vs_consts_f[j] = j;
405 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
406 for(j = 0; j < MAX_CONST_I; j++) {
407 object->contained_vs_consts_i[j] = j;
409 object->num_contained_vs_consts_i = MAX_CONST_I;
410 for(j = 0; j < MAX_CONST_B; j++) {
411 object->contained_vs_consts_b[j] = j;
413 object->num_contained_vs_consts_b = MAX_CONST_B;
414 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
415 object->contained_ps_consts_f[j] = j;
417 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
418 for(j = 0; j < MAX_CONST_I; j++) {
419 object->contained_ps_consts_i[j] = j;
421 object->num_contained_ps_consts_i = MAX_CONST_I;
422 for(j = 0; j < MAX_CONST_B; j++) {
423 object->contained_ps_consts_b[j] = j;
425 object->num_contained_ps_consts_b = MAX_CONST_B;
426 for(i = 0; i < MAX_TEXTURES; i++) {
427 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
428 object->contained_tss_states[object->num_contained_tss_states].stage = i;
429 object->contained_tss_states[object->num_contained_tss_states].state = j;
430 object->num_contained_tss_states++;
433 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
434 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
435 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
436 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
437 object->num_contained_sampler_states++;
441 for(i = 0; i < MAX_STREAMS; i++) {
442 if(object->streamSource[i]) {
443 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
446 if(object->pIndexData) {
447 IWineD3DIndexBuffer_AddRef(object->pIndexData);
449 if(object->vertexShader) {
450 IWineD3DVertexShader_AddRef(object->vertexShader);
452 if(object->pixelShader) {
453 IWineD3DPixelShader_AddRef(object->pixelShader);
456 } else if (Type == WINED3DSBT_PIXELSTATE) {
458 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
459 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
461 object->changed.pixelShader = TRUE;
463 /* Pixel Shader Constants */
464 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
465 object->contained_ps_consts_f[i] = i;
466 object->changed.pixelShaderConstantsF[i] = TRUE;
468 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
469 for (i = 0; i < MAX_CONST_B; ++i) {
470 object->contained_ps_consts_b[i] = i;
471 object->changed.pixelShaderConstantsB[i] = TRUE;
473 object->num_contained_ps_consts_b = MAX_CONST_B;
474 for (i = 0; i < MAX_CONST_I; ++i) {
475 object->contained_ps_consts_i[i] = i;
476 object->changed.pixelShaderConstantsI[i] = TRUE;
478 object->num_contained_ps_consts_i = MAX_CONST_I;
480 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
481 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
482 object->contained_render_states[i] = SavedPixelStates_R[i];
484 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
485 for (j = 0; j < MAX_TEXTURES; j++) {
486 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
487 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
488 object->contained_tss_states[object->num_contained_tss_states].stage = j;
489 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
490 object->num_contained_tss_states++;
493 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
494 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
495 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
496 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
497 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
498 object->num_contained_sampler_states++;
501 if(object->pixelShader) {
502 IWineD3DPixelShader_AddRef(object->pixelShader);
505 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
506 * on them. This makes releasing the buffer easier
508 for(i = 0; i < MAX_STREAMS; i++) {
509 object->streamSource[i] = NULL;
511 object->pIndexData = NULL;
512 object->vertexShader = NULL;
514 } else if (Type == WINED3DSBT_VERTEXSTATE) {
516 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
517 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
519 object->changed.vertexShader = TRUE;
521 /* Vertex Shader Constants */
522 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
523 object->changed.vertexShaderConstantsF[i] = TRUE;
524 object->contained_vs_consts_f[i] = i;
526 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
527 for (i = 0; i < MAX_CONST_B; ++i) {
528 object->changed.vertexShaderConstantsB[i] = TRUE;
529 object->contained_vs_consts_b[i] = i;
531 object->num_contained_vs_consts_b = MAX_CONST_B;
532 for (i = 0; i < MAX_CONST_I; ++i) {
533 object->changed.vertexShaderConstantsI[i] = TRUE;
534 object->contained_vs_consts_i[i] = i;
536 object->num_contained_vs_consts_i = MAX_CONST_I;
537 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
538 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
539 object->contained_render_states[i] = SavedVertexStates_R[i];
541 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
542 for (j = 0; j < MAX_TEXTURES; j++) {
543 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
544 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
545 object->contained_tss_states[object->num_contained_tss_states].stage = j;
546 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
547 object->num_contained_tss_states++;
550 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
551 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
552 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
553 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
554 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
555 object->num_contained_sampler_states++;
559 for(j = 0; j < LIGHTMAP_SIZE; j++) {
560 struct list *e;
561 LIST_FOR_EACH(e, &object->lightMap[j]) {
562 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
563 light->changed = TRUE;
564 light->enabledChanged = TRUE;
568 for(i = 0; i < MAX_STREAMS; i++) {
569 if(object->streamSource[i]) {
570 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
573 if(object->vertexShader) {
574 IWineD3DVertexShader_AddRef(object->vertexShader);
576 object->pIndexData = NULL;
577 object->pixelShader = NULL;
578 } else {
579 FIXME("Unrecognized state block type %d\n", Type);
582 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
583 return WINED3D_OK;
586 /* ************************************
587 MSDN:
588 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
590 Discard
591 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
593 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.
595 ******************************** */
597 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) {
598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
599 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
600 unsigned int Size = 1;
601 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
602 TRACE("(%p) Create surface\n",This);
604 /** FIXME: Check ranges on the inputs are valid
605 * MSDN
606 * MultisampleQuality
607 * [in] Quality level. The valid range is between zero and one less than the level
608 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
609 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
610 * values of paired render targets, depth stencil surfaces, and the MultiSample type
611 * must all match.
612 *******************************/
616 * TODO: Discard MSDN
617 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
619 * If this flag is set, the contents of the depth stencil buffer will be
620 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
621 * with a different depth surface.
623 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
624 ***************************/
626 if(MultisampleQuality > 0) {
627 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
628 MultisampleQuality=0;
631 /** FIXME: Check that the format is supported
632 * by the device.
633 *******************************/
635 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
636 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
637 * space!
638 *********************************/
639 if (WINED3DFMT_UNKNOWN == Format) {
640 Size = 0;
641 } else if (Format == WINED3DFMT_DXT1) {
642 /* DXT1 is half byte per pixel */
643 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
645 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
646 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
647 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
648 } else {
649 /* The pitch is a multiple of 4 bytes */
650 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
651 Size *= Height;
654 /** Create and initialise the surface resource **/
655 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
656 /* "Standalone" surface */
657 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
659 object->currentDesc.Width = Width;
660 object->currentDesc.Height = Height;
661 object->currentDesc.MultiSampleType = MultiSample;
662 object->currentDesc.MultiSampleQuality = MultisampleQuality;
663 object->glDescription.level = Level;
665 /* Flags */
666 object->Flags = 0;
667 object->Flags |= Discard ? SFLAG_DISCARD : 0;
668 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
669 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
672 if (WINED3DFMT_UNKNOWN != Format) {
673 object->bytesPerPixel = tableEntry->bpp;
674 } else {
675 object->bytesPerPixel = 0;
678 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
680 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
682 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
683 * this function is too deep to need to care about things like this.
684 * Levels need to be checked too, and possibly Type since they all affect what can be done.
685 * ****************************************/
686 switch(Pool) {
687 case WINED3DPOOL_SCRATCH:
688 if(!Lockable)
689 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
690 "which are mutually exclusive, setting lockable to TRUE\n");
691 Lockable = TRUE;
692 break;
693 case WINED3DPOOL_SYSTEMMEM:
694 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
695 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
696 case WINED3DPOOL_MANAGED:
697 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
698 "Usage of DYNAMIC which are mutually exclusive, not doing "
699 "anything just telling you.\n");
700 break;
701 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
702 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
703 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
704 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
705 break;
706 default:
707 FIXME("(%p) Unknown pool %d\n", This, Pool);
708 break;
711 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
712 FIXME("Trying to create a render target that isn't in the default pool\n");
715 /* mark the texture as dirty so that it gets loaded first time around*/
716 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
717 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
718 This, Width, Height, Format, debug_d3dformat(Format),
719 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
721 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
722 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
723 This->ddraw_primary = (IWineD3DSurface *) object;
725 /* Look at the implementation and set the correct Vtable */
726 switch(Impl) {
727 case SURFACE_OPENGL:
728 /* Check if a 3D adapter is available when creating gl surfaces */
729 if(!This->adapter) {
730 ERR("OpenGL surfaces are not available without opengl\n");
731 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
732 HeapFree(GetProcessHeap(), 0, object);
733 return WINED3DERR_NOTAVAILABLE;
735 break;
737 case SURFACE_GDI:
738 object->lpVtbl = &IWineGDISurface_Vtbl;
739 break;
741 default:
742 /* To be sure to catch this */
743 ERR("Unknown requested surface implementation %d!\n", Impl);
744 IWineD3DSurface_Release((IWineD3DSurface *) object);
745 return WINED3DERR_INVALIDCALL;
748 list_init(&object->renderbuffers);
750 /* Call the private setup routine */
751 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
755 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
756 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
757 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
758 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
761 IWineD3DTextureImpl *object;
762 unsigned int i;
763 UINT tmpW;
764 UINT tmpH;
765 HRESULT hr;
766 unsigned int pow2Width;
767 unsigned int pow2Height;
768 const GlPixelFormatDesc *glDesc;
769 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
772 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
773 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
774 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
776 /* TODO: It should only be possible to create textures for formats
777 that are reported as supported */
778 if (WINED3DFMT_UNKNOWN >= Format) {
779 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
780 return WINED3DERR_INVALIDCALL;
783 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
784 D3DINITIALIZEBASETEXTURE(object->baseTexture);
785 object->width = Width;
786 object->height = Height;
788 /** Non-power2 support **/
789 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
790 pow2Width = Width;
791 pow2Height = Height;
792 } else {
793 /* Find the nearest pow2 match */
794 pow2Width = pow2Height = 1;
795 while (pow2Width < Width) pow2Width <<= 1;
796 while (pow2Height < Height) pow2Height <<= 1;
798 if(pow2Width != Width || pow2Height != Height) {
799 if(Levels > 1) {
800 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
801 HeapFree(GetProcessHeap(), 0, object);
802 *ppTexture = NULL;
803 return WINED3DERR_INVALIDCALL;
804 } else {
805 Levels = 1;
810 /** FIXME: add support for real non-power-two if it's provided by the video card **/
811 /* Precalculated scaling for 'faked' non power of two texture coords.
812 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
813 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
814 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
816 if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
817 (Width != pow2Width || Height != pow2Height) &&
818 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
820 object->baseTexture.pow2Matrix[0] = (float)Width;
821 object->baseTexture.pow2Matrix[5] = (float)Height;
822 object->baseTexture.pow2Matrix[10] = 1.0;
823 object->baseTexture.pow2Matrix[15] = 1.0;
824 object->target = GL_TEXTURE_RECTANGLE_ARB;
825 } else {
826 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
827 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
828 object->baseTexture.pow2Matrix[10] = 1.0;
829 object->baseTexture.pow2Matrix[15] = 1.0;
830 object->target = GL_TEXTURE_2D;
832 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
834 /* Calculate levels for mip mapping */
835 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
836 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
837 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
838 return WINED3DERR_INVALIDCALL;
840 if(Levels > 1) {
841 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
842 return WINED3DERR_INVALIDCALL;
844 object->baseTexture.levels = 1;
845 } else if (Levels == 0) {
846 TRACE("calculating levels %d\n", object->baseTexture.levels);
847 object->baseTexture.levels++;
848 tmpW = Width;
849 tmpH = Height;
850 while (tmpW > 1 || tmpH > 1) {
851 tmpW = max(1, tmpW >> 1);
852 tmpH = max(1, tmpH >> 1);
853 object->baseTexture.levels++;
855 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
858 /* Generate all the surfaces */
859 tmpW = Width;
860 tmpH = Height;
861 for (i = 0; i < object->baseTexture.levels; i++)
863 /* use the callback to create the texture surface */
864 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
865 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
866 FIXME("Failed to create surface %p\n", object);
867 /* clean up */
868 object->surfaces[i] = NULL;
869 IWineD3DTexture_Release((IWineD3DTexture *)object);
871 *ppTexture = NULL;
872 return hr;
875 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
876 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
877 /* calculate the next mipmap level */
878 tmpW = max(1, tmpW >> 1);
879 tmpH = max(1, tmpH >> 1);
881 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
883 TRACE("(%p) : Created texture %p\n", This, object);
884 return WINED3D_OK;
887 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
888 UINT Width, UINT Height, UINT Depth,
889 UINT Levels, DWORD Usage,
890 WINED3DFORMAT Format, WINED3DPOOL Pool,
891 IWineD3DVolumeTexture **ppVolumeTexture,
892 HANDLE *pSharedHandle, IUnknown *parent,
893 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
896 IWineD3DVolumeTextureImpl *object;
897 unsigned int i;
898 UINT tmpW;
899 UINT tmpH;
900 UINT tmpD;
901 const GlPixelFormatDesc *glDesc;
903 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
905 /* TODO: It should only be possible to create textures for formats
906 that are reported as supported */
907 if (WINED3DFMT_UNKNOWN >= Format) {
908 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
909 return WINED3DERR_INVALIDCALL;
911 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
912 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
913 return WINED3DERR_INVALIDCALL;
916 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
917 D3DINITIALIZEBASETEXTURE(object->baseTexture);
919 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
920 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
922 object->width = Width;
923 object->height = Height;
924 object->depth = Depth;
926 /* Is NP2 support for volumes needed? */
927 object->baseTexture.pow2Matrix[ 0] = 1.0;
928 object->baseTexture.pow2Matrix[ 5] = 1.0;
929 object->baseTexture.pow2Matrix[10] = 1.0;
930 object->baseTexture.pow2Matrix[15] = 1.0;
932 /* Calculate levels for mip mapping */
933 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
934 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
935 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
936 return WINED3DERR_INVALIDCALL;
938 if(Levels > 1) {
939 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
940 return WINED3DERR_INVALIDCALL;
942 Levels = 1;
943 } else if (Levels == 0) {
944 object->baseTexture.levels++;
945 tmpW = Width;
946 tmpH = Height;
947 tmpD = Depth;
948 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
949 tmpW = max(1, tmpW >> 1);
950 tmpH = max(1, tmpH >> 1);
951 tmpD = max(1, tmpD >> 1);
952 object->baseTexture.levels++;
954 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
957 /* Generate all the surfaces */
958 tmpW = Width;
959 tmpH = Height;
960 tmpD = Depth;
962 for (i = 0; i < object->baseTexture.levels; i++)
964 HRESULT hr;
965 /* Create the volume */
966 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
967 &object->volumes[i], pSharedHandle);
969 if(FAILED(hr)) {
970 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
971 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
972 *ppVolumeTexture = NULL;
973 return hr;
976 /* Set its container to this object */
977 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
979 /* calculate the next mipmap level */
980 tmpW = max(1, tmpW >> 1);
981 tmpH = max(1, tmpH >> 1);
982 tmpD = max(1, tmpD >> 1);
984 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
986 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
987 TRACE("(%p) : Created volume texture %p\n", This, object);
988 return WINED3D_OK;
991 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
992 UINT Width, UINT Height, UINT Depth,
993 DWORD Usage,
994 WINED3DFORMAT Format, WINED3DPOOL Pool,
995 IWineD3DVolume** ppVolume,
996 HANDLE* pSharedHandle, IUnknown *parent) {
998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
999 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1000 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1002 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1003 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1004 return WINED3DERR_INVALIDCALL;
1007 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1009 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1010 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1012 object->currentDesc.Width = Width;
1013 object->currentDesc.Height = Height;
1014 object->currentDesc.Depth = Depth;
1015 object->bytesPerPixel = formatDesc->bpp;
1017 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1018 object->lockable = TRUE;
1019 object->locked = FALSE;
1020 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1021 object->dirty = TRUE;
1023 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1026 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1027 UINT Levels, DWORD Usage,
1028 WINED3DFORMAT Format, WINED3DPOOL Pool,
1029 IWineD3DCubeTexture **ppCubeTexture,
1030 HANDLE *pSharedHandle, IUnknown *parent,
1031 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1034 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1035 unsigned int i, j;
1036 UINT tmpW;
1037 HRESULT hr;
1038 unsigned int pow2EdgeLength = EdgeLength;
1039 const GlPixelFormatDesc *glDesc;
1040 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1042 /* TODO: It should only be possible to create textures for formats
1043 that are reported as supported */
1044 if (WINED3DFMT_UNKNOWN >= Format) {
1045 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1046 return WINED3DERR_INVALIDCALL;
1049 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1050 WARN("(%p) : Tried to create not supported cube texture\n", This);
1051 return WINED3DERR_INVALIDCALL;
1054 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1055 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1057 TRACE("(%p) Create Cube Texture\n", This);
1059 /** Non-power2 support **/
1061 /* Find the nearest pow2 match */
1062 pow2EdgeLength = 1;
1063 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1065 object->edgeLength = EdgeLength;
1066 /* TODO: support for native non-power 2 */
1067 /* Precalculated scaling for 'faked' non power of two texture coords */
1068 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1069 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1070 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1071 object->baseTexture.pow2Matrix[15] = 1.0;
1073 /* Calculate levels for mip mapping */
1074 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1075 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1076 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1077 HeapFree(GetProcessHeap(), 0, object);
1078 *ppCubeTexture = NULL;
1080 return WINED3DERR_INVALIDCALL;
1082 if(Levels > 1) {
1083 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1084 HeapFree(GetProcessHeap(), 0, object);
1085 *ppCubeTexture = NULL;
1087 return WINED3DERR_INVALIDCALL;
1089 Levels = 1;
1090 } else if (Levels == 0) {
1091 object->baseTexture.levels++;
1092 tmpW = EdgeLength;
1093 while (tmpW > 1) {
1094 tmpW = max(1, tmpW >> 1);
1095 object->baseTexture.levels++;
1097 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1100 /* Generate all the surfaces */
1101 tmpW = EdgeLength;
1102 for (i = 0; i < object->baseTexture.levels; i++) {
1104 /* Create the 6 faces */
1105 for (j = 0; j < 6; j++) {
1107 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1108 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1110 if(hr!= WINED3D_OK) {
1111 /* clean up */
1112 int k;
1113 int l;
1114 for (l = 0; l < j; l++) {
1115 IWineD3DSurface_Release(object->surfaces[l][i]);
1117 for (k = 0; k < i; k++) {
1118 for (l = 0; l < 6; l++) {
1119 IWineD3DSurface_Release(object->surfaces[l][k]);
1123 FIXME("(%p) Failed to create surface\n",object);
1124 HeapFree(GetProcessHeap(),0,object);
1125 *ppCubeTexture = NULL;
1126 return hr;
1128 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1129 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1131 tmpW = max(1, tmpW >> 1);
1133 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1135 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1136 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1137 return WINED3D_OK;
1140 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1142 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1143 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1144 const IWineD3DQueryVtbl *vtable;
1146 /* Just a check to see if we support this type of query */
1147 switch(Type) {
1148 case WINED3DQUERYTYPE_OCCLUSION:
1149 TRACE("(%p) occlusion query\n", This);
1150 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1151 hr = WINED3D_OK;
1152 else
1153 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1155 vtable = &IWineD3DOcclusionQuery_Vtbl;
1156 break;
1158 case WINED3DQUERYTYPE_EVENT:
1159 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1160 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1161 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1163 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1165 vtable = &IWineD3DEventQuery_Vtbl;
1166 hr = WINED3D_OK;
1167 break;
1169 case WINED3DQUERYTYPE_VCACHE:
1170 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1171 case WINED3DQUERYTYPE_VERTEXSTATS:
1172 case WINED3DQUERYTYPE_TIMESTAMP:
1173 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1174 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1175 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1176 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1177 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1178 case WINED3DQUERYTYPE_PIXELTIMINGS:
1179 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1180 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1181 default:
1182 /* Use the base Query vtable until we have a special one for each query */
1183 vtable = &IWineD3DQuery_Vtbl;
1184 FIXME("(%p) Unhandled query type %d\n", This, Type);
1186 if(NULL == ppQuery || hr != WINED3D_OK) {
1187 return hr;
1190 D3DCREATEOBJECTINSTANCE(object, Query)
1191 object->lpVtbl = vtable;
1192 object->type = Type;
1193 object->state = QUERY_CREATED;
1194 /* allocated the 'extended' data based on the type of query requested */
1195 switch(Type){
1196 case WINED3DQUERYTYPE_OCCLUSION:
1197 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1198 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1200 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1201 TRACE("(%p) Allocating data for an occlusion query\n", This);
1202 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1203 break;
1205 case WINED3DQUERYTYPE_EVENT:
1206 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1207 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1209 if(GL_SUPPORT(APPLE_FENCE)) {
1210 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1211 checkGLcall("glGenFencesAPPLE");
1212 } else if(GL_SUPPORT(NV_FENCE)) {
1213 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1214 checkGLcall("glGenFencesNV");
1216 break;
1218 case WINED3DQUERYTYPE_VCACHE:
1219 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1220 case WINED3DQUERYTYPE_VERTEXSTATS:
1221 case WINED3DQUERYTYPE_TIMESTAMP:
1222 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1223 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1224 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1225 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1226 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1227 case WINED3DQUERYTYPE_PIXELTIMINGS:
1228 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1229 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1230 default:
1231 object->extendedData = 0;
1232 FIXME("(%p) Unhandled query type %d\n",This , Type);
1234 TRACE("(%p) : Created Query %p\n", This, object);
1235 return WINED3D_OK;
1238 /*****************************************************************************
1239 * IWineD3DDeviceImpl_SetupFullscreenWindow
1241 * Helper function that modifies a HWND's Style and ExStyle for proper
1242 * fullscreen use.
1244 * Params:
1245 * iface: Pointer to the IWineD3DDevice interface
1246 * window: Window to setup
1248 *****************************************************************************/
1249 static LONG fullscreen_style(LONG orig_style) {
1250 LONG style = orig_style;
1251 style &= ~WS_CAPTION;
1252 style &= ~WS_THICKFRAME;
1254 /* Make sure the window is managed, otherwise we won't get keyboard input */
1255 style |= WS_POPUP | WS_SYSMENU;
1257 return style;
1260 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1261 LONG exStyle = orig_exStyle;
1263 /* Filter out window decorations */
1264 exStyle &= ~WS_EX_WINDOWEDGE;
1265 exStyle &= ~WS_EX_CLIENTEDGE;
1267 return exStyle;
1270 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1273 LONG style, exStyle;
1274 /* Don't do anything if an original style is stored.
1275 * That shouldn't happen
1277 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1278 if (This->style || This->exStyle) {
1279 ERR("(%p): Want to change the window parameters of HWND %p, but "
1280 "another style is stored for restoration afterwards\n", This, window);
1283 /* Get the parameters and save them */
1284 style = GetWindowLongW(window, GWL_STYLE);
1285 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1286 This->style = style;
1287 This->exStyle = exStyle;
1289 style = fullscreen_style(style);
1290 exStyle = fullscreen_exStyle(exStyle);
1292 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1293 This->style, This->exStyle, style, exStyle);
1295 SetWindowLongW(window, GWL_STYLE, style);
1296 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1298 /* Inform the window about the update. */
1299 SetWindowPos(window, HWND_TOP, 0, 0,
1300 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1301 ShowWindow(window, SW_NORMAL);
1304 /*****************************************************************************
1305 * IWineD3DDeviceImpl_RestoreWindow
1307 * Helper function that restores a windows' properties when taking it out
1308 * of fullscreen mode
1310 * Params:
1311 * iface: Pointer to the IWineD3DDevice interface
1312 * window: Window to setup
1314 *****************************************************************************/
1315 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1317 LONG style, exStyle;
1319 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1320 * switch, do nothing
1322 if (!This->style && !This->exStyle) return;
1324 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1325 This, window, This->style, This->exStyle);
1327 style = GetWindowLongW(window, GWL_STYLE);
1328 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1330 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1331 * Some applications change it before calling Reset() when switching between windowed and
1332 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1334 if(style == fullscreen_style(This->style) &&
1335 exStyle == fullscreen_style(This->exStyle)) {
1336 SetWindowLongW(window, GWL_STYLE, This->style);
1337 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1340 /* Delete the old values */
1341 This->style = 0;
1342 This->exStyle = 0;
1344 /* Inform the window about the update */
1345 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1346 0, 0, 0, 0, /* Pos, Size, ignored */
1347 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1350 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1351 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1352 IUnknown* parent,
1353 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1354 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1357 HDC hDc;
1358 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1359 HRESULT hr = WINED3D_OK;
1360 IUnknown *bufferParent;
1361 BOOL displaymode_set = FALSE;
1362 WINED3DDISPLAYMODE Mode;
1363 const StaticPixelFormatDesc *formatDesc;
1365 TRACE("(%p) : Created Additional Swap Chain\n", This);
1367 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1368 * does a device hold a reference to a swap chain giving them a lifetime of the device
1369 * or does the swap chain notify the device of its destruction.
1370 *******************************/
1372 /* Check the params */
1373 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1374 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1375 return WINED3DERR_INVALIDCALL;
1376 } else if (pPresentationParameters->BackBufferCount > 1) {
1377 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");
1380 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1382 /*********************
1383 * Lookup the window Handle and the relating X window handle
1384 ********************/
1386 /* Setup hwnd we are using, plus which display this equates to */
1387 object->win_handle = pPresentationParameters->hDeviceWindow;
1388 if (!object->win_handle) {
1389 object->win_handle = This->createParms.hFocusWindow;
1391 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1393 hDc = GetDC(object->win_handle);
1394 TRACE("Using hDc %p\n", hDc);
1396 if (NULL == hDc) {
1397 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1398 return WINED3DERR_NOTAVAILABLE;
1401 /* Get info on the current display setup */
1402 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1403 object->orig_width = Mode.Width;
1404 object->orig_height = Mode.Height;
1405 object->orig_fmt = Mode.Format;
1406 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1408 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1409 * then the corresponding dimension of the client area of the hDeviceWindow
1410 * (or the focus window, if hDeviceWindow is NULL) is taken.
1411 **********************/
1413 if (pPresentationParameters->Windowed &&
1414 ((pPresentationParameters->BackBufferWidth == 0) ||
1415 (pPresentationParameters->BackBufferHeight == 0) ||
1416 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1418 RECT Rect;
1419 GetClientRect(object->win_handle, &Rect);
1421 if (pPresentationParameters->BackBufferWidth == 0) {
1422 pPresentationParameters->BackBufferWidth = Rect.right;
1423 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1425 if (pPresentationParameters->BackBufferHeight == 0) {
1426 pPresentationParameters->BackBufferHeight = Rect.bottom;
1427 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1429 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1430 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1431 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1435 /* Put the correct figures in the presentation parameters */
1436 TRACE("Copying across presentation parameters\n");
1437 object->presentParms = *pPresentationParameters;
1439 TRACE("calling rendertarget CB\n");
1440 hr = D3DCB_CreateRenderTarget(This->parent,
1441 parent,
1442 object->presentParms.BackBufferWidth,
1443 object->presentParms.BackBufferHeight,
1444 object->presentParms.BackBufferFormat,
1445 object->presentParms.MultiSampleType,
1446 object->presentParms.MultiSampleQuality,
1447 TRUE /* Lockable */,
1448 &object->frontBuffer,
1449 NULL /* pShared (always null)*/);
1450 if (object->frontBuffer != NULL) {
1451 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1452 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1453 } else {
1454 ERR("Failed to create the front buffer\n");
1455 goto error;
1458 /*********************
1459 * Windowed / Fullscreen
1460 *******************/
1463 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1464 * so we should really check to see if there is a fullscreen swapchain already
1465 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1466 **************************************/
1468 if (!pPresentationParameters->Windowed) {
1469 WINED3DDISPLAYMODE mode;
1472 /* Change the display settings */
1473 mode.Width = pPresentationParameters->BackBufferWidth;
1474 mode.Height = pPresentationParameters->BackBufferHeight;
1475 mode.Format = pPresentationParameters->BackBufferFormat;
1476 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1478 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1479 displaymode_set = TRUE;
1480 IWineD3DDevice_SetFullscreen(iface, TRUE);
1484 * Create an opengl context for the display visual
1485 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1486 * use different properties after that point in time. FIXME: How to handle when requested format
1487 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1488 * it chooses is identical to the one already being used!
1489 **********************************/
1490 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1492 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1493 if(!object->context)
1494 return E_OUTOFMEMORY;
1495 object->num_contexts = 1;
1497 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1498 if (!object->context[0]) {
1499 ERR("Failed to create a new context\n");
1500 hr = WINED3DERR_NOTAVAILABLE;
1501 goto error;
1502 } else {
1503 TRACE("Context created (HWND=%p, glContext=%p)\n",
1504 object->win_handle, object->context[0]->glCtx);
1507 /*********************
1508 * Create the back, front and stencil buffers
1509 *******************/
1510 if(object->presentParms.BackBufferCount > 0) {
1511 int i;
1513 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1514 if(!object->backBuffer) {
1515 ERR("Out of memory\n");
1516 hr = E_OUTOFMEMORY;
1517 goto error;
1520 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1521 TRACE("calling rendertarget CB\n");
1522 hr = D3DCB_CreateRenderTarget(This->parent,
1523 parent,
1524 object->presentParms.BackBufferWidth,
1525 object->presentParms.BackBufferHeight,
1526 object->presentParms.BackBufferFormat,
1527 object->presentParms.MultiSampleType,
1528 object->presentParms.MultiSampleQuality,
1529 TRUE /* Lockable */,
1530 &object->backBuffer[i],
1531 NULL /* pShared (always null)*/);
1532 if(hr == WINED3D_OK && object->backBuffer[i]) {
1533 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1534 } else {
1535 ERR("Cannot create new back buffer\n");
1536 goto error;
1538 ENTER_GL();
1539 glDrawBuffer(GL_BACK);
1540 checkGLcall("glDrawBuffer(GL_BACK)");
1541 LEAVE_GL();
1543 } else {
1544 object->backBuffer = NULL;
1546 /* Single buffering - draw to front buffer */
1547 ENTER_GL();
1548 glDrawBuffer(GL_FRONT);
1549 checkGLcall("glDrawBuffer(GL_FRONT)");
1550 LEAVE_GL();
1553 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1554 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1555 TRACE("Creating depth stencil buffer\n");
1556 if (This->auto_depth_stencil_buffer == NULL ) {
1557 hr = D3DCB_CreateDepthStencil(This->parent,
1558 parent,
1559 object->presentParms.BackBufferWidth,
1560 object->presentParms.BackBufferHeight,
1561 object->presentParms.AutoDepthStencilFormat,
1562 object->presentParms.MultiSampleType,
1563 object->presentParms.MultiSampleQuality,
1564 FALSE /* FIXME: Discard */,
1565 &This->auto_depth_stencil_buffer,
1566 NULL /* pShared (always null)*/ );
1567 if (This->auto_depth_stencil_buffer != NULL)
1568 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1571 /** TODO: A check on width, height and multisample types
1572 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1573 ****************************/
1574 object->wantsDepthStencilBuffer = TRUE;
1575 } else {
1576 object->wantsDepthStencilBuffer = FALSE;
1579 TRACE("Created swapchain %p\n", object);
1580 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1581 return WINED3D_OK;
1583 error:
1584 if (displaymode_set) {
1585 DEVMODEW devmode;
1586 RECT clip_rc;
1588 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1589 ClipCursor(NULL);
1591 /* Change the display settings */
1592 memset(&devmode, 0, sizeof(devmode));
1593 devmode.dmSize = sizeof(devmode);
1594 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1595 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1596 devmode.dmPelsWidth = object->orig_width;
1597 devmode.dmPelsHeight = object->orig_height;
1598 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1601 if (object->backBuffer) {
1602 int i;
1603 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1604 if(object->backBuffer[i]) {
1605 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1606 IUnknown_Release(bufferParent); /* once for the get parent */
1607 if (IUnknown_Release(bufferParent) > 0) {
1608 FIXME("(%p) Something's still holding the back buffer\n",This);
1612 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1613 object->backBuffer = NULL;
1615 if(object->context[0])
1616 DestroyContext(This, object->context[0]);
1617 if(object->frontBuffer) {
1618 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1619 IUnknown_Release(bufferParent); /* once for the get parent */
1620 if (IUnknown_Release(bufferParent) > 0) {
1621 FIXME("(%p) Something's still holding the front buffer\n",This);
1624 HeapFree(GetProcessHeap(), 0, object);
1625 return hr;
1628 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1629 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1631 TRACE("(%p)\n", This);
1633 return This->NumberOfSwapChains;
1636 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1638 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1640 if(iSwapChain < This->NumberOfSwapChains) {
1641 *pSwapChain = This->swapchains[iSwapChain];
1642 IWineD3DSwapChain_AddRef(*pSwapChain);
1643 TRACE("(%p) returning %p\n", This, *pSwapChain);
1644 return WINED3D_OK;
1645 } else {
1646 TRACE("Swapchain out of range\n");
1647 *pSwapChain = NULL;
1648 return WINED3DERR_INVALIDCALL;
1652 /*****
1653 * Vertex Declaration
1654 *****/
1655 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1656 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1658 IWineD3DVertexDeclarationImpl *object = NULL;
1659 HRESULT hr = WINED3D_OK;
1661 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1662 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1664 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1666 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1667 if(FAILED(hr)) {
1668 *ppVertexDeclaration = NULL;
1669 HeapFree(GetProcessHeap(), 0, object);
1672 return hr;
1675 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1676 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1678 unsigned int idx, idx2;
1679 unsigned int offset;
1680 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1681 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1682 BOOL has_blend_idx = has_blend &&
1683 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1684 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1685 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1686 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1687 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1688 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1689 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1691 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1692 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1694 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1695 WINED3DVERTEXELEMENT *elements = NULL;
1697 unsigned int size;
1698 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1699 if (has_blend_idx) num_blends--;
1701 /* Compute declaration size */
1702 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1703 has_psize + has_diffuse + has_specular + num_textures + 1;
1705 /* convert the declaration */
1706 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1707 if (!elements)
1708 return 0;
1710 elements[size-1] = end_element;
1711 idx = 0;
1712 if (has_pos) {
1713 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1714 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1715 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1717 else {
1718 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1719 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1721 elements[idx].UsageIndex = 0;
1722 idx++;
1724 if (has_blend && (num_blends > 0)) {
1725 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1726 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1727 else
1728 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1729 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1730 elements[idx].UsageIndex = 0;
1731 idx++;
1733 if (has_blend_idx) {
1734 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1735 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1736 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1737 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1738 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1739 else
1740 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1741 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1742 elements[idx].UsageIndex = 0;
1743 idx++;
1745 if (has_normal) {
1746 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1747 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1748 elements[idx].UsageIndex = 0;
1749 idx++;
1751 if (has_psize) {
1752 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1753 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1754 elements[idx].UsageIndex = 0;
1755 idx++;
1757 if (has_diffuse) {
1758 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1759 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1760 elements[idx].UsageIndex = 0;
1761 idx++;
1763 if (has_specular) {
1764 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1765 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1766 elements[idx].UsageIndex = 1;
1767 idx++;
1769 for (idx2 = 0; idx2 < num_textures; idx2++) {
1770 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1771 switch (numcoords) {
1772 case WINED3DFVF_TEXTUREFORMAT1:
1773 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1774 break;
1775 case WINED3DFVF_TEXTUREFORMAT2:
1776 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1777 break;
1778 case WINED3DFVF_TEXTUREFORMAT3:
1779 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1780 break;
1781 case WINED3DFVF_TEXTUREFORMAT4:
1782 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1783 break;
1785 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1786 elements[idx].UsageIndex = idx2;
1787 idx++;
1790 /* Now compute offsets, and initialize the rest of the fields */
1791 for (idx = 0, offset = 0; idx < size-1; idx++) {
1792 elements[idx].Stream = 0;
1793 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1794 elements[idx].Offset = offset;
1795 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1798 *ppVertexElements = elements;
1799 return size;
1802 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1803 WINED3DVERTEXELEMENT* elements = NULL;
1804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1805 unsigned int size;
1806 DWORD hr;
1808 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1809 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1811 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1812 HeapFree(GetProcessHeap(), 0, elements);
1813 if (hr != S_OK) return hr;
1815 return WINED3D_OK;
1818 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1820 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1821 HRESULT hr = WINED3D_OK;
1822 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1823 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1825 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1827 if (vertex_declaration) {
1828 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1831 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1833 if (WINED3D_OK != hr) {
1834 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1835 IWineD3DVertexShader_Release(*ppVertexShader);
1836 return WINED3DERR_INVALIDCALL;
1838 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1840 return WINED3D_OK;
1843 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1845 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1846 HRESULT hr = WINED3D_OK;
1848 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1849 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1850 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1851 if (WINED3D_OK == hr) {
1852 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1853 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1854 } else {
1855 WARN("(%p) : Failed to create pixel shader\n", This);
1858 return hr;
1861 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1863 IWineD3DPaletteImpl *object;
1864 HRESULT hr;
1865 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1867 /* Create the new object */
1868 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1869 if(!object) {
1870 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1871 return E_OUTOFMEMORY;
1874 object->lpVtbl = &IWineD3DPalette_Vtbl;
1875 object->ref = 1;
1876 object->Flags = Flags;
1877 object->parent = Parent;
1878 object->wineD3DDevice = This;
1879 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1881 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1883 if(!object->hpal) {
1884 HeapFree( GetProcessHeap(), 0, object);
1885 return E_OUTOFMEMORY;
1888 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1889 if(FAILED(hr)) {
1890 IWineD3DPalette_Release((IWineD3DPalette *) object);
1891 return hr;
1894 *Palette = (IWineD3DPalette *) object;
1896 return WINED3D_OK;
1899 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1900 HBITMAP hbm;
1901 BITMAP bm;
1902 HRESULT hr;
1903 HDC dcb = NULL, dcs = NULL;
1904 WINEDDCOLORKEY colorkey;
1906 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1907 if(hbm)
1909 GetObjectA(hbm, sizeof(BITMAP), &bm);
1910 dcb = CreateCompatibleDC(NULL);
1911 if(!dcb) goto out;
1912 SelectObject(dcb, hbm);
1914 else
1916 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1917 * couldn't be loaded
1919 memset(&bm, 0, sizeof(bm));
1920 bm.bmWidth = 32;
1921 bm.bmHeight = 32;
1924 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1925 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1926 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1927 if(FAILED(hr)) {
1928 ERR("Wine logo requested, but failed to create surface\n");
1929 goto out;
1932 if(dcb) {
1933 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1934 if(FAILED(hr)) goto out;
1935 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1936 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1938 colorkey.dwColorSpaceLowValue = 0;
1939 colorkey.dwColorSpaceHighValue = 0;
1940 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1941 } else {
1942 /* Fill the surface with a white color to show that wined3d is there */
1943 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1946 out:
1947 if(dcb) {
1948 DeleteDC(dcb);
1950 if(hbm) {
1951 DeleteObject(hbm);
1953 return;
1956 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1957 unsigned int i;
1958 /* Under DirectX you can have texture stage operations even if no texture is
1959 bound, whereas opengl will only do texture operations when a valid texture is
1960 bound. We emulate this by creating dummy textures and binding them to each
1961 texture stage, but disable all stages by default. Hence if a stage is enabled
1962 then the default texture will kick in until replaced by a SetTexture call */
1963 ENTER_GL();
1965 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1966 /* The dummy texture does not have client storage backing */
1967 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1968 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1970 for (i = 0; i < GL_LIMITS(textures); i++) {
1971 GLubyte white = 255;
1973 /* Make appropriate texture active */
1974 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1975 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1976 checkGLcall("glActiveTextureARB");
1977 } else if (i > 0) {
1978 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1981 /* Generate an opengl texture name */
1982 glGenTextures(1, &This->dummyTextureName[i]);
1983 checkGLcall("glGenTextures");
1984 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1986 /* Generate a dummy 2d texture (not using 1d because they cause many
1987 * DRI drivers fall back to sw) */
1988 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
1989 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1990 checkGLcall("glBindTexture");
1992 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1993 checkGLcall("glTexImage2D");
1995 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1996 /* Reenable because if supported it is enabled by default */
1997 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1998 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2001 LEAVE_GL();
2004 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2006 IWineD3DSwapChainImpl *swapchain = NULL;
2007 HRESULT hr;
2008 DWORD state;
2009 unsigned int i;
2011 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2012 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2014 /* TODO: Test if OpenGL is compiled in and loaded */
2016 TRACE("(%p) : Creating stateblock\n", This);
2017 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2018 hr = IWineD3DDevice_CreateStateBlock(iface,
2019 WINED3DSBT_INIT,
2020 (IWineD3DStateBlock **)&This->stateBlock,
2021 NULL);
2022 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2023 WARN("Failed to create stateblock\n");
2024 goto err_out;
2026 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2027 This->updateStateBlock = This->stateBlock;
2028 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2030 hr = allocate_shader_constants(This->updateStateBlock);
2031 if (WINED3D_OK != hr) {
2032 goto err_out;
2035 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2036 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2037 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2039 This->NumberOfPalettes = 1;
2040 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2041 if(!This->palettes || !This->render_targets || !This->fbo_color_attachments || !This->draw_buffers) {
2042 ERR("Out of memory!\n");
2043 goto err_out;
2045 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2046 if(!This->palettes[0]) {
2047 ERR("Out of memory!\n");
2048 goto err_out;
2050 for (i = 0; i < 256; ++i) {
2051 This->palettes[0][i].peRed = 0xFF;
2052 This->palettes[0][i].peGreen = 0xFF;
2053 This->palettes[0][i].peBlue = 0xFF;
2054 This->palettes[0][i].peFlags = 0xFF;
2056 This->currentPalette = 0;
2058 /* Initialize the texture unit mapping to a 1:1 mapping */
2059 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2060 if (state < GL_LIMITS(fragment_samplers)) {
2061 This->texUnitMap[state] = state;
2062 This->rev_tex_unit_map[state] = state;
2063 } else {
2064 This->texUnitMap[state] = -1;
2065 This->rev_tex_unit_map[state] = -1;
2069 /* Setup the implicit swapchain */
2070 TRACE("Creating implicit swapchain\n");
2071 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2072 if (FAILED(hr) || !swapchain) {
2073 WARN("Failed to create implicit swapchain\n");
2074 goto err_out;
2077 This->NumberOfSwapChains = 1;
2078 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2079 if(!This->swapchains) {
2080 ERR("Out of memory!\n");
2081 goto err_out;
2083 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2085 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2086 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2087 This->render_targets[0] = swapchain->backBuffer[0];
2088 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2090 else {
2091 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2092 This->render_targets[0] = swapchain->frontBuffer;
2093 This->lastActiveRenderTarget = swapchain->frontBuffer;
2095 IWineD3DSurface_AddRef(This->render_targets[0]);
2096 This->activeContext = swapchain->context[0];
2097 This->lastThread = GetCurrentThreadId();
2099 /* Depth Stencil support */
2100 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2101 if (NULL != This->stencilBufferTarget) {
2102 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2105 hr = This->shader_backend->shader_alloc_private(iface);
2106 if(FAILED(hr)) {
2107 TRACE("Shader private data couldn't be allocated\n");
2108 goto err_out;
2111 /* Set up some starting GL setup */
2112 ENTER_GL();
2114 /* Setup all the devices defaults */
2115 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2116 create_dummy_textures(This);
2117 #if 0
2118 IWineD3DImpl_CheckGraphicsMemory();
2119 #endif
2121 { /* Set a default viewport */
2122 WINED3DVIEWPORT vp;
2123 vp.X = 0;
2124 vp.Y = 0;
2125 vp.Width = pPresentationParameters->BackBufferWidth;
2126 vp.Height = pPresentationParameters->BackBufferHeight;
2127 vp.MinZ = 0.0f;
2128 vp.MaxZ = 1.0f;
2129 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2132 /* Initialize the current view state */
2133 This->view_ident = 1;
2134 This->contexts[0]->last_was_rhw = 0;
2135 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2136 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2138 switch(wined3d_settings.offscreen_rendering_mode) {
2139 case ORM_FBO:
2140 case ORM_PBUFFER:
2141 This->offscreenBuffer = GL_BACK;
2142 break;
2144 case ORM_BACKBUFFER:
2146 if(GL_LIMITS(aux_buffers) > 0) {
2147 TRACE("Using auxilliary buffer for offscreen rendering\n");
2148 This->offscreenBuffer = GL_AUX0;
2149 } else {
2150 TRACE("Using back buffer for offscreen rendering\n");
2151 This->offscreenBuffer = GL_BACK;
2156 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2157 LEAVE_GL();
2159 /* Clear the screen */
2160 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2161 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2162 0x00, 1.0, 0);
2164 This->d3d_initialized = TRUE;
2166 if(wined3d_settings.logo) {
2167 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2169 This->highest_dirty_ps_const = 0;
2170 This->highest_dirty_vs_const = 0;
2171 return WINED3D_OK;
2173 err_out:
2174 This->shader_backend->shader_free_private(iface);
2175 HeapFree(GetProcessHeap(), 0, This->render_targets);
2176 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2177 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2178 HeapFree(GetProcessHeap(), 0, This->swapchains);
2179 This->NumberOfSwapChains = 0;
2180 if(This->palettes) {
2181 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2182 HeapFree(GetProcessHeap(), 0, This->palettes);
2184 This->NumberOfPalettes = 0;
2185 if(swapchain) {
2186 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2188 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2189 if(This->stateBlock) {
2190 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2191 This->stateBlock = NULL;
2193 return hr;
2196 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2198 int sampler;
2199 UINT i;
2200 TRACE("(%p)\n", This);
2202 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2204 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2205 * it was created. Thus make sure a context is active for the glDelete* calls
2207 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2209 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2211 TRACE("Deleting high order patches\n");
2212 for(i = 0; i < PATCHMAP_SIZE; i++) {
2213 struct list *e1, *e2;
2214 struct WineD3DRectPatch *patch;
2215 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2216 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2217 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2221 /* Delete the palette conversion shader if it is around */
2222 if(This->paletteConversionShader) {
2223 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2224 This->paletteConversionShader = 0;
2227 /* Delete the pbuffer context if there is any */
2228 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2230 /* Delete the mouse cursor texture */
2231 if(This->cursorTexture) {
2232 ENTER_GL();
2233 glDeleteTextures(1, &This->cursorTexture);
2234 LEAVE_GL();
2235 This->cursorTexture = 0;
2238 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2239 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2241 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2242 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2245 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2246 * private data, it might contain opengl pointers
2248 This->shader_backend->shader_destroy_depth_blt(iface);
2249 This->shader_backend->shader_free_private(iface);
2251 /* Release the update stateblock */
2252 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2253 if(This->updateStateBlock != This->stateBlock)
2254 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2256 This->updateStateBlock = NULL;
2258 { /* because were not doing proper internal refcounts releasing the primary state block
2259 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2260 to set this->stateBlock = NULL; first */
2261 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2262 This->stateBlock = NULL;
2264 /* Release the stateblock */
2265 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2266 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2270 /* Release the buffers (with sanity checks)*/
2271 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2272 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2273 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2274 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2276 This->stencilBufferTarget = NULL;
2278 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2279 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2280 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2282 TRACE("Setting rendertarget to NULL\n");
2283 This->render_targets[0] = NULL;
2285 if (This->auto_depth_stencil_buffer) {
2286 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2287 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2289 This->auto_depth_stencil_buffer = NULL;
2292 for(i=0; i < This->NumberOfSwapChains; i++) {
2293 TRACE("Releasing the implicit swapchain %d\n", i);
2294 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2295 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2299 HeapFree(GetProcessHeap(), 0, This->swapchains);
2300 This->swapchains = NULL;
2301 This->NumberOfSwapChains = 0;
2303 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2304 HeapFree(GetProcessHeap(), 0, This->palettes);
2305 This->palettes = NULL;
2306 This->NumberOfPalettes = 0;
2308 HeapFree(GetProcessHeap(), 0, This->render_targets);
2309 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2310 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2311 This->render_targets = NULL;
2312 This->fbo_color_attachments = NULL;
2313 This->draw_buffers = NULL;
2315 This->d3d_initialized = FALSE;
2316 return WINED3D_OK;
2319 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2321 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2323 /* Setup the window for fullscreen mode */
2324 if(fullscreen && !This->ddraw_fullscreen) {
2325 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2326 } else if(!fullscreen && This->ddraw_fullscreen) {
2327 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2330 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2331 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2332 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2333 * separately.
2335 This->ddraw_fullscreen = fullscreen;
2338 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2339 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2340 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2342 * There is no way to deactivate thread safety once it is enabled.
2344 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2347 /*For now just store the flag(needed in case of ddraw) */
2348 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2350 return;
2353 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2354 DEVMODEW devmode;
2355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2356 LONG ret;
2357 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2358 RECT clip_rc;
2360 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2362 /* Resize the screen even without a window:
2363 * The app could have unset it with SetCooperativeLevel, but not called
2364 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2365 * but we don't have any hwnd
2368 memset(&devmode, 0, sizeof(devmode));
2369 devmode.dmSize = sizeof(devmode);
2370 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2371 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2372 devmode.dmPelsWidth = pMode->Width;
2373 devmode.dmPelsHeight = pMode->Height;
2375 devmode.dmDisplayFrequency = pMode->RefreshRate;
2376 if (pMode->RefreshRate != 0) {
2377 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2380 /* Only change the mode if necessary */
2381 if( (This->ddraw_width == pMode->Width) &&
2382 (This->ddraw_height == pMode->Height) &&
2383 (This->ddraw_format == pMode->Format) &&
2384 (pMode->RefreshRate == 0) ) {
2385 return WINED3D_OK;
2388 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2389 if (ret != DISP_CHANGE_SUCCESSFUL) {
2390 if(devmode.dmDisplayFrequency != 0) {
2391 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2392 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2393 devmode.dmDisplayFrequency = 0;
2394 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2396 if(ret != DISP_CHANGE_SUCCESSFUL) {
2397 return WINED3DERR_NOTAVAILABLE;
2401 /* Store the new values */
2402 This->ddraw_width = pMode->Width;
2403 This->ddraw_height = pMode->Height;
2404 This->ddraw_format = pMode->Format;
2406 /* Only do this with a window of course, and only if we're fullscreened */
2407 if(This->ddraw_window && This->ddraw_fullscreen)
2408 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2410 /* And finally clip mouse to our screen */
2411 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2412 ClipCursor(&clip_rc);
2414 return WINED3D_OK;
2417 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2419 *ppD3D= This->wineD3D;
2420 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2421 IWineD3D_AddRef(*ppD3D);
2422 return WINED3D_OK;
2425 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2428 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2429 (This->adapter->TextureRam/(1024*1024)),
2430 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2431 /* return simulated texture memory left */
2432 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2437 /*****
2438 * Get / Set FVF
2439 *****/
2440 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2443 /* Update the current state block */
2444 This->updateStateBlock->changed.fvf = TRUE;
2446 if(This->updateStateBlock->fvf == fvf) {
2447 TRACE("Application is setting the old fvf over, nothing to do\n");
2448 return WINED3D_OK;
2451 This->updateStateBlock->fvf = fvf;
2452 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2453 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2454 return WINED3D_OK;
2458 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2460 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2461 *pfvf = This->stateBlock->fvf;
2462 return WINED3D_OK;
2465 /*****
2466 * Get / Set Stream Source
2467 *****/
2468 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2470 IWineD3DVertexBuffer *oldSrc;
2472 if (StreamNumber >= MAX_STREAMS) {
2473 WARN("Stream out of range %d\n", StreamNumber);
2474 return WINED3DERR_INVALIDCALL;
2475 } else if(OffsetInBytes & 0x3) {
2476 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2477 return WINED3DERR_INVALIDCALL;
2480 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2481 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2483 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2485 if(oldSrc == pStreamData &&
2486 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2487 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2488 TRACE("Application is setting the old values over, nothing to do\n");
2489 return WINED3D_OK;
2492 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2493 if (pStreamData) {
2494 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2495 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2498 /* Handle recording of state blocks */
2499 if (This->isRecordingState) {
2500 TRACE("Recording... not performing anything\n");
2501 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2502 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2503 return WINED3D_OK;
2506 /* Need to do a getParent and pass the references up */
2507 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2508 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2509 so for now, just count internally */
2510 if (pStreamData != NULL) {
2511 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2512 InterlockedIncrement(&vbImpl->bindCount);
2513 IWineD3DVertexBuffer_AddRef(pStreamData);
2515 if (oldSrc != NULL) {
2516 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2517 IWineD3DVertexBuffer_Release(oldSrc);
2520 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2522 return WINED3D_OK;
2525 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2528 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2529 This->stateBlock->streamSource[StreamNumber],
2530 This->stateBlock->streamOffset[StreamNumber],
2531 This->stateBlock->streamStride[StreamNumber]);
2533 if (StreamNumber >= MAX_STREAMS) {
2534 WARN("Stream out of range %d\n", StreamNumber);
2535 return WINED3DERR_INVALIDCALL;
2537 *pStream = This->stateBlock->streamSource[StreamNumber];
2538 *pStride = This->stateBlock->streamStride[StreamNumber];
2539 if (pOffset) {
2540 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2543 if (*pStream != NULL) {
2544 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2546 return WINED3D_OK;
2549 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2551 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2552 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2554 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2555 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2557 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2558 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2560 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2561 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2562 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2565 return WINED3D_OK;
2568 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2571 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2572 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2574 TRACE("(%p) : returning %d\n", This, *Divider);
2576 return WINED3D_OK;
2579 /*****
2580 * Get / Set & Multiply Transform
2581 *****/
2582 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2585 /* Most of this routine, comments included copied from ddraw tree initially: */
2586 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2588 /* Handle recording of state blocks */
2589 if (This->isRecordingState) {
2590 TRACE("Recording... not performing anything\n");
2591 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2592 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2593 return WINED3D_OK;
2597 * If the new matrix is the same as the current one,
2598 * we cut off any further processing. this seems to be a reasonable
2599 * optimization because as was noticed, some apps (warcraft3 for example)
2600 * tend towards setting the same matrix repeatedly for some reason.
2602 * From here on we assume that the new matrix is different, wherever it matters.
2604 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2605 TRACE("The app is setting the same matrix over again\n");
2606 return WINED3D_OK;
2607 } else {
2608 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2612 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2613 where ViewMat = Camera space, WorldMat = world space.
2615 In OpenGL, camera and world space is combined into GL_MODELVIEW
2616 matrix. The Projection matrix stay projection matrix.
2619 /* Capture the times we can just ignore the change for now */
2620 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2621 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2622 /* Handled by the state manager */
2625 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2626 return WINED3D_OK;
2629 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2631 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2632 *pMatrix = This->stateBlock->transforms[State];
2633 return WINED3D_OK;
2636 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2637 WINED3DMATRIX *mat = NULL;
2638 WINED3DMATRIX temp;
2640 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2641 * below means it will be recorded in a state block change, but it
2642 * works regardless where it is recorded.
2643 * If this is found to be wrong, change to StateBlock.
2645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2646 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2648 if (State < HIGHEST_TRANSFORMSTATE)
2650 mat = &This->updateStateBlock->transforms[State];
2651 } else {
2652 FIXME("Unhandled transform state!!\n");
2655 multiply_matrix(&temp, mat, pMatrix);
2657 /* Apply change via set transform - will reapply to eg. lights this way */
2658 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2661 /*****
2662 * Get / Set Light
2663 *****/
2664 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2665 you can reference any indexes you want as long as that number max are enabled at any
2666 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2667 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2668 but when recording, just build a chain pretty much of commands to be replayed. */
2670 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2671 float rho;
2672 PLIGHTINFOEL *object = NULL;
2673 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2674 struct list *e;
2676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2677 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2679 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2680 * the gl driver.
2682 if(!pLight) {
2683 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2684 return WINED3DERR_INVALIDCALL;
2687 switch(pLight->Type) {
2688 case WINED3DLIGHT_POINT:
2689 case WINED3DLIGHT_SPOT:
2690 case WINED3DLIGHT_PARALLELPOINT:
2691 case WINED3DLIGHT_GLSPOT:
2692 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2693 * most wanted
2695 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2696 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2697 return WINED3DERR_INVALIDCALL;
2699 break;
2701 case WINED3DLIGHT_DIRECTIONAL:
2702 /* Ignores attenuation */
2703 break;
2705 default:
2706 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2707 return WINED3DERR_INVALIDCALL;
2710 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2711 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2712 if(object->OriginalIndex == Index) break;
2713 object = NULL;
2716 if(!object) {
2717 TRACE("Adding new light\n");
2718 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2719 if(!object) {
2720 ERR("Out of memory error when allocating a light\n");
2721 return E_OUTOFMEMORY;
2723 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2724 object->glIndex = -1;
2725 object->OriginalIndex = Index;
2726 object->changed = TRUE;
2729 /* Initialize the object */
2730 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,
2731 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2732 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2733 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2734 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2735 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2736 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2738 /* Save away the information */
2739 object->OriginalParms = *pLight;
2741 switch (pLight->Type) {
2742 case WINED3DLIGHT_POINT:
2743 /* Position */
2744 object->lightPosn[0] = pLight->Position.x;
2745 object->lightPosn[1] = pLight->Position.y;
2746 object->lightPosn[2] = pLight->Position.z;
2747 object->lightPosn[3] = 1.0f;
2748 object->cutoff = 180.0f;
2749 /* FIXME: Range */
2750 break;
2752 case WINED3DLIGHT_DIRECTIONAL:
2753 /* Direction */
2754 object->lightPosn[0] = -pLight->Direction.x;
2755 object->lightPosn[1] = -pLight->Direction.y;
2756 object->lightPosn[2] = -pLight->Direction.z;
2757 object->lightPosn[3] = 0.0;
2758 object->exponent = 0.0f;
2759 object->cutoff = 180.0f;
2760 break;
2762 case WINED3DLIGHT_SPOT:
2763 /* Position */
2764 object->lightPosn[0] = pLight->Position.x;
2765 object->lightPosn[1] = pLight->Position.y;
2766 object->lightPosn[2] = pLight->Position.z;
2767 object->lightPosn[3] = 1.0;
2769 /* Direction */
2770 object->lightDirn[0] = pLight->Direction.x;
2771 object->lightDirn[1] = pLight->Direction.y;
2772 object->lightDirn[2] = pLight->Direction.z;
2773 object->lightDirn[3] = 1.0;
2776 * opengl-ish and d3d-ish spot lights use too different models for the
2777 * light "intensity" as a function of the angle towards the main light direction,
2778 * so we only can approximate very roughly.
2779 * however spot lights are rather rarely used in games (if ever used at all).
2780 * furthermore if still used, probably nobody pays attention to such details.
2782 if (pLight->Falloff == 0) {
2783 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2784 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2785 * will always be 1.0 for both of them, and we don't have to care for the
2786 * rest of the rather complex calculation
2788 object->exponent = 0;
2789 } else {
2790 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2791 if (rho < 0.0001) rho = 0.0001f;
2792 object->exponent = -0.3/log(cos(rho/2));
2794 if (object->exponent > 128.0) {
2795 object->exponent = 128.0;
2797 object->cutoff = pLight->Phi*90/M_PI;
2799 /* FIXME: Range */
2800 break;
2802 default:
2803 FIXME("Unrecognized light type %d\n", pLight->Type);
2806 /* Update the live definitions if the light is currently assigned a glIndex */
2807 if (object->glIndex != -1 && !This->isRecordingState) {
2808 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2810 return WINED3D_OK;
2813 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2814 PLIGHTINFOEL *lightInfo = NULL;
2815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2816 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2817 struct list *e;
2818 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2820 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2821 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2822 if(lightInfo->OriginalIndex == Index) break;
2823 lightInfo = NULL;
2826 if (lightInfo == NULL) {
2827 TRACE("Light information requested but light not defined\n");
2828 return WINED3DERR_INVALIDCALL;
2831 *pLight = lightInfo->OriginalParms;
2832 return WINED3D_OK;
2835 /*****
2836 * Get / Set Light Enable
2837 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2838 *****/
2839 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2840 PLIGHTINFOEL *lightInfo = NULL;
2841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2842 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2843 struct list *e;
2844 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2846 /* Tests show true = 128...not clear why */
2847 Enable = Enable? 128: 0;
2849 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2850 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2851 if(lightInfo->OriginalIndex == Index) break;
2852 lightInfo = NULL;
2854 TRACE("Found light: %p\n", lightInfo);
2856 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2857 if (lightInfo == NULL) {
2859 TRACE("Light enabled requested but light not defined, so defining one!\n");
2860 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2862 /* Search for it again! Should be fairly quick as near head of list */
2863 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2864 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2865 if(lightInfo->OriginalIndex == Index) break;
2866 lightInfo = NULL;
2868 if (lightInfo == NULL) {
2869 FIXME("Adding default lights has failed dismally\n");
2870 return WINED3DERR_INVALIDCALL;
2874 lightInfo->enabledChanged = TRUE;
2875 if(!Enable) {
2876 if(lightInfo->glIndex != -1) {
2877 if(!This->isRecordingState) {
2878 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2881 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2882 lightInfo->glIndex = -1;
2883 } else {
2884 TRACE("Light already disabled, nothing to do\n");
2886 lightInfo->enabled = FALSE;
2887 } else {
2888 lightInfo->enabled = TRUE;
2889 if (lightInfo->glIndex != -1) {
2890 /* nop */
2891 TRACE("Nothing to do as light was enabled\n");
2892 } else {
2893 int i;
2894 /* Find a free gl light */
2895 for(i = 0; i < This->maxConcurrentLights; i++) {
2896 if(This->stateBlock->activeLights[i] == NULL) {
2897 This->stateBlock->activeLights[i] = lightInfo;
2898 lightInfo->glIndex = i;
2899 break;
2902 if(lightInfo->glIndex == -1) {
2903 /* Our tests show that Windows returns D3D_OK in this situation, even with
2904 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2905 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2906 * as well for those lights.
2908 * TODO: Test how this affects rendering
2910 FIXME("Too many concurrently active lights\n");
2911 return WINED3D_OK;
2914 /* i == lightInfo->glIndex */
2915 if(!This->isRecordingState) {
2916 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2921 return WINED3D_OK;
2924 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2926 PLIGHTINFOEL *lightInfo = NULL;
2927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2928 struct list *e;
2929 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2930 TRACE("(%p) : for idx(%d)\n", This, Index);
2932 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2933 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2934 if(lightInfo->OriginalIndex == Index) break;
2935 lightInfo = NULL;
2938 if (lightInfo == NULL) {
2939 TRACE("Light enabled state requested but light not defined\n");
2940 return WINED3DERR_INVALIDCALL;
2942 /* true is 128 according to SetLightEnable */
2943 *pEnable = lightInfo->enabled ? 128 : 0;
2944 return WINED3D_OK;
2947 /*****
2948 * Get / Set Clip Planes
2949 *****/
2950 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2952 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2954 /* Validate Index */
2955 if (Index >= GL_LIMITS(clipplanes)) {
2956 TRACE("Application has requested clipplane this device doesn't support\n");
2957 return WINED3DERR_INVALIDCALL;
2960 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2962 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2963 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2964 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2965 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2966 TRACE("Application is setting old values over, nothing to do\n");
2967 return WINED3D_OK;
2970 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2971 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2972 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2973 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2975 /* Handle recording of state blocks */
2976 if (This->isRecordingState) {
2977 TRACE("Recording... not performing anything\n");
2978 return WINED3D_OK;
2981 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2983 return WINED3D_OK;
2986 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2988 TRACE("(%p) : for idx %d\n", This, Index);
2990 /* Validate Index */
2991 if (Index >= GL_LIMITS(clipplanes)) {
2992 TRACE("Application has requested clipplane this device doesn't support\n");
2993 return WINED3DERR_INVALIDCALL;
2996 pPlane[0] = This->stateBlock->clipplane[Index][0];
2997 pPlane[1] = This->stateBlock->clipplane[Index][1];
2998 pPlane[2] = This->stateBlock->clipplane[Index][2];
2999 pPlane[3] = This->stateBlock->clipplane[Index][3];
3000 return WINED3D_OK;
3003 /*****
3004 * Get / Set Clip Plane Status
3005 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3006 *****/
3007 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3009 FIXME("(%p) : stub\n", This);
3010 if (NULL == pClipStatus) {
3011 return WINED3DERR_INVALIDCALL;
3013 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3014 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3015 return WINED3D_OK;
3018 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3020 FIXME("(%p) : stub\n", This);
3021 if (NULL == pClipStatus) {
3022 return WINED3DERR_INVALIDCALL;
3024 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3025 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3026 return WINED3D_OK;
3029 /*****
3030 * Get / Set Material
3031 *****/
3032 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3035 This->updateStateBlock->changed.material = TRUE;
3036 This->updateStateBlock->material = *pMaterial;
3038 /* Handle recording of state blocks */
3039 if (This->isRecordingState) {
3040 TRACE("Recording... not performing anything\n");
3041 return WINED3D_OK;
3044 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3045 return WINED3D_OK;
3048 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3050 *pMaterial = This->updateStateBlock->material;
3051 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3052 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3053 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3054 pMaterial->Ambient.b, pMaterial->Ambient.a);
3055 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3056 pMaterial->Specular.b, pMaterial->Specular.a);
3057 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3058 pMaterial->Emissive.b, pMaterial->Emissive.a);
3059 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3061 return WINED3D_OK;
3064 /*****
3065 * Get / Set Indices
3066 *****/
3067 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3069 IWineD3DIndexBuffer *oldIdxs;
3071 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3072 oldIdxs = This->updateStateBlock->pIndexData;
3074 This->updateStateBlock->changed.indices = TRUE;
3075 This->updateStateBlock->pIndexData = pIndexData;
3077 /* Handle recording of state blocks */
3078 if (This->isRecordingState) {
3079 TRACE("Recording... not performing anything\n");
3080 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3081 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3082 return WINED3D_OK;
3085 if(oldIdxs != pIndexData) {
3086 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3087 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3088 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3090 return WINED3D_OK;
3093 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3094 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3096 *ppIndexData = This->stateBlock->pIndexData;
3098 /* up ref count on ppindexdata */
3099 if (*ppIndexData) {
3100 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3101 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3102 }else{
3103 TRACE("(%p) No index data set\n", This);
3105 TRACE("Returning %p\n", *ppIndexData);
3107 return WINED3D_OK;
3110 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3111 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3113 TRACE("(%p)->(%d)\n", This, BaseIndex);
3115 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3116 TRACE("Application is setting the old value over, nothing to do\n");
3117 return WINED3D_OK;
3120 This->updateStateBlock->baseVertexIndex = BaseIndex;
3122 if (This->isRecordingState) {
3123 TRACE("Recording... not performing anything\n");
3124 return WINED3D_OK;
3126 /* The base vertex index affects the stream sources */
3127 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3128 return WINED3D_OK;
3131 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3133 TRACE("(%p) : base_index %p\n", This, base_index);
3135 *base_index = This->stateBlock->baseVertexIndex;
3137 TRACE("Returning %u\n", *base_index);
3139 return WINED3D_OK;
3142 /*****
3143 * Get / Set Viewports
3144 *****/
3145 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3148 TRACE("(%p)\n", This);
3149 This->updateStateBlock->changed.viewport = TRUE;
3150 This->updateStateBlock->viewport = *pViewport;
3152 /* Handle recording of state blocks */
3153 if (This->isRecordingState) {
3154 TRACE("Recording... not performing anything\n");
3155 return WINED3D_OK;
3158 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3159 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3161 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3162 return WINED3D_OK;
3166 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3168 TRACE("(%p)\n", This);
3169 *pViewport = This->stateBlock->viewport;
3170 return WINED3D_OK;
3173 /*****
3174 * Get / Set Render States
3175 * TODO: Verify against dx9 definitions
3176 *****/
3177 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3180 DWORD oldValue = This->stateBlock->renderState[State];
3182 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3184 This->updateStateBlock->changed.renderState[State] = TRUE;
3185 This->updateStateBlock->renderState[State] = Value;
3187 /* Handle recording of state blocks */
3188 if (This->isRecordingState) {
3189 TRACE("Recording... not performing anything\n");
3190 return WINED3D_OK;
3193 /* Compared here and not before the assignment to allow proper stateblock recording */
3194 if(Value == oldValue) {
3195 TRACE("Application is setting the old value over, nothing to do\n");
3196 } else {
3197 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3200 return WINED3D_OK;
3203 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3205 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3206 *pValue = This->stateBlock->renderState[State];
3207 return WINED3D_OK;
3210 /*****
3211 * Get / Set Sampler States
3212 * TODO: Verify against dx9 definitions
3213 *****/
3215 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3217 DWORD oldValue;
3219 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3220 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3222 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3223 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3226 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3227 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3228 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3231 * SetSampler is designed to allow for more than the standard up to 8 textures
3232 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3233 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3235 * http://developer.nvidia.com/object/General_FAQ.html#t6
3237 * There are two new settings for GForce
3238 * the sampler one:
3239 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3240 * and the texture one:
3241 * GL_MAX_TEXTURE_COORDS_ARB.
3242 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3243 ******************/
3245 oldValue = This->stateBlock->samplerState[Sampler][Type];
3246 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3247 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3249 /* Handle recording of state blocks */
3250 if (This->isRecordingState) {
3251 TRACE("Recording... not performing anything\n");
3252 return WINED3D_OK;
3255 if(oldValue == Value) {
3256 TRACE("Application is setting the old value over, nothing to do\n");
3257 return WINED3D_OK;
3260 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3262 return WINED3D_OK;
3265 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3268 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3269 This, Sampler, debug_d3dsamplerstate(Type), Type);
3271 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3272 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3275 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3276 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3277 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3279 *Value = This->stateBlock->samplerState[Sampler][Type];
3280 TRACE("(%p) : Returning %#x\n", This, *Value);
3282 return WINED3D_OK;
3285 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3288 This->updateStateBlock->changed.scissorRect = TRUE;
3289 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3290 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3291 return WINED3D_OK;
3293 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3295 if(This->isRecordingState) {
3296 TRACE("Recording... not performing anything\n");
3297 return WINED3D_OK;
3300 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3302 return WINED3D_OK;
3305 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3308 *pRect = This->updateStateBlock->scissorRect;
3309 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3310 return WINED3D_OK;
3313 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3315 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3317 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3319 This->updateStateBlock->vertexDecl = pDecl;
3320 This->updateStateBlock->changed.vertexDecl = TRUE;
3322 if (This->isRecordingState) {
3323 TRACE("Recording... not performing anything\n");
3324 return WINED3D_OK;
3325 } else if(pDecl == oldDecl) {
3326 /* Checked after the assignment to allow proper stateblock recording */
3327 TRACE("Application is setting the old declaration over, nothing to do\n");
3328 return WINED3D_OK;
3331 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3332 return WINED3D_OK;
3335 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3338 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3340 *ppDecl = This->stateBlock->vertexDecl;
3341 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3342 return WINED3D_OK;
3345 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3347 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3349 This->updateStateBlock->vertexShader = pShader;
3350 This->updateStateBlock->changed.vertexShader = TRUE;
3352 if (This->isRecordingState) {
3353 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3354 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3355 TRACE("Recording... not performing anything\n");
3356 return WINED3D_OK;
3357 } else if(oldShader == pShader) {
3358 /* Checked here to allow proper stateblock recording */
3359 TRACE("App is setting the old shader over, nothing to do\n");
3360 return WINED3D_OK;
3363 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3364 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3365 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3367 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3369 return WINED3D_OK;
3372 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3375 if (NULL == ppShader) {
3376 return WINED3DERR_INVALIDCALL;
3378 *ppShader = This->stateBlock->vertexShader;
3379 if( NULL != *ppShader)
3380 IWineD3DVertexShader_AddRef(*ppShader);
3382 TRACE("(%p) : returning %p\n", This, *ppShader);
3383 return WINED3D_OK;
3386 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3387 IWineD3DDevice *iface,
3388 UINT start,
3389 CONST BOOL *srcData,
3390 UINT count) {
3392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3393 int i, cnt = min(count, MAX_CONST_B - start);
3395 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3396 iface, srcData, start, count);
3398 if (srcData == NULL || cnt < 0)
3399 return WINED3DERR_INVALIDCALL;
3401 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3402 for (i = 0; i < cnt; i++)
3403 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3405 for (i = start; i < cnt + start; ++i) {
3406 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3409 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3411 return WINED3D_OK;
3414 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3415 IWineD3DDevice *iface,
3416 UINT start,
3417 BOOL *dstData,
3418 UINT count) {
3420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3421 int cnt = min(count, MAX_CONST_B - start);
3423 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3424 iface, dstData, start, count);
3426 if (dstData == NULL || cnt < 0)
3427 return WINED3DERR_INVALIDCALL;
3429 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3430 return WINED3D_OK;
3433 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3434 IWineD3DDevice *iface,
3435 UINT start,
3436 CONST int *srcData,
3437 UINT count) {
3439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3440 int i, cnt = min(count, MAX_CONST_I - start);
3442 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3443 iface, srcData, start, count);
3445 if (srcData == NULL || cnt < 0)
3446 return WINED3DERR_INVALIDCALL;
3448 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3449 for (i = 0; i < cnt; i++)
3450 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3451 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3453 for (i = start; i < cnt + start; ++i) {
3454 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3457 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3459 return WINED3D_OK;
3462 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3463 IWineD3DDevice *iface,
3464 UINT start,
3465 int *dstData,
3466 UINT count) {
3468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3469 int cnt = min(count, MAX_CONST_I - start);
3471 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3472 iface, dstData, start, count);
3474 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3475 return WINED3DERR_INVALIDCALL;
3477 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3478 return WINED3D_OK;
3481 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3482 IWineD3DDevice *iface,
3483 UINT start,
3484 CONST float *srcData,
3485 UINT count) {
3487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3488 int i;
3490 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3491 iface, srcData, start, count);
3493 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3494 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3495 return WINED3DERR_INVALIDCALL;
3497 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3498 if(TRACE_ON(d3d)) {
3499 for (i = 0; i < count; i++)
3500 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3501 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3504 for (i = start; i < count + start; ++i) {
3505 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3506 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3507 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3508 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3509 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3511 ptr->idx[ptr->count++] = i;
3512 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3516 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3518 return WINED3D_OK;
3521 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3522 IWineD3DDevice *iface,
3523 UINT start,
3524 CONST float *srcData,
3525 UINT count) {
3527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3528 int i;
3530 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3531 iface, srcData, start, count);
3533 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3534 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3535 return WINED3DERR_INVALIDCALL;
3537 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3538 if(TRACE_ON(d3d)) {
3539 for (i = 0; i < count; i++)
3540 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3541 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3544 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3545 * context. On a context switch the old context will be fully dirtified
3547 memset(This->activeContext->vshader_const_dirty + start, 1,
3548 sizeof(*This->activeContext->vshader_const_dirty) * count);
3549 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count);
3551 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3553 return WINED3D_OK;
3556 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3557 IWineD3DDevice *iface,
3558 UINT start,
3559 float *dstData,
3560 UINT count) {
3562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3563 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3565 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3566 iface, dstData, start, count);
3568 if (dstData == NULL || cnt < 0)
3569 return WINED3DERR_INVALIDCALL;
3571 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3572 return WINED3D_OK;
3575 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3576 DWORD i;
3577 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3578 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3582 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3583 int i = This->rev_tex_unit_map[unit];
3584 int j = This->texUnitMap[stage];
3586 This->texUnitMap[stage] = unit;
3587 if (i != -1 && i != stage) {
3588 This->texUnitMap[i] = -1;
3591 This->rev_tex_unit_map[unit] = stage;
3592 if (j != -1 && j != unit) {
3593 This->rev_tex_unit_map[j] = -1;
3597 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3598 int i;
3600 for (i = 0; i < MAX_TEXTURES; ++i) {
3601 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3602 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3603 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3604 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3605 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3606 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3607 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3608 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3610 if (color_op == WINED3DTOP_DISABLE) {
3611 /* Not used, and disable higher stages */
3612 while (i < MAX_TEXTURES) {
3613 This->fixed_function_usage_map[i] = FALSE;
3614 ++i;
3616 break;
3619 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3620 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3621 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3622 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3623 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3624 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3625 This->fixed_function_usage_map[i] = TRUE;
3626 } else {
3627 This->fixed_function_usage_map[i] = FALSE;
3630 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3631 This->fixed_function_usage_map[i+1] = TRUE;
3636 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3637 int i, tex;
3639 device_update_fixed_function_usage_map(This);
3641 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3642 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3643 if (!This->fixed_function_usage_map[i]) continue;
3645 if (This->texUnitMap[i] != i) {
3646 device_map_stage(This, i, i);
3647 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3648 markTextureStagesDirty(This, i);
3651 return;
3654 /* Now work out the mapping */
3655 tex = 0;
3656 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3657 if (!This->fixed_function_usage_map[i]) continue;
3659 if (This->texUnitMap[i] != tex) {
3660 device_map_stage(This, i, tex);
3661 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3662 markTextureStagesDirty(This, i);
3665 ++tex;
3669 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3670 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3671 int i;
3673 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3674 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3675 device_map_stage(This, i, i);
3676 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3677 if (i < MAX_TEXTURES) {
3678 markTextureStagesDirty(This, i);
3684 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3685 int current_mapping = This->rev_tex_unit_map[unit];
3687 if (current_mapping == -1) {
3688 /* Not currently used */
3689 return TRUE;
3692 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3693 /* Used by a fragment sampler */
3695 if (!pshader_sampler_tokens) {
3696 /* No pixel shader, check fixed function */
3697 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3700 /* Pixel shader, check the shader's sampler map */
3701 return !pshader_sampler_tokens[current_mapping];
3704 /* Used by a vertex sampler */
3705 return !vshader_sampler_tokens[current_mapping];
3708 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3709 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3710 DWORD *pshader_sampler_tokens = NULL;
3711 int start = GL_LIMITS(combined_samplers) - 1;
3712 int i;
3714 if (ps) {
3715 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3717 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3718 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3719 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3722 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3723 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3724 if (vshader_sampler_tokens[i]) {
3725 if (This->texUnitMap[vsampler_idx] != -1) {
3726 /* Already mapped somewhere */
3727 continue;
3730 while (start >= 0) {
3731 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3732 device_map_stage(This, vsampler_idx, start);
3733 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3735 --start;
3736 break;
3739 --start;
3745 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3746 BOOL vs = use_vs(This);
3747 BOOL ps = use_ps(This);
3749 * Rules are:
3750 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3751 * that would be really messy and require shader recompilation
3752 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3753 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3755 if (ps) {
3756 device_map_psamplers(This);
3757 } else {
3758 device_map_fixed_function_samplers(This);
3761 if (vs) {
3762 device_map_vsamplers(This, ps);
3766 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3768 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3769 This->updateStateBlock->pixelShader = pShader;
3770 This->updateStateBlock->changed.pixelShader = TRUE;
3772 /* Handle recording of state blocks */
3773 if (This->isRecordingState) {
3774 TRACE("Recording... not performing anything\n");
3777 if (This->isRecordingState) {
3778 TRACE("Recording... not performing anything\n");
3779 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3780 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3781 return WINED3D_OK;
3784 if(pShader == oldShader) {
3785 TRACE("App is setting the old pixel shader over, nothing to do\n");
3786 return WINED3D_OK;
3789 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3790 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3792 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3793 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3795 return WINED3D_OK;
3798 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3801 if (NULL == ppShader) {
3802 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3803 return WINED3DERR_INVALIDCALL;
3806 *ppShader = This->stateBlock->pixelShader;
3807 if (NULL != *ppShader) {
3808 IWineD3DPixelShader_AddRef(*ppShader);
3810 TRACE("(%p) : returning %p\n", This, *ppShader);
3811 return WINED3D_OK;
3814 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3815 IWineD3DDevice *iface,
3816 UINT start,
3817 CONST BOOL *srcData,
3818 UINT count) {
3820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3821 int i, cnt = min(count, MAX_CONST_B - start);
3823 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3824 iface, srcData, start, count);
3826 if (srcData == NULL || cnt < 0)
3827 return WINED3DERR_INVALIDCALL;
3829 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3830 for (i = 0; i < cnt; i++)
3831 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3833 for (i = start; i < cnt + start; ++i) {
3834 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3837 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3839 return WINED3D_OK;
3842 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3843 IWineD3DDevice *iface,
3844 UINT start,
3845 BOOL *dstData,
3846 UINT count) {
3848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3849 int cnt = min(count, MAX_CONST_B - start);
3851 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3852 iface, dstData, start, count);
3854 if (dstData == NULL || cnt < 0)
3855 return WINED3DERR_INVALIDCALL;
3857 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3858 return WINED3D_OK;
3861 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3862 IWineD3DDevice *iface,
3863 UINT start,
3864 CONST int *srcData,
3865 UINT count) {
3867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3868 int i, cnt = min(count, MAX_CONST_I - start);
3870 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3871 iface, srcData, start, count);
3873 if (srcData == NULL || cnt < 0)
3874 return WINED3DERR_INVALIDCALL;
3876 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3877 for (i = 0; i < cnt; i++)
3878 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3879 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3881 for (i = start; i < cnt + start; ++i) {
3882 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3885 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3887 return WINED3D_OK;
3890 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3891 IWineD3DDevice *iface,
3892 UINT start,
3893 int *dstData,
3894 UINT count) {
3896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3897 int cnt = min(count, MAX_CONST_I - start);
3899 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3900 iface, dstData, start, count);
3902 if (dstData == NULL || cnt < 0)
3903 return WINED3DERR_INVALIDCALL;
3905 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3906 return WINED3D_OK;
3909 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3910 IWineD3DDevice *iface,
3911 UINT start,
3912 CONST float *srcData,
3913 UINT count) {
3915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3916 int i;
3918 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3919 iface, srcData, start, count);
3921 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3922 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3923 return WINED3DERR_INVALIDCALL;
3925 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3926 if(TRACE_ON(d3d)) {
3927 for (i = 0; i < count; i++)
3928 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3929 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3932 for (i = start; i < count + start; ++i) {
3933 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3934 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3935 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3936 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3937 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3939 ptr->idx[ptr->count++] = i;
3940 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3944 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3946 return WINED3D_OK;
3949 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
3950 IWineD3DDevice *iface,
3951 UINT start,
3952 CONST float *srcData,
3953 UINT count) {
3955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3956 int i;
3958 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3959 iface, srcData, start, count);
3961 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3962 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3963 return WINED3DERR_INVALIDCALL;
3965 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3966 if(TRACE_ON(d3d)) {
3967 for (i = 0; i < count; i++)
3968 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3969 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3972 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3973 * context. On a context switch the old context will be fully dirtified
3975 memset(This->activeContext->pshader_const_dirty + start, 1,
3976 sizeof(*This->activeContext->pshader_const_dirty) * count);
3977 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count);
3979 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3981 return WINED3D_OK;
3984 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3985 IWineD3DDevice *iface,
3986 UINT start,
3987 float *dstData,
3988 UINT count) {
3990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3991 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3993 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3994 iface, dstData, start, count);
3996 if (dstData == NULL || cnt < 0)
3997 return WINED3DERR_INVALIDCALL;
3999 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4000 return WINED3D_OK;
4003 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4004 static HRESULT
4005 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4006 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4007 unsigned int i;
4008 DWORD DestFVF = dest->fvf;
4009 WINED3DVIEWPORT vp;
4010 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4011 BOOL doClip;
4012 int numTextures;
4014 if (lpStrideData->u.s.normal.lpData) {
4015 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4018 if (lpStrideData->u.s.position.lpData == NULL) {
4019 ERR("Source has no position mask\n");
4020 return WINED3DERR_INVALIDCALL;
4023 /* We might access VBOs from this code, so hold the lock */
4024 ENTER_GL();
4026 if (dest->resource.allocatedMemory == NULL) {
4027 /* This may happen if we do direct locking into a vbo. Unlikely,
4028 * but theoretically possible(ddraw processvertices test)
4030 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4031 if(!dest->resource.allocatedMemory) {
4032 LEAVE_GL();
4033 ERR("Out of memory\n");
4034 return E_OUTOFMEMORY;
4036 if(dest->vbo) {
4037 void *src;
4038 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4039 checkGLcall("glBindBufferARB");
4040 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4041 if(src) {
4042 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4044 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4045 checkGLcall("glUnmapBufferARB");
4049 /* Get a pointer into the destination vbo(create one if none exists) and
4050 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4052 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4053 dest->Flags |= VBFLAG_CREATEVBO;
4054 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4057 if(dest->vbo) {
4058 unsigned char extrabytes = 0;
4059 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4060 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4061 * this may write 4 extra bytes beyond the area that should be written
4063 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4064 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4065 if(!dest_conv_addr) {
4066 ERR("Out of memory\n");
4067 /* Continue without storing converted vertices */
4069 dest_conv = dest_conv_addr;
4072 /* Should I clip?
4073 * a) WINED3DRS_CLIPPING is enabled
4074 * b) WINED3DVOP_CLIP is passed
4076 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4077 static BOOL warned = FALSE;
4079 * The clipping code is not quite correct. Some things need
4080 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4081 * so disable clipping for now.
4082 * (The graphics in Half-Life are broken, and my processvertices
4083 * test crashes with IDirect3DDevice3)
4084 doClip = TRUE;
4086 doClip = FALSE;
4087 if(!warned) {
4088 warned = TRUE;
4089 FIXME("Clipping is broken and disabled for now\n");
4091 } else doClip = FALSE;
4092 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4094 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4095 WINED3DTS_VIEW,
4096 &view_mat);
4097 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4098 WINED3DTS_PROJECTION,
4099 &proj_mat);
4100 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4101 WINED3DTS_WORLDMATRIX(0),
4102 &world_mat);
4104 TRACE("View mat:\n");
4105 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);
4106 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);
4107 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);
4108 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);
4110 TRACE("Proj mat:\n");
4111 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);
4112 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);
4113 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);
4114 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);
4116 TRACE("World mat:\n");
4117 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);
4118 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);
4119 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);
4120 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);
4122 /* Get the viewport */
4123 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4124 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4125 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4127 multiply_matrix(&mat,&view_mat,&world_mat);
4128 multiply_matrix(&mat,&proj_mat,&mat);
4130 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4132 for (i = 0; i < dwCount; i+= 1) {
4133 unsigned int tex_index;
4135 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4136 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4137 /* The position first */
4138 float *p =
4139 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4140 float x, y, z, rhw;
4141 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4143 /* Multiplication with world, view and projection matrix */
4144 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);
4145 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);
4146 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);
4147 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);
4149 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4151 /* WARNING: The following things are taken from d3d7 and were not yet checked
4152 * against d3d8 or d3d9!
4155 /* Clipping conditions: From msdn
4157 * A vertex is clipped if it does not match the following requirements
4158 * -rhw < x <= rhw
4159 * -rhw < y <= rhw
4160 * 0 < z <= rhw
4161 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4163 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4164 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4168 if( !doClip ||
4169 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4170 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4171 ( rhw > eps ) ) ) {
4173 /* "Normal" viewport transformation (not clipped)
4174 * 1) The values are divided by rhw
4175 * 2) The y axis is negative, so multiply it with -1
4176 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4177 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4178 * 4) Multiply x with Width/2 and add Width/2
4179 * 5) The same for the height
4180 * 6) Add the viewpoint X and Y to the 2D coordinates and
4181 * The minimum Z value to z
4182 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4184 * Well, basically it's simply a linear transformation into viewport
4185 * coordinates
4188 x /= rhw;
4189 y /= rhw;
4190 z /= rhw;
4192 y *= -1;
4194 x *= vp.Width / 2;
4195 y *= vp.Height / 2;
4196 z *= vp.MaxZ - vp.MinZ;
4198 x += vp.Width / 2 + vp.X;
4199 y += vp.Height / 2 + vp.Y;
4200 z += vp.MinZ;
4202 rhw = 1 / rhw;
4203 } else {
4204 /* That vertex got clipped
4205 * Contrary to OpenGL it is not dropped completely, it just
4206 * undergoes a different calculation.
4208 TRACE("Vertex got clipped\n");
4209 x += rhw;
4210 y += rhw;
4212 x /= 2;
4213 y /= 2;
4215 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4216 * outside of the main vertex buffer memory. That needs some more
4217 * investigation...
4221 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4224 ( (float *) dest_ptr)[0] = x;
4225 ( (float *) dest_ptr)[1] = y;
4226 ( (float *) dest_ptr)[2] = z;
4227 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4229 dest_ptr += 3 * sizeof(float);
4231 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4232 dest_ptr += sizeof(float);
4235 if(dest_conv) {
4236 float w = 1 / rhw;
4237 ( (float *) dest_conv)[0] = x * w;
4238 ( (float *) dest_conv)[1] = y * w;
4239 ( (float *) dest_conv)[2] = z * w;
4240 ( (float *) dest_conv)[3] = w;
4242 dest_conv += 3 * sizeof(float);
4244 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4245 dest_conv += sizeof(float);
4249 if (DestFVF & WINED3DFVF_PSIZE) {
4250 dest_ptr += sizeof(DWORD);
4251 if(dest_conv) dest_conv += sizeof(DWORD);
4253 if (DestFVF & WINED3DFVF_NORMAL) {
4254 float *normal =
4255 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4256 /* AFAIK this should go into the lighting information */
4257 FIXME("Didn't expect the destination to have a normal\n");
4258 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4259 if(dest_conv) {
4260 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4264 if (DestFVF & WINED3DFVF_DIFFUSE) {
4265 DWORD *color_d =
4266 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4267 if(!color_d) {
4268 static BOOL warned = FALSE;
4270 if(!warned) {
4271 ERR("No diffuse color in source, but destination has one\n");
4272 warned = TRUE;
4275 *( (DWORD *) dest_ptr) = 0xffffffff;
4276 dest_ptr += sizeof(DWORD);
4278 if(dest_conv) {
4279 *( (DWORD *) dest_conv) = 0xffffffff;
4280 dest_conv += sizeof(DWORD);
4283 else {
4284 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4285 if(dest_conv) {
4286 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4287 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4288 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4289 dest_conv += sizeof(DWORD);
4294 if (DestFVF & WINED3DFVF_SPECULAR) {
4295 /* What's the color value in the feedback buffer? */
4296 DWORD *color_s =
4297 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4298 if(!color_s) {
4299 static BOOL warned = FALSE;
4301 if(!warned) {
4302 ERR("No specular color in source, but destination has one\n");
4303 warned = TRUE;
4306 *( (DWORD *) dest_ptr) = 0xFF000000;
4307 dest_ptr += sizeof(DWORD);
4309 if(dest_conv) {
4310 *( (DWORD *) dest_conv) = 0xFF000000;
4311 dest_conv += sizeof(DWORD);
4314 else {
4315 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4316 if(dest_conv) {
4317 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4318 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4319 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4320 dest_conv += sizeof(DWORD);
4325 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4326 float *tex_coord =
4327 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4328 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4329 if(!tex_coord) {
4330 ERR("No source texture, but destination requests one\n");
4331 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4332 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4334 else {
4335 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4336 if(dest_conv) {
4337 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4343 if(dest_conv) {
4344 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4345 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4346 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4347 dwCount * get_flexible_vertex_size(DestFVF),
4348 dest_conv_addr));
4349 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4350 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4353 LEAVE_GL();
4355 return WINED3D_OK;
4357 #undef copy_and_next
4359 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4361 WineDirect3DVertexStridedData strided;
4362 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4363 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4365 if(pVertexDecl) {
4366 ERR("Output vertex declaration not implemented yet\n");
4369 /* Need any context to write to the vbo. */
4370 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4372 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4373 * control the streamIsUP flag, thus restore it afterwards.
4375 This->stateBlock->streamIsUP = FALSE;
4376 memset(&strided, 0, sizeof(strided));
4377 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4378 This->stateBlock->streamIsUP = streamWasUP;
4380 if(vbo || SrcStartIndex) {
4381 unsigned int i;
4382 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4383 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4385 * Also get the start index in, but only loop over all elements if there's something to add at all.
4387 #define FIXSRC(type) \
4388 if(strided.u.s.type.VBO) { \
4389 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4390 strided.u.s.type.VBO = 0; \
4391 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4392 ENTER_GL(); \
4393 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4394 vb->vbo = 0; \
4395 LEAVE_GL(); \
4397 if(strided.u.s.type.lpData) { \
4398 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4400 FIXSRC(position);
4401 FIXSRC(blendWeights);
4402 FIXSRC(blendMatrixIndices);
4403 FIXSRC(normal);
4404 FIXSRC(pSize);
4405 FIXSRC(diffuse);
4406 FIXSRC(specular);
4407 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4408 FIXSRC(texCoords[i]);
4410 FIXSRC(position2);
4411 FIXSRC(normal2);
4412 FIXSRC(tangent);
4413 FIXSRC(binormal);
4414 FIXSRC(tessFactor);
4415 FIXSRC(fog);
4416 FIXSRC(depth);
4417 FIXSRC(sample);
4418 #undef FIXSRC
4421 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4424 /*****
4425 * Get / Set Texture Stage States
4426 * TODO: Verify against dx9 definitions
4427 *****/
4428 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4430 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4432 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4434 if (Stage >= MAX_TEXTURES) {
4435 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4436 return WINED3D_OK;
4439 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4440 This->updateStateBlock->textureState[Stage][Type] = Value;
4442 if (This->isRecordingState) {
4443 TRACE("Recording... not performing anything\n");
4444 return WINED3D_OK;
4447 /* Checked after the assignments to allow proper stateblock recording */
4448 if(oldValue == Value) {
4449 TRACE("App is setting the old value over, nothing to do\n");
4450 return WINED3D_OK;
4453 if(Stage > This->stateBlock->lowest_disabled_stage &&
4454 This->shader_backend->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4455 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4456 * Changes in other states are important on disabled stages too
4458 return WINED3D_OK;
4461 if(Type == WINED3DTSS_COLOROP) {
4462 int i;
4464 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4465 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4466 * they have to be disabled
4468 * The current stage is dirtified below.
4470 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4471 TRACE("Additionally dirtifying stage %d\n", i);
4472 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4474 This->stateBlock->lowest_disabled_stage = Stage;
4475 TRACE("New lowest disabled: %d\n", Stage);
4476 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4477 /* Previously disabled stage enabled. Stages above it may need enabling
4478 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4479 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4481 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4484 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4485 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4486 break;
4488 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4489 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4491 This->stateBlock->lowest_disabled_stage = i;
4492 TRACE("New lowest disabled: %d\n", i);
4494 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4495 /* TODO: Built a stage -> texture unit mapping for register combiners */
4499 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4501 return WINED3D_OK;
4504 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4506 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4507 *pValue = This->updateStateBlock->textureState[Stage][Type];
4508 return WINED3D_OK;
4511 /*****
4512 * Get / Set Texture
4513 *****/
4514 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4516 IWineD3DBaseTexture *oldTexture;
4518 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4520 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4521 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4524 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4525 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4526 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4529 oldTexture = This->updateStateBlock->textures[Stage];
4531 if(pTexture != NULL) {
4532 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4534 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4535 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4536 return WINED3DERR_INVALIDCALL;
4538 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4541 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4542 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4544 This->updateStateBlock->changed.textures[Stage] = TRUE;
4545 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4546 This->updateStateBlock->textures[Stage] = pTexture;
4548 /* Handle recording of state blocks */
4549 if (This->isRecordingState) {
4550 TRACE("Recording... not performing anything\n");
4551 return WINED3D_OK;
4554 if(oldTexture == pTexture) {
4555 TRACE("App is setting the same texture again, nothing to do\n");
4556 return WINED3D_OK;
4559 /** NOTE: MSDN says that setTexture increases the reference count,
4560 * and that the application must set the texture back to null (or have a leaky application),
4561 * This means we should pass the refcount up to the parent
4562 *******************************/
4563 if (NULL != This->updateStateBlock->textures[Stage]) {
4564 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4565 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4567 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4568 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4569 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4570 * so the COLOROP and ALPHAOP have to be dirtified.
4572 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4573 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4575 if(bindCount == 1) {
4576 new->baseTexture.sampler = Stage;
4578 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4582 if (NULL != oldTexture) {
4583 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4584 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4586 IWineD3DBaseTexture_Release(oldTexture);
4587 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4588 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4589 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4592 if(bindCount && old->baseTexture.sampler == Stage) {
4593 int i;
4594 /* Have to do a search for the other sampler(s) where the texture is bound to
4595 * Shouldn't happen as long as apps bind a texture only to one stage
4597 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4598 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4599 if(This->updateStateBlock->textures[i] == oldTexture) {
4600 old->baseTexture.sampler = i;
4601 break;
4607 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4609 return WINED3D_OK;
4612 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4615 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4617 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4618 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4621 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4622 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4623 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4626 *ppTexture=This->stateBlock->textures[Stage];
4627 if (*ppTexture)
4628 IWineD3DBaseTexture_AddRef(*ppTexture);
4630 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4632 return WINED3D_OK;
4635 /*****
4636 * Get Back Buffer
4637 *****/
4638 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4639 IWineD3DSurface **ppBackBuffer) {
4640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4641 IWineD3DSwapChain *swapChain;
4642 HRESULT hr;
4644 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4646 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4647 if (hr == WINED3D_OK) {
4648 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4649 IWineD3DSwapChain_Release(swapChain);
4650 } else {
4651 *ppBackBuffer = NULL;
4653 return hr;
4656 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4658 WARN("(%p) : stub, calling idirect3d for now\n", This);
4659 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4662 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4664 IWineD3DSwapChain *swapChain;
4665 HRESULT hr;
4667 if(iSwapChain > 0) {
4668 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4669 if (hr == WINED3D_OK) {
4670 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4671 IWineD3DSwapChain_Release(swapChain);
4672 } else {
4673 FIXME("(%p) Error getting display mode\n", This);
4675 } else {
4676 /* Don't read the real display mode,
4677 but return the stored mode instead. X11 can't change the color
4678 depth, and some apps are pretty angry if they SetDisplayMode from
4679 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4681 Also don't relay to the swapchain because with ddraw it's possible
4682 that there isn't a swapchain at all */
4683 pMode->Width = This->ddraw_width;
4684 pMode->Height = This->ddraw_height;
4685 pMode->Format = This->ddraw_format;
4686 pMode->RefreshRate = 0;
4687 hr = WINED3D_OK;
4690 return hr;
4693 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4695 TRACE("(%p)->(%p)\n", This, hWnd);
4697 if(This->ddraw_fullscreen) {
4698 if(This->ddraw_window && This->ddraw_window != hWnd) {
4699 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4701 if(hWnd && This->ddraw_window != hWnd) {
4702 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4706 This->ddraw_window = hWnd;
4707 return WINED3D_OK;
4710 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4712 TRACE("(%p)->(%p)\n", This, hWnd);
4714 *hWnd = This->ddraw_window;
4715 return WINED3D_OK;
4718 /*****
4719 * Stateblock related functions
4720 *****/
4722 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4724 IWineD3DStateBlockImpl *object;
4725 HRESULT temp_result;
4726 int i;
4728 TRACE("(%p)\n", This);
4730 if (This->isRecordingState) {
4731 return WINED3DERR_INVALIDCALL;
4734 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4735 if (NULL == object ) {
4736 FIXME("(%p)Error allocating memory for stateblock\n", This);
4737 return E_OUTOFMEMORY;
4739 TRACE("(%p) created object %p\n", This, object);
4740 object->wineD3DDevice= This;
4741 /** FIXME: object->parent = parent; **/
4742 object->parent = NULL;
4743 object->blockType = WINED3DSBT_RECORDED;
4744 object->ref = 1;
4745 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4747 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4748 list_init(&object->lightMap[i]);
4751 temp_result = allocate_shader_constants(object);
4752 if (WINED3D_OK != temp_result)
4753 return temp_result;
4755 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4756 This->updateStateBlock = object;
4757 This->isRecordingState = TRUE;
4759 TRACE("(%p) recording stateblock %p\n",This , object);
4760 return WINED3D_OK;
4763 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4765 unsigned int i, j;
4766 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4768 if (!This->isRecordingState) {
4769 FIXME("(%p) not recording! returning error\n", This);
4770 *ppStateBlock = NULL;
4771 return WINED3DERR_INVALIDCALL;
4774 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4775 if(object->changed.renderState[i]) {
4776 object->contained_render_states[object->num_contained_render_states] = i;
4777 object->num_contained_render_states++;
4780 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4781 if(object->changed.transform[i]) {
4782 object->contained_transform_states[object->num_contained_transform_states] = i;
4783 object->num_contained_transform_states++;
4786 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4787 if(object->changed.vertexShaderConstantsF[i]) {
4788 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4789 object->num_contained_vs_consts_f++;
4792 for(i = 0; i < MAX_CONST_I; i++) {
4793 if(object->changed.vertexShaderConstantsI[i]) {
4794 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4795 object->num_contained_vs_consts_i++;
4798 for(i = 0; i < MAX_CONST_B; i++) {
4799 if(object->changed.vertexShaderConstantsB[i]) {
4800 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4801 object->num_contained_vs_consts_b++;
4804 for(i = 0; i < MAX_CONST_I; i++) {
4805 if(object->changed.pixelShaderConstantsI[i]) {
4806 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4807 object->num_contained_ps_consts_i++;
4810 for(i = 0; i < MAX_CONST_B; i++) {
4811 if(object->changed.pixelShaderConstantsB[i]) {
4812 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4813 object->num_contained_ps_consts_b++;
4816 for(i = 0; i < MAX_TEXTURES; i++) {
4817 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4818 if(object->changed.textureState[i][j]) {
4819 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4820 object->contained_tss_states[object->num_contained_tss_states].state = j;
4821 object->num_contained_tss_states++;
4825 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4826 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4827 if(object->changed.samplerState[i][j]) {
4828 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4829 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4830 object->num_contained_sampler_states++;
4835 *ppStateBlock = (IWineD3DStateBlock*) object;
4836 This->isRecordingState = FALSE;
4837 This->updateStateBlock = This->stateBlock;
4838 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4839 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4840 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4841 return WINED3D_OK;
4844 /*****
4845 * Scene related functions
4846 *****/
4847 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4848 /* At the moment we have no need for any functionality at the beginning
4849 of a scene */
4850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4851 TRACE("(%p)\n", This);
4853 if(This->inScene) {
4854 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4855 return WINED3DERR_INVALIDCALL;
4857 This->inScene = TRUE;
4858 return WINED3D_OK;
4861 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4863 TRACE("(%p)\n", This);
4865 if(!This->inScene) {
4866 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4867 return WINED3DERR_INVALIDCALL;
4870 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4871 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4872 ENTER_GL();
4873 glFlush();
4874 checkGLcall("glFlush");
4875 LEAVE_GL();
4877 This->inScene = FALSE;
4878 return WINED3D_OK;
4881 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4882 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4883 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4885 IWineD3DSwapChain *swapChain = NULL;
4886 int i;
4887 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4889 TRACE("(%p) Presenting the frame\n", This);
4891 for(i = 0 ; i < swapchains ; i ++) {
4893 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4894 TRACE("presentinng chain %d, %p\n", i, swapChain);
4895 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4896 IWineD3DSwapChain_Release(swapChain);
4899 return WINED3D_OK;
4902 /* Not called from the VTable (internal subroutine) */
4903 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4904 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4905 float Z, DWORD Stencil) {
4906 GLbitfield glMask = 0;
4907 unsigned int i;
4908 WINED3DRECT curRect;
4909 RECT vp_rect;
4910 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4911 UINT drawable_width, drawable_height;
4912 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4914 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4915 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4916 * for the cleared parts, and the untouched parts.
4918 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4919 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4920 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4921 * checking all this if the dest surface is in the drawable anyway.
4923 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4924 while(1) {
4925 if(vp->X != 0 || vp->Y != 0 ||
4926 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4927 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4928 break;
4930 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4931 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4932 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4933 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4934 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4935 break;
4937 if(Count > 0 && pRects && (
4938 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4939 pRects[0].x2 < target->currentDesc.Width ||
4940 pRects[0].y2 < target->currentDesc.Height)) {
4941 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4942 break;
4944 break;
4948 target->get_drawable_size(target, &drawable_width, &drawable_height);
4950 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4951 ENTER_GL();
4953 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4954 apply_fbo_state((IWineD3DDevice *) This);
4957 /* Only set the values up once, as they are not changing */
4958 if (Flags & WINED3DCLEAR_STENCIL) {
4959 glClearStencil(Stencil);
4960 checkGLcall("glClearStencil");
4961 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4962 glStencilMask(0xFFFFFFFF);
4965 if (Flags & WINED3DCLEAR_ZBUFFER) {
4966 glDepthMask(GL_TRUE);
4967 glClearDepth(Z);
4968 checkGLcall("glClearDepth");
4969 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4970 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4972 if(This->depth_copy_state == WINED3D_DCS_COPY) {
4973 if(vp->X != 0 || vp->Y != 0 ||
4974 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4975 depth_copy((IWineD3DDevice *) This);
4977 else if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4978 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4979 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4980 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4981 depth_copy((IWineD3DDevice *) This);
4983 else if(Count > 0 && pRects && (
4984 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4985 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4986 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4987 depth_copy((IWineD3DDevice *) This);
4990 This->depth_copy_state = WINED3D_DCS_INITIAL;
4993 if (Flags & WINED3DCLEAR_TARGET) {
4994 TRACE("Clearing screen with glClear to color %x\n", Color);
4995 glClearColor(D3DCOLOR_R(Color),
4996 D3DCOLOR_G(Color),
4997 D3DCOLOR_B(Color),
4998 D3DCOLOR_A(Color));
4999 checkGLcall("glClearColor");
5001 /* Clear ALL colors! */
5002 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5003 glMask = glMask | GL_COLOR_BUFFER_BIT;
5006 vp_rect.left = vp->X;
5007 vp_rect.top = vp->Y;
5008 vp_rect.right = vp->X + vp->Width;
5009 vp_rect.bottom = vp->Y + vp->Height;
5010 if (!(Count > 0 && pRects)) {
5011 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5012 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5014 if(This->render_offscreen) {
5015 glScissor(vp_rect.left, vp_rect.top,
5016 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5017 } else {
5018 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5019 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5021 checkGLcall("glScissor");
5022 glClear(glMask);
5023 checkGLcall("glClear");
5024 } else {
5025 /* Now process each rect in turn */
5026 for (i = 0; i < Count; i++) {
5027 /* Note gl uses lower left, width/height */
5028 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5029 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5030 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5032 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5033 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5034 curRect.x1, (target->currentDesc.Height - curRect.y2),
5035 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5037 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5038 * The rectangle is not cleared, no error is returned, but further rectanlges are
5039 * still cleared if they are valid
5041 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5042 TRACE("Rectangle with negative dimensions, ignoring\n");
5043 continue;
5046 if(This->render_offscreen) {
5047 glScissor(curRect.x1, curRect.y1,
5048 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5049 } else {
5050 glScissor(curRect.x1, drawable_height - curRect.y2,
5051 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5053 checkGLcall("glScissor");
5055 glClear(glMask);
5056 checkGLcall("glClear");
5060 /* Restore the old values (why..?) */
5061 if (Flags & WINED3DCLEAR_STENCIL) {
5062 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5064 if (Flags & WINED3DCLEAR_TARGET) {
5065 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5066 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5067 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5068 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5069 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5071 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5072 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5074 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5075 /* TODO: Move the fbo logic into ModifyLocation() */
5076 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5077 target->Flags |= SFLAG_INTEXTURE;
5080 LEAVE_GL();
5082 return WINED3D_OK;
5085 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5086 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5088 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5090 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5091 Count, pRects, Flags, Color, Z, Stencil);
5093 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5094 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5095 /* TODO: What about depth stencil buffers without stencil bits? */
5096 return WINED3DERR_INVALIDCALL;
5099 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5102 /*****
5103 * Drawing functions
5104 *****/
5105 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5106 UINT PrimitiveCount) {
5108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5110 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5111 debug_d3dprimitivetype(PrimitiveType),
5112 StartVertex, PrimitiveCount);
5114 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5115 if(This->stateBlock->streamIsUP) {
5116 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5117 This->stateBlock->streamIsUP = FALSE;
5120 if(This->stateBlock->loadBaseVertexIndex != 0) {
5121 This->stateBlock->loadBaseVertexIndex = 0;
5122 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5124 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5125 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5126 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5127 return WINED3D_OK;
5130 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5131 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5132 WINED3DPRIMITIVETYPE PrimitiveType,
5133 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5136 UINT idxStride = 2;
5137 IWineD3DIndexBuffer *pIB;
5138 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5139 GLuint vbo;
5141 pIB = This->stateBlock->pIndexData;
5142 if (!pIB) {
5143 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5144 * without an index buffer set. (The first time at least...)
5145 * D3D8 simply dies, but I doubt it can do much harm to return
5146 * D3DERR_INVALIDCALL there as well. */
5147 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5148 return WINED3DERR_INVALIDCALL;
5151 if(This->stateBlock->streamIsUP) {
5152 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5153 This->stateBlock->streamIsUP = FALSE;
5155 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5157 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5158 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5159 minIndex, NumVertices, startIndex, primCount);
5161 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5162 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5163 idxStride = 2;
5164 } else {
5165 idxStride = 4;
5168 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5169 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5170 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5173 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5174 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5176 return WINED3D_OK;
5179 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5180 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5181 UINT VertexStreamZeroStride) {
5182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5183 IWineD3DVertexBuffer *vb;
5185 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5186 debug_d3dprimitivetype(PrimitiveType),
5187 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5189 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5190 vb = This->stateBlock->streamSource[0];
5191 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5192 if(vb) IWineD3DVertexBuffer_Release(vb);
5193 This->stateBlock->streamOffset[0] = 0;
5194 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5195 This->stateBlock->streamIsUP = TRUE;
5196 This->stateBlock->loadBaseVertexIndex = 0;
5198 /* TODO: Only mark dirty if drawing from a different UP address */
5199 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5201 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5202 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5204 /* MSDN specifies stream zero settings must be set to NULL */
5205 This->stateBlock->streamStride[0] = 0;
5206 This->stateBlock->streamSource[0] = NULL;
5208 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5209 * the new stream sources or use UP drawing again
5211 return WINED3D_OK;
5214 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5215 UINT MinVertexIndex, UINT NumVertices,
5216 UINT PrimitiveCount, CONST void* pIndexData,
5217 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5218 UINT VertexStreamZeroStride) {
5219 int idxStride;
5220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5221 IWineD3DVertexBuffer *vb;
5222 IWineD3DIndexBuffer *ib;
5224 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5225 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5226 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5227 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5229 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5230 idxStride = 2;
5231 } else {
5232 idxStride = 4;
5235 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5236 vb = This->stateBlock->streamSource[0];
5237 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5238 if(vb) IWineD3DVertexBuffer_Release(vb);
5239 This->stateBlock->streamIsUP = TRUE;
5240 This->stateBlock->streamOffset[0] = 0;
5241 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5243 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5244 This->stateBlock->baseVertexIndex = 0;
5245 This->stateBlock->loadBaseVertexIndex = 0;
5246 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5247 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5248 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5250 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5252 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5253 This->stateBlock->streamSource[0] = NULL;
5254 This->stateBlock->streamStride[0] = 0;
5255 ib = This->stateBlock->pIndexData;
5256 if(ib) {
5257 IWineD3DIndexBuffer_Release(ib);
5258 This->stateBlock->pIndexData = NULL;
5260 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5261 * SetStreamSource to specify a vertex buffer
5264 return WINED3D_OK;
5267 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5270 /* Mark the state dirty until we have nicer tracking
5271 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5272 * that value.
5274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5275 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5276 This->stateBlock->baseVertexIndex = 0;
5277 This->up_strided = DrawPrimStrideData;
5278 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5279 This->up_strided = NULL;
5280 return WINED3D_OK;
5283 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5285 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5287 /* Mark the state dirty until we have nicer tracking
5288 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5289 * that value.
5291 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5292 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5293 This->stateBlock->streamIsUP = TRUE;
5294 This->stateBlock->baseVertexIndex = 0;
5295 This->up_strided = DrawPrimStrideData;
5296 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5297 This->up_strided = NULL;
5298 return WINED3D_OK;
5301 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5302 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5303 * not callable by the app directly no parameter validation checks are needed here.
5305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5306 WINED3DLOCKED_BOX src;
5307 WINED3DLOCKED_BOX dst;
5308 HRESULT hr;
5309 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5311 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5312 * dirtification to improve loading performance.
5314 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5315 if(FAILED(hr)) return hr;
5316 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5317 if(FAILED(hr)) {
5318 IWineD3DVolume_UnlockBox(pSourceVolume);
5319 return hr;
5322 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5324 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5325 if(FAILED(hr)) {
5326 IWineD3DVolume_UnlockBox(pSourceVolume);
5327 } else {
5328 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5330 return hr;
5333 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5334 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5336 HRESULT hr = WINED3D_OK;
5337 WINED3DRESOURCETYPE sourceType;
5338 WINED3DRESOURCETYPE destinationType;
5339 int i ,levels;
5341 /* TODO: think about moving the code into IWineD3DBaseTexture */
5343 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5345 /* verify that the source and destination textures aren't NULL */
5346 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5347 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5348 This, pSourceTexture, pDestinationTexture);
5349 hr = WINED3DERR_INVALIDCALL;
5352 if (pSourceTexture == pDestinationTexture) {
5353 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5354 This, pSourceTexture, pDestinationTexture);
5355 hr = WINED3DERR_INVALIDCALL;
5357 /* Verify that the source and destination textures are the same type */
5358 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5359 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5361 if (sourceType != destinationType) {
5362 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5363 This);
5364 hr = WINED3DERR_INVALIDCALL;
5367 /* check that both textures have the identical numbers of levels */
5368 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5369 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5370 hr = WINED3DERR_INVALIDCALL;
5373 if (WINED3D_OK == hr) {
5375 /* Make sure that the destination texture is loaded */
5376 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5378 /* Update every surface level of the texture */
5379 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5381 switch (sourceType) {
5382 case WINED3DRTYPE_TEXTURE:
5384 IWineD3DSurface *srcSurface;
5385 IWineD3DSurface *destSurface;
5387 for (i = 0 ; i < levels ; ++i) {
5388 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5389 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5390 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5391 IWineD3DSurface_Release(srcSurface);
5392 IWineD3DSurface_Release(destSurface);
5393 if (WINED3D_OK != hr) {
5394 WARN("(%p) : Call to update surface failed\n", This);
5395 return hr;
5399 break;
5400 case WINED3DRTYPE_CUBETEXTURE:
5402 IWineD3DSurface *srcSurface;
5403 IWineD3DSurface *destSurface;
5404 WINED3DCUBEMAP_FACES faceType;
5406 for (i = 0 ; i < levels ; ++i) {
5407 /* Update each cube face */
5408 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5409 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5410 if (WINED3D_OK != hr) {
5411 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5412 } else {
5413 TRACE("Got srcSurface %p\n", srcSurface);
5415 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5416 if (WINED3D_OK != hr) {
5417 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5418 } else {
5419 TRACE("Got desrSurface %p\n", destSurface);
5421 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5422 IWineD3DSurface_Release(srcSurface);
5423 IWineD3DSurface_Release(destSurface);
5424 if (WINED3D_OK != hr) {
5425 WARN("(%p) : Call to update surface failed\n", This);
5426 return hr;
5431 break;
5433 case WINED3DRTYPE_VOLUMETEXTURE:
5435 IWineD3DVolume *srcVolume = NULL;
5436 IWineD3DVolume *destVolume = NULL;
5438 for (i = 0 ; i < levels ; ++i) {
5439 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5440 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5441 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5442 IWineD3DVolume_Release(srcVolume);
5443 IWineD3DVolume_Release(destVolume);
5444 if (WINED3D_OK != hr) {
5445 WARN("(%p) : Call to update volume failed\n", This);
5446 return hr;
5450 break;
5452 default:
5453 FIXME("(%p) : Unsupported source and destination type\n", This);
5454 hr = WINED3DERR_INVALIDCALL;
5458 return hr;
5461 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5462 IWineD3DSwapChain *swapChain;
5463 HRESULT hr;
5464 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5465 if(hr == WINED3D_OK) {
5466 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5467 IWineD3DSwapChain_Release(swapChain);
5469 return hr;
5472 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5474 /* return a sensible default */
5475 *pNumPasses = 1;
5476 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5477 FIXME("(%p) : stub\n", This);
5478 return WINED3D_OK;
5481 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5483 int j;
5484 UINT NewSize;
5485 PALETTEENTRY **palettes;
5487 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5489 if (PaletteNumber >= MAX_PALETTES) {
5490 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5491 return WINED3DERR_INVALIDCALL;
5494 if (PaletteNumber >= This->NumberOfPalettes) {
5495 NewSize = This->NumberOfPalettes;
5496 do {
5497 NewSize *= 2;
5498 } while(PaletteNumber >= NewSize);
5499 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5500 if (!palettes) {
5501 ERR("Out of memory!\n");
5502 return E_OUTOFMEMORY;
5504 This->palettes = palettes;
5505 This->NumberOfPalettes = NewSize;
5508 if (!This->palettes[PaletteNumber]) {
5509 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5510 if (!This->palettes[PaletteNumber]) {
5511 ERR("Out of memory!\n");
5512 return E_OUTOFMEMORY;
5516 for (j = 0; j < 256; ++j) {
5517 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5518 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5519 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5520 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5522 TRACE("(%p) : returning\n", This);
5523 return WINED3D_OK;
5526 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5528 int j;
5529 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5530 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5531 /* What happens in such situation isn't documented; Native seems to silently abort
5532 on such conditions. Return Invalid Call. */
5533 ERR("(%p) : (%u) Non-existent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5534 return WINED3DERR_INVALIDCALL;
5536 for (j = 0; j < 256; ++j) {
5537 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5538 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5539 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5540 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5542 TRACE("(%p) : returning\n", This);
5543 return WINED3D_OK;
5546 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5548 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5549 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5550 (tested with reference rasterizer). Return Invalid Call. */
5551 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5552 ERR("(%p) : (%u) Non-existent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5553 return WINED3DERR_INVALIDCALL;
5555 /*TODO: stateblocks */
5556 This->currentPalette = PaletteNumber;
5557 TRACE("(%p) : returning\n", This);
5558 return WINED3D_OK;
5561 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5563 if (PaletteNumber == NULL) {
5564 WARN("(%p) : returning Invalid Call\n", This);
5565 return WINED3DERR_INVALIDCALL;
5567 /*TODO: stateblocks */
5568 *PaletteNumber = This->currentPalette;
5569 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5570 return WINED3D_OK;
5573 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5575 static BOOL showFixmes = TRUE;
5576 if (showFixmes) {
5577 FIXME("(%p) : stub\n", This);
5578 showFixmes = FALSE;
5581 This->softwareVertexProcessing = bSoftware;
5582 return WINED3D_OK;
5586 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5588 static BOOL showFixmes = TRUE;
5589 if (showFixmes) {
5590 FIXME("(%p) : stub\n", This);
5591 showFixmes = FALSE;
5593 return This->softwareVertexProcessing;
5597 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5599 IWineD3DSwapChain *swapChain;
5600 HRESULT hr;
5602 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5604 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5605 if(hr == WINED3D_OK){
5606 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5607 IWineD3DSwapChain_Release(swapChain);
5608 }else{
5609 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5611 return hr;
5615 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5617 static BOOL showfixmes = TRUE;
5618 if(nSegments != 0.0f) {
5619 if( showfixmes) {
5620 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5621 showfixmes = FALSE;
5624 return WINED3D_OK;
5627 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5629 static BOOL showfixmes = TRUE;
5630 if( showfixmes) {
5631 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5632 showfixmes = FALSE;
5634 return 0.0f;
5637 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5639 /** TODO: remove casts to IWineD3DSurfaceImpl
5640 * NOTE: move code to surface to accomplish this
5641 ****************************************/
5642 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5643 int srcWidth, srcHeight;
5644 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5645 WINED3DFORMAT destFormat, srcFormat;
5646 UINT destSize;
5647 int srcLeft, destLeft, destTop;
5648 WINED3DPOOL srcPool, destPool;
5649 int offset = 0;
5650 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5651 glDescriptor *glDescription = NULL;
5652 GLenum dummy;
5653 int bpp;
5654 CONVERT_TYPES convert = NO_CONVERSION;
5656 WINED3DSURFACE_DESC winedesc;
5658 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5659 memset(&winedesc, 0, sizeof(winedesc));
5660 winedesc.Width = &srcSurfaceWidth;
5661 winedesc.Height = &srcSurfaceHeight;
5662 winedesc.Pool = &srcPool;
5663 winedesc.Format = &srcFormat;
5665 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5667 winedesc.Width = &destSurfaceWidth;
5668 winedesc.Height = &destSurfaceHeight;
5669 winedesc.Pool = &destPool;
5670 winedesc.Format = &destFormat;
5671 winedesc.Size = &destSize;
5673 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5675 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5676 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5677 return WINED3DERR_INVALIDCALL;
5680 /* This call loads the opengl surface directly, instead of copying the surface to the
5681 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5682 * copy in sysmem and use regular surface loading.
5684 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5685 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5686 if(convert != NO_CONVERSION) {
5687 return IWineD3DSurface_BltFast(pDestinationSurface,
5688 pDestPoint ? pDestPoint->x : 0,
5689 pDestPoint ? pDestPoint->y : 0,
5690 pSourceSurface, (RECT *) pSourceRect, 0);
5693 if (destFormat == WINED3DFMT_UNKNOWN) {
5694 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5695 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5697 /* Get the update surface description */
5698 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5701 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5703 ENTER_GL();
5705 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5706 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5707 checkGLcall("glActiveTextureARB");
5710 /* Make sure the surface is loaded and up to date */
5711 IWineD3DSurface_PreLoad(pDestinationSurface);
5713 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5715 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5716 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5717 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5718 srcLeft = pSourceRect ? pSourceRect->left : 0;
5719 destLeft = pDestPoint ? pDestPoint->x : 0;
5720 destTop = pDestPoint ? pDestPoint->y : 0;
5723 /* This function doesn't support compressed textures
5724 the pitch is just bytesPerPixel * width */
5725 if(srcWidth != srcSurfaceWidth || srcLeft ){
5726 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5727 offset += srcLeft * pSrcSurface->bytesPerPixel;
5728 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5730 /* TODO DXT formats */
5732 if(pSourceRect != NULL && pSourceRect->top != 0){
5733 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5735 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5736 ,This
5737 ,glDescription->level
5738 ,destLeft
5739 ,destTop
5740 ,srcWidth
5741 ,srcHeight
5742 ,glDescription->glFormat
5743 ,glDescription->glType
5744 ,IWineD3DSurface_GetData(pSourceSurface)
5747 /* Sanity check */
5748 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5750 /* need to lock the surface to get the data */
5751 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5754 /* TODO: Cube and volume support */
5755 if(rowoffset != 0){
5756 /* not a whole row so we have to do it a line at a time */
5757 int j;
5759 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5760 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5762 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5764 glTexSubImage2D(glDescription->target
5765 ,glDescription->level
5766 ,destLeft
5768 ,srcWidth
5770 ,glDescription->glFormat
5771 ,glDescription->glType
5772 ,data /* could be quicker using */
5774 data += rowoffset;
5777 } else { /* Full width, so just write out the whole texture */
5779 if (WINED3DFMT_DXT1 == destFormat ||
5780 WINED3DFMT_DXT2 == destFormat ||
5781 WINED3DFMT_DXT3 == destFormat ||
5782 WINED3DFMT_DXT4 == destFormat ||
5783 WINED3DFMT_DXT5 == destFormat) {
5784 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5785 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5786 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5787 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5788 } if (destFormat != srcFormat) {
5789 FIXME("Updating mixed format compressed texture is not curretly support\n");
5790 } else {
5791 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5792 glDescription->level,
5793 glDescription->glFormatInternal,
5794 srcWidth,
5795 srcHeight,
5797 destSize,
5798 IWineD3DSurface_GetData(pSourceSurface));
5800 } else {
5801 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5805 } else {
5806 glTexSubImage2D(glDescription->target
5807 ,glDescription->level
5808 ,destLeft
5809 ,destTop
5810 ,srcWidth
5811 ,srcHeight
5812 ,glDescription->glFormat
5813 ,glDescription->glType
5814 ,IWineD3DSurface_GetData(pSourceSurface)
5818 checkGLcall("glTexSubImage2D");
5820 LEAVE_GL();
5822 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5823 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5825 return WINED3D_OK;
5828 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5830 struct WineD3DRectPatch *patch;
5831 unsigned int i;
5832 struct list *e;
5833 BOOL found;
5834 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5836 if(!(Handle || pRectPatchInfo)) {
5837 /* TODO: Write a test for the return value, thus the FIXME */
5838 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5839 return WINED3DERR_INVALIDCALL;
5842 if(Handle) {
5843 i = PATCHMAP_HASHFUNC(Handle);
5844 found = FALSE;
5845 LIST_FOR_EACH(e, &This->patches[i]) {
5846 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5847 if(patch->Handle == Handle) {
5848 found = TRUE;
5849 break;
5853 if(!found) {
5854 TRACE("Patch does not exist. Creating a new one\n");
5855 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5856 patch->Handle = Handle;
5857 list_add_head(&This->patches[i], &patch->entry);
5858 } else {
5859 TRACE("Found existing patch %p\n", patch);
5861 } else {
5862 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5863 * attributes we have to tesselate, read back, and draw. This needs a patch
5864 * management structure instance. Create one.
5866 * A possible improvement is to check if a vertex shader is used, and if not directly
5867 * draw the patch.
5869 FIXME("Drawing an uncached patch. This is slow\n");
5870 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5873 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5874 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5875 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5876 HRESULT hr;
5877 TRACE("Tesselation density or patch info changed, retesselating\n");
5879 if(pRectPatchInfo) {
5880 patch->RectPatchInfo = *pRectPatchInfo;
5882 patch->numSegs[0] = pNumSegs[0];
5883 patch->numSegs[1] = pNumSegs[1];
5884 patch->numSegs[2] = pNumSegs[2];
5885 patch->numSegs[3] = pNumSegs[3];
5887 hr = tesselate_rectpatch(This, patch);
5888 if(FAILED(hr)) {
5889 WARN("Patch tesselation failed\n");
5891 /* Do not release the handle to store the params of the patch */
5892 if(!Handle) {
5893 HeapFree(GetProcessHeap(), 0, patch);
5895 return hr;
5899 This->currentPatch = patch;
5900 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5901 This->currentPatch = NULL;
5903 /* Destroy uncached patches */
5904 if(!Handle) {
5905 HeapFree(GetProcessHeap(), 0, patch->mem);
5906 HeapFree(GetProcessHeap(), 0, patch);
5908 return WINED3D_OK;
5911 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5913 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5914 FIXME("(%p) : Stub\n", This);
5915 return WINED3D_OK;
5918 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5920 int i;
5921 struct WineD3DRectPatch *patch;
5922 struct list *e;
5923 TRACE("(%p) Handle(%d)\n", This, Handle);
5925 i = PATCHMAP_HASHFUNC(Handle);
5926 LIST_FOR_EACH(e, &This->patches[i]) {
5927 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5928 if(patch->Handle == Handle) {
5929 TRACE("Deleting patch %p\n", patch);
5930 list_remove(&patch->entry);
5931 HeapFree(GetProcessHeap(), 0, patch->mem);
5932 HeapFree(GetProcessHeap(), 0, patch);
5933 return WINED3D_OK;
5937 /* TODO: Write a test for the return value */
5938 FIXME("Attempt to destroy nonexistent patch\n");
5939 return WINED3DERR_INVALIDCALL;
5942 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5943 HRESULT hr;
5944 IWineD3DSwapChain *swapchain;
5946 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5947 if (SUCCEEDED(hr)) {
5948 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5949 return swapchain;
5952 return NULL;
5955 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5958 if (!*fbo) {
5959 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5960 checkGLcall("glGenFramebuffersEXT()");
5962 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5963 checkGLcall("glBindFramebuffer()");
5966 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5967 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5968 IWineD3DBaseTextureImpl *texture_impl;
5969 GLenum texttarget, target;
5970 GLint old_binding;
5972 texttarget = surface_impl->glDescription.target;
5973 if(texttarget == GL_TEXTURE_2D) {
5974 target = GL_TEXTURE_2D;
5975 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5976 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
5977 target = GL_TEXTURE_RECTANGLE_ARB;
5978 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5979 } else {
5980 target = GL_TEXTURE_CUBE_MAP_ARB;
5981 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5984 IWineD3DSurface_PreLoad(surface);
5986 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5987 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5988 glBindTexture(target, old_binding);
5990 /* Update base texture states array */
5991 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5992 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5993 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5994 if (texture_impl->baseTexture.bindCount) {
5995 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5998 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6001 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6002 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6004 checkGLcall("attach_surface_fbo");
6007 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6009 IWineD3DSwapChain *swapchain;
6011 swapchain = get_swapchain(surface);
6012 if (swapchain) {
6013 GLenum buffer;
6015 TRACE("Surface %p is onscreen\n", surface);
6017 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6018 buffer = surface_get_gl_buffer(surface, swapchain);
6019 glDrawBuffer(buffer);
6020 checkGLcall("glDrawBuffer()");
6021 } else {
6022 TRACE("Surface %p is offscreen\n", surface);
6023 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
6024 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6027 if (rect) {
6028 glEnable(GL_SCISSOR_TEST);
6029 if(!swapchain) {
6030 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6031 } else {
6032 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6033 rect->x2 - rect->x1, rect->y2 - rect->y1);
6035 checkGLcall("glScissor");
6036 } else {
6037 glDisable(GL_SCISSOR_TEST);
6039 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6041 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6042 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6044 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6045 glClear(GL_COLOR_BUFFER_BIT);
6046 checkGLcall("glClear");
6048 if (This->render_offscreen) {
6049 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6050 } else {
6051 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6052 checkGLcall("glBindFramebuffer()");
6055 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6056 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6057 glDrawBuffer(GL_BACK);
6058 checkGLcall("glDrawBuffer()");
6062 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6063 unsigned int r, g, b, a;
6064 DWORD ret;
6066 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6067 destfmt == WINED3DFMT_R8G8B8)
6068 return color;
6070 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6072 a = (color & 0xff000000) >> 24;
6073 r = (color & 0x00ff0000) >> 16;
6074 g = (color & 0x0000ff00) >> 8;
6075 b = (color & 0x000000ff) >> 0;
6077 switch(destfmt)
6079 case WINED3DFMT_R5G6B5:
6080 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6081 r = (r * 32) / 256;
6082 g = (g * 64) / 256;
6083 b = (b * 32) / 256;
6084 ret = r << 11;
6085 ret |= g << 5;
6086 ret |= b;
6087 TRACE("Returning %08x\n", ret);
6088 return ret;
6090 case WINED3DFMT_X1R5G5B5:
6091 case WINED3DFMT_A1R5G5B5:
6092 a = (a * 2) / 256;
6093 r = (r * 32) / 256;
6094 g = (g * 32) / 256;
6095 b = (b * 32) / 256;
6096 ret = a << 15;
6097 ret |= r << 10;
6098 ret |= g << 5;
6099 ret |= b << 0;
6100 TRACE("Returning %08x\n", ret);
6101 return ret;
6103 case WINED3DFMT_A8:
6104 TRACE("Returning %08x\n", a);
6105 return a;
6107 case WINED3DFMT_X4R4G4B4:
6108 case WINED3DFMT_A4R4G4B4:
6109 a = (a * 16) / 256;
6110 r = (r * 16) / 256;
6111 g = (g * 16) / 256;
6112 b = (b * 16) / 256;
6113 ret = a << 12;
6114 ret |= r << 8;
6115 ret |= g << 4;
6116 ret |= b << 0;
6117 TRACE("Returning %08x\n", ret);
6118 return ret;
6120 case WINED3DFMT_R3G3B2:
6121 r = (r * 8) / 256;
6122 g = (g * 8) / 256;
6123 b = (b * 4) / 256;
6124 ret = r << 5;
6125 ret |= g << 2;
6126 ret |= b << 0;
6127 TRACE("Returning %08x\n", ret);
6128 return ret;
6130 case WINED3DFMT_X8B8G8R8:
6131 case WINED3DFMT_A8B8G8R8:
6132 ret = a << 24;
6133 ret |= b << 16;
6134 ret |= g << 8;
6135 ret |= r << 0;
6136 TRACE("Returning %08x\n", ret);
6137 return ret;
6139 case WINED3DFMT_A2R10G10B10:
6140 a = (a * 4) / 256;
6141 r = (r * 1024) / 256;
6142 g = (g * 1024) / 256;
6143 b = (b * 1024) / 256;
6144 ret = a << 30;
6145 ret |= r << 20;
6146 ret |= g << 10;
6147 ret |= b << 0;
6148 TRACE("Returning %08x\n", ret);
6149 return ret;
6151 case WINED3DFMT_A2B10G10R10:
6152 a = (a * 4) / 256;
6153 r = (r * 1024) / 256;
6154 g = (g * 1024) / 256;
6155 b = (b * 1024) / 256;
6156 ret = a << 30;
6157 ret |= b << 20;
6158 ret |= g << 10;
6159 ret |= r << 0;
6160 TRACE("Returning %08x\n", ret);
6161 return ret;
6163 default:
6164 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6165 return 0;
6169 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6171 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6172 WINEDDBLTFX BltFx;
6173 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6175 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6176 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6177 return WINED3DERR_INVALIDCALL;
6180 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6181 color_fill_fbo(iface, pSurface, pRect, color);
6182 return WINED3D_OK;
6183 } else {
6184 /* Just forward this to the DirectDraw blitting engine */
6185 memset(&BltFx, 0, sizeof(BltFx));
6186 BltFx.dwSize = sizeof(BltFx);
6187 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6188 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6192 /* rendertarget and depth stencil functions */
6193 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6196 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6197 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6198 return WINED3DERR_INVALIDCALL;
6201 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6202 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6203 /* Note inc ref on returned surface */
6204 if(*ppRenderTarget != NULL)
6205 IWineD3DSurface_AddRef(*ppRenderTarget);
6206 return WINED3D_OK;
6209 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6211 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6212 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6213 IWineD3DSwapChainImpl *Swapchain;
6214 HRESULT hr;
6216 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6218 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6219 if(hr != WINED3D_OK) {
6220 ERR("Can't get the swapchain\n");
6221 return hr;
6224 /* Make sure to release the swapchain */
6225 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6227 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6228 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6229 return WINED3DERR_INVALIDCALL;
6231 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6232 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6233 return WINED3DERR_INVALIDCALL;
6236 if(Swapchain->frontBuffer != Front) {
6237 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6239 if(Swapchain->frontBuffer)
6240 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6241 Swapchain->frontBuffer = Front;
6243 if(Swapchain->frontBuffer) {
6244 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6248 if(Back && !Swapchain->backBuffer) {
6249 /* We need memory for the back buffer array - only one back buffer this way */
6250 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6251 if(!Swapchain->backBuffer) {
6252 ERR("Out of memory\n");
6253 return E_OUTOFMEMORY;
6257 if(Swapchain->backBuffer[0] != Back) {
6258 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6260 /* What to do about the context here in the case of multithreading? Not sure.
6261 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6263 ENTER_GL();
6264 if(!Swapchain->backBuffer[0]) {
6265 /* GL was told to draw to the front buffer at creation,
6266 * undo that
6268 glDrawBuffer(GL_BACK);
6269 checkGLcall("glDrawBuffer(GL_BACK)");
6270 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6271 Swapchain->presentParms.BackBufferCount = 1;
6272 } else if (!Back) {
6273 /* That makes problems - disable for now */
6274 /* glDrawBuffer(GL_FRONT); */
6275 checkGLcall("glDrawBuffer(GL_FRONT)");
6276 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6277 Swapchain->presentParms.BackBufferCount = 0;
6279 LEAVE_GL();
6281 if(Swapchain->backBuffer[0])
6282 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6283 Swapchain->backBuffer[0] = Back;
6285 if(Swapchain->backBuffer[0]) {
6286 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6287 } else {
6288 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6289 Swapchain->backBuffer = NULL;
6294 return WINED3D_OK;
6297 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6299 *ppZStencilSurface = This->stencilBufferTarget;
6300 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6302 if(*ppZStencilSurface != NULL) {
6303 /* Note inc ref on returned surface */
6304 IWineD3DSurface_AddRef(*ppZStencilSurface);
6305 return WINED3D_OK;
6306 } else {
6307 return WINED3DERR_NOTFOUND;
6311 /* TODO: Handle stencil attachments */
6312 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6314 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6316 TRACE("Set depth stencil to %p\n", depth_stencil);
6318 if (depth_stencil_impl) {
6319 if (depth_stencil_impl->current_renderbuffer) {
6320 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6321 checkGLcall("glFramebufferRenderbufferEXT()");
6322 } else {
6323 IWineD3DBaseTextureImpl *texture_impl;
6324 GLenum texttarget, target;
6325 GLint old_binding = 0;
6327 texttarget = depth_stencil_impl->glDescription.target;
6328 if(texttarget == GL_TEXTURE_2D) {
6329 target = GL_TEXTURE_2D;
6330 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6331 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6332 target = GL_TEXTURE_RECTANGLE_ARB;
6333 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6334 } else {
6335 target = GL_TEXTURE_CUBE_MAP_ARB;
6336 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6339 IWineD3DSurface_PreLoad(depth_stencil);
6341 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6342 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6343 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6344 glBindTexture(target, old_binding);
6346 /* Update base texture states array */
6347 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6348 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6349 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6350 if (texture_impl->baseTexture.bindCount) {
6351 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6354 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6357 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6358 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6359 checkGLcall("glFramebufferTexture2DEXT()");
6361 } else {
6362 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6363 checkGLcall("glFramebufferTexture2DEXT()");
6367 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6368 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6369 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6371 TRACE("Set render target %u to %p\n", idx, render_target);
6373 if (rtimpl) {
6374 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6375 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6376 } else {
6377 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6378 checkGLcall("glFramebufferTexture2DEXT()");
6380 This->draw_buffers[idx] = GL_NONE;
6384 static void check_fbo_status(IWineD3DDevice *iface) {
6385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6386 GLenum status;
6388 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6389 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6390 TRACE("FBO complete\n");
6391 } else {
6392 IWineD3DSurfaceImpl *attachment;
6393 int i;
6394 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6396 /* Dump the FBO attachments */
6397 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6398 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6399 if (attachment) {
6400 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6401 attachment->pow2Width, attachment->pow2Height);
6404 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6405 if (attachment) {
6406 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6407 attachment->pow2Width, attachment->pow2Height);
6412 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6414 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6415 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6417 if (!ds_impl) return FALSE;
6419 if (ds_impl->current_renderbuffer) {
6420 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6421 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6424 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6425 rt_impl->pow2Height != ds_impl->pow2Height);
6428 void apply_fbo_state(IWineD3DDevice *iface) {
6429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6430 unsigned int i;
6432 if (This->render_offscreen) {
6433 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6435 /* Apply render targets */
6436 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6437 IWineD3DSurface *render_target = This->render_targets[i];
6438 if (This->fbo_color_attachments[i] != render_target) {
6439 set_render_target_fbo(iface, i, render_target);
6440 This->fbo_color_attachments[i] = render_target;
6444 /* Apply depth targets */
6445 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6446 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6447 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6449 if (This->stencilBufferTarget) {
6450 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6452 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6453 This->fbo_depth_attachment = This->stencilBufferTarget;
6456 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6457 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6458 checkGLcall("glDrawBuffers()");
6459 } else {
6460 glDrawBuffer(This->draw_buffers[0]);
6461 checkGLcall("glDrawBuffer()");
6463 } else {
6464 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6467 check_fbo_status(iface);
6470 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6471 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6473 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6474 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6475 GLenum gl_filter;
6477 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6478 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6479 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6480 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6482 switch (filter) {
6483 case WINED3DTEXF_LINEAR:
6484 gl_filter = GL_LINEAR;
6485 break;
6487 default:
6488 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6489 case WINED3DTEXF_NONE:
6490 case WINED3DTEXF_POINT:
6491 gl_filter = GL_NEAREST;
6492 break;
6495 /* Attach src surface to src fbo */
6496 src_swapchain = get_swapchain(src_surface);
6497 if (src_swapchain) {
6498 GLenum buffer;
6500 TRACE("Source surface %p is onscreen\n", src_surface);
6501 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6502 /* Make sure the drawable is up to date. In the offscreen case
6503 * attach_surface_fbo() implicitly takes care of this. */
6504 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6506 ENTER_GL();
6507 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6508 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6509 glReadBuffer(buffer);
6510 checkGLcall("glReadBuffer()");
6512 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6513 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6514 } else {
6515 TRACE("Source surface %p is offscreen\n", src_surface);
6516 ENTER_GL();
6517 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6518 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6519 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6520 checkGLcall("glReadBuffer()");
6522 LEAVE_GL();
6524 /* Attach dst surface to dst fbo */
6525 dst_swapchain = get_swapchain(dst_surface);
6526 if (dst_swapchain) {
6527 GLenum buffer;
6529 TRACE("Destination surface %p is onscreen\n", dst_surface);
6530 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6531 /* Make sure the drawable is up to date. In the offscreen case
6532 * attach_surface_fbo() implicitly takes care of this. */
6533 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6535 ENTER_GL();
6536 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6537 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6538 glDrawBuffer(buffer);
6539 checkGLcall("glDrawBuffer()");
6541 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6542 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6543 } else {
6544 TRACE("Destination surface %p is offscreen\n", dst_surface);
6546 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6547 if(!src_swapchain) {
6548 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6551 ENTER_GL();
6552 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6553 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6554 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6555 checkGLcall("glDrawBuffer()");
6557 glDisable(GL_SCISSOR_TEST);
6558 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6560 if (flip) {
6561 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6562 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6563 checkGLcall("glBlitFramebuffer()");
6564 } else {
6565 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6566 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6567 checkGLcall("glBlitFramebuffer()");
6570 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6572 if (This->render_offscreen) {
6573 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6574 } else {
6575 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6576 checkGLcall("glBindFramebuffer()");
6579 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6580 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6581 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6582 glDrawBuffer(GL_BACK);
6583 checkGLcall("glDrawBuffer()");
6585 LEAVE_GL();
6588 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6590 WINED3DVIEWPORT viewport;
6592 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6594 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6595 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6596 This, RenderTargetIndex, GL_LIMITS(buffers));
6597 return WINED3DERR_INVALIDCALL;
6600 /* MSDN says that null disables the render target
6601 but a device must always be associated with a render target
6602 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6604 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6605 FIXME("Trying to set render target 0 to NULL\n");
6606 return WINED3DERR_INVALIDCALL;
6608 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6609 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);
6610 return WINED3DERR_INVALIDCALL;
6613 /* If we are trying to set what we already have, don't bother */
6614 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6615 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6616 return WINED3D_OK;
6618 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6619 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6620 This->render_targets[RenderTargetIndex] = pRenderTarget;
6622 /* Render target 0 is special */
6623 if(RenderTargetIndex == 0) {
6624 /* Finally, reset the viewport as the MSDN states. */
6625 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6626 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6627 viewport.X = 0;
6628 viewport.Y = 0;
6629 viewport.MaxZ = 1.0f;
6630 viewport.MinZ = 0.0f;
6631 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6632 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6633 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6635 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6637 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6638 * ctx properly.
6639 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6640 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6642 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6644 return WINED3D_OK;
6647 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6649 HRESULT hr = WINED3D_OK;
6650 IWineD3DSurface *tmp;
6652 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6654 if (pNewZStencil == This->stencilBufferTarget) {
6655 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6656 } else {
6657 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6658 * depending on the renter target implementation being used.
6659 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6660 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6661 * stencil buffer and incur an extra memory overhead
6662 ******************************************************/
6664 tmp = This->stencilBufferTarget;
6665 This->stencilBufferTarget = pNewZStencil;
6666 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6667 /* should we be calling the parent or the wined3d surface? */
6668 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6669 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6670 hr = WINED3D_OK;
6672 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6673 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6674 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6675 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6676 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6680 return hr;
6683 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6684 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6686 /* TODO: the use of Impl is deprecated. */
6687 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6688 WINED3DLOCKED_RECT lockedRect;
6690 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6692 /* some basic validation checks */
6693 if(This->cursorTexture) {
6694 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6695 ENTER_GL();
6696 glDeleteTextures(1, &This->cursorTexture);
6697 LEAVE_GL();
6698 This->cursorTexture = 0;
6701 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6702 This->haveHardwareCursor = TRUE;
6703 else
6704 This->haveHardwareCursor = FALSE;
6706 if(pCursorBitmap) {
6707 WINED3DLOCKED_RECT rect;
6709 /* MSDN: Cursor must be A8R8G8B8 */
6710 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6711 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6712 return WINED3DERR_INVALIDCALL;
6715 /* MSDN: Cursor must be smaller than the display mode */
6716 if(pSur->currentDesc.Width > This->ddraw_width ||
6717 pSur->currentDesc.Height > This->ddraw_height) {
6718 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);
6719 return WINED3DERR_INVALIDCALL;
6722 if (!This->haveHardwareCursor) {
6723 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6725 /* Do not store the surface's pointer because the application may
6726 * release it after setting the cursor image. Windows doesn't
6727 * addref the set surface, so we can't do this either without
6728 * creating circular refcount dependencies. Copy out the gl texture
6729 * instead.
6731 This->cursorWidth = pSur->currentDesc.Width;
6732 This->cursorHeight = pSur->currentDesc.Height;
6733 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6735 const GlPixelFormatDesc *glDesc;
6736 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6737 char *mem, *bits = (char *)rect.pBits;
6738 GLint intfmt = glDesc->glInternal;
6739 GLint format = glDesc->glFormat;
6740 GLint type = glDesc->glType;
6741 INT height = This->cursorHeight;
6742 INT width = This->cursorWidth;
6743 INT bpp = tableEntry->bpp;
6744 INT i;
6746 /* Reformat the texture memory (pitch and width can be
6747 * different) */
6748 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6749 for(i = 0; i < height; i++)
6750 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6751 IWineD3DSurface_UnlockRect(pCursorBitmap);
6752 ENTER_GL();
6754 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6755 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6756 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6759 /* Make sure that a proper texture unit is selected */
6760 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6761 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6762 checkGLcall("glActiveTextureARB");
6764 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6765 /* Create a new cursor texture */
6766 glGenTextures(1, &This->cursorTexture);
6767 checkGLcall("glGenTextures");
6768 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6769 checkGLcall("glBindTexture");
6770 /* Copy the bitmap memory into the cursor texture */
6771 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6772 HeapFree(GetProcessHeap(), 0, mem);
6773 checkGLcall("glTexImage2D");
6775 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6776 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6777 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6780 LEAVE_GL();
6782 else
6784 FIXME("A cursor texture was not returned.\n");
6785 This->cursorTexture = 0;
6788 else
6790 /* Draw a hardware cursor */
6791 ICONINFO cursorInfo;
6792 HCURSOR cursor;
6793 /* Create and clear maskBits because it is not needed for
6794 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6795 * chunks. */
6796 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6797 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6798 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6799 WINED3DLOCK_NO_DIRTY_UPDATE |
6800 WINED3DLOCK_READONLY
6802 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6803 pSur->currentDesc.Height);
6805 cursorInfo.fIcon = FALSE;
6806 cursorInfo.xHotspot = XHotSpot;
6807 cursorInfo.yHotspot = YHotSpot;
6808 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6809 pSur->currentDesc.Height, 1,
6810 1, &maskBits);
6811 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6812 pSur->currentDesc.Height, 1,
6813 32, lockedRect.pBits);
6814 IWineD3DSurface_UnlockRect(pCursorBitmap);
6815 /* Create our cursor and clean up. */
6816 cursor = CreateIconIndirect(&cursorInfo);
6817 SetCursor(cursor);
6818 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6819 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6820 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6821 This->hardwareCursor = cursor;
6822 HeapFree(GetProcessHeap(), 0, maskBits);
6826 This->xHotSpot = XHotSpot;
6827 This->yHotSpot = YHotSpot;
6828 return WINED3D_OK;
6831 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6833 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6835 This->xScreenSpace = XScreenSpace;
6836 This->yScreenSpace = YScreenSpace;
6838 return;
6842 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6844 BOOL oldVisible = This->bCursorVisible;
6845 POINT pt;
6847 TRACE("(%p) : visible(%d)\n", This, bShow);
6850 * When ShowCursor is first called it should make the cursor appear at the OS's last
6851 * known cursor position. Because of this, some applications just repetitively call
6852 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6854 GetCursorPos(&pt);
6855 This->xScreenSpace = pt.x;
6856 This->yScreenSpace = pt.y;
6858 if (This->haveHardwareCursor) {
6859 This->bCursorVisible = bShow;
6860 if (bShow)
6861 SetCursor(This->hardwareCursor);
6862 else
6863 SetCursor(NULL);
6865 else
6867 if (This->cursorTexture)
6868 This->bCursorVisible = bShow;
6871 return oldVisible;
6874 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6876 IWineD3DResourceImpl *resource;
6877 TRACE("(%p) : state (%u)\n", This, This->state);
6879 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6880 switch (This->state) {
6881 case WINED3D_OK:
6882 return WINED3D_OK;
6883 case WINED3DERR_DEVICELOST:
6885 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6886 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6887 return WINED3DERR_DEVICENOTRESET;
6889 return WINED3DERR_DEVICELOST;
6891 case WINED3DERR_DRIVERINTERNALERROR:
6892 return WINED3DERR_DRIVERINTERNALERROR;
6895 /* Unknown state */
6896 return WINED3DERR_DRIVERINTERNALERROR;
6900 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6902 /** FIXME: Resource tracking needs to be done,
6903 * The closes we can do to this is set the priorities of all managed textures low
6904 * and then reset them.
6905 ***********************************************************/
6906 FIXME("(%p) : stub\n", This);
6907 return WINED3D_OK;
6910 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6911 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6913 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6914 if(surface->Flags & SFLAG_DIBSECTION) {
6915 /* Release the DC */
6916 SelectObject(surface->hDC, surface->dib.holdbitmap);
6917 DeleteDC(surface->hDC);
6918 /* Release the DIB section */
6919 DeleteObject(surface->dib.DIBsection);
6920 surface->dib.bitmap_data = NULL;
6921 surface->resource.allocatedMemory = NULL;
6922 surface->Flags &= ~SFLAG_DIBSECTION;
6924 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6925 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6926 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE)) {
6927 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6928 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6929 } else {
6930 surface->pow2Width = surface->pow2Height = 1;
6931 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6932 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6934 surface->glRect.left = 0;
6935 surface->glRect.top = 0;
6936 surface->glRect.right = surface->pow2Width;
6937 surface->glRect.bottom = surface->pow2Height;
6939 if(surface->glDescription.textureName) {
6940 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6941 ENTER_GL();
6942 glDeleteTextures(1, &surface->glDescription.textureName);
6943 LEAVE_GL();
6944 surface->glDescription.textureName = 0;
6945 surface->Flags &= ~SFLAG_CLIENT;
6947 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6948 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6949 surface->Flags |= SFLAG_NONPOW2;
6950 } else {
6951 surface->Flags &= ~SFLAG_NONPOW2;
6953 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6954 surface->resource.allocatedMemory = NULL;
6955 surface->resource.heapMemory = NULL;
6956 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6959 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6960 TRACE("Unloading resource %p\n", resource);
6961 IWineD3DResource_UnLoad(resource);
6962 IWineD3DResource_Release(resource);
6963 return S_OK;
6966 static void reset_fbo_state(IWineD3DDevice *iface) {
6967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6968 unsigned int i;
6970 ENTER_GL();
6971 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6972 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
6974 if (This->fbo) {
6975 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
6976 This->fbo = 0;
6978 if (This->src_fbo) {
6979 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
6980 This->src_fbo = 0;
6982 if (This->dst_fbo) {
6983 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
6984 This->dst_fbo = 0;
6986 checkGLcall("Tear down fbos\n");
6987 LEAVE_GL();
6989 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6990 This->fbo_color_attachments[i] = NULL;
6992 This->fbo_depth_attachment = NULL;
6995 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
6996 UINT i, count;
6997 WINED3DDISPLAYMODE m;
6998 HRESULT hr;
7000 /* All Windowed modes are supported, as is leaving the current mode */
7001 if(pp->Windowed) return TRUE;
7002 if(!pp->BackBufferWidth) return TRUE;
7003 if(!pp->BackBufferHeight) return TRUE;
7005 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7006 for(i = 0; i < count; i++) {
7007 memset(&m, 0, sizeof(m));
7008 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7009 if(FAILED(hr)) {
7010 ERR("EnumAdapterModes failed\n");
7012 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7013 /* Mode found, it is supported */
7014 return TRUE;
7017 /* Mode not found -> not supported */
7018 return FALSE;
7021 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7023 IWineD3DSwapChainImpl *swapchain;
7024 HRESULT hr;
7025 BOOL DisplayModeChanged = FALSE;
7026 WINED3DDISPLAYMODE mode;
7027 IWineD3DBaseShaderImpl *shader;
7028 IWineD3DSurfaceImpl *target;
7029 UINT i;
7030 TRACE("(%p)\n", This);
7032 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7033 if(FAILED(hr)) {
7034 ERR("Failed to get the first implicit swapchain\n");
7035 return hr;
7038 if(!is_display_mode_supported(This, pPresentationParameters)) {
7039 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7040 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7041 pPresentationParameters->BackBufferHeight);
7042 return WINED3DERR_INVALIDCALL;
7045 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7046 * on an existing gl context, so there's no real need for recreation.
7048 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7050 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7052 TRACE("New params:\n");
7053 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7054 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7055 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7056 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7057 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7058 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7059 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7060 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7061 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7062 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7063 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7064 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7065 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7067 /* No special treatment of these parameters. Just store them */
7068 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7069 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7070 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7071 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7073 /* What to do about these? */
7074 if(pPresentationParameters->BackBufferCount != 0 &&
7075 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7076 ERR("Cannot change the back buffer count yet\n");
7078 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7079 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7080 ERR("Cannot change the back buffer format yet\n");
7082 if(pPresentationParameters->hDeviceWindow != NULL &&
7083 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7084 ERR("Cannot change the device window yet\n");
7086 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7087 ERR("What do do about a changed auto depth stencil parameter?\n");
7090 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7091 reset_fbo_state((IWineD3DDevice *) This);
7094 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7095 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7096 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7099 ENTER_GL();
7100 if(This->depth_blt_texture) {
7101 glDeleteTextures(1, &This->depth_blt_texture);
7102 This->depth_blt_texture = 0;
7104 This->shader_backend->shader_destroy_depth_blt(iface);
7105 This->shader_backend->shader_free_private(iface);
7107 for (i = 0; i < GL_LIMITS(textures); i++) {
7108 /* Textures are recreated below */
7109 glDeleteTextures(1, &This->dummyTextureName[i]);
7110 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7111 This->dummyTextureName[i] = 0;
7113 LEAVE_GL();
7115 while(This->numContexts) {
7116 DestroyContext(This, This->contexts[0]);
7118 This->activeContext = NULL;
7119 HeapFree(GetProcessHeap(), 0, swapchain->context);
7120 swapchain->context = NULL;
7121 swapchain->num_contexts = 0;
7123 if(pPresentationParameters->Windowed) {
7124 mode.Width = swapchain->orig_width;
7125 mode.Height = swapchain->orig_height;
7126 mode.RefreshRate = 0;
7127 mode.Format = swapchain->presentParms.BackBufferFormat;
7128 } else {
7129 mode.Width = pPresentationParameters->BackBufferWidth;
7130 mode.Height = pPresentationParameters->BackBufferHeight;
7131 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7132 mode.Format = swapchain->presentParms.BackBufferFormat;
7135 /* Should Width == 800 && Height == 0 set 800x600? */
7136 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7137 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7138 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7140 WINED3DVIEWPORT vp;
7141 int i;
7143 vp.X = 0;
7144 vp.Y = 0;
7145 vp.Width = pPresentationParameters->BackBufferWidth;
7146 vp.Height = pPresentationParameters->BackBufferHeight;
7147 vp.MinZ = 0;
7148 vp.MaxZ = 1;
7150 if(!pPresentationParameters->Windowed) {
7151 DisplayModeChanged = TRUE;
7153 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7154 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7156 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7157 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7158 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7160 if(This->auto_depth_stencil_buffer) {
7161 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7165 /* Now set the new viewport */
7166 IWineD3DDevice_SetViewport(iface, &vp);
7169 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7170 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7171 DisplayModeChanged) {
7173 IWineD3DDevice_SetFullscreen(iface, !pPresentationParameters->Windowed);
7174 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7175 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7176 } else if(!pPresentationParameters->Windowed) {
7177 DWORD style = This->style, exStyle = This->exStyle;
7178 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7179 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7180 * Reset to clear up their mess. Guild Wars also loses the device during that.
7182 This->style = 0;
7183 This->exStyle = 0;
7184 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
7185 This->style = style;
7186 This->exStyle = exStyle;
7189 /* Recreate the primary swapchain's context */
7190 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7191 if(swapchain->backBuffer) {
7192 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7193 } else {
7194 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7196 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7197 &swapchain->presentParms);
7198 swapchain->num_contexts = 1;
7199 This->activeContext = swapchain->context[0];
7200 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7202 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7203 if(FAILED(hr)) {
7204 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7206 create_dummy_textures(This);
7209 hr = This->shader_backend->shader_alloc_private(iface);
7210 if(FAILED(hr)) {
7211 ERR("Failed to recreate shader private data\n");
7212 return hr;
7215 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7216 * first use
7218 return WINED3D_OK;
7221 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7223 /** FIXME: always true at the moment **/
7224 if(!bEnableDialogs) {
7225 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7227 return WINED3D_OK;
7231 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7233 TRACE("(%p) : pParameters %p\n", This, pParameters);
7235 *pParameters = This->createParms;
7236 return WINED3D_OK;
7239 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7240 IWineD3DSwapChain *swapchain;
7241 HRESULT hrc = WINED3D_OK;
7243 TRACE("Relaying to swapchain\n");
7245 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7246 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7247 IWineD3DSwapChain_Release(swapchain);
7249 return;
7252 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7253 IWineD3DSwapChain *swapchain;
7254 HRESULT hrc = WINED3D_OK;
7256 TRACE("Relaying to swapchain\n");
7258 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7259 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7260 IWineD3DSwapChain_Release(swapchain);
7262 return;
7266 /** ********************************************************
7267 * Notification functions
7268 ** ********************************************************/
7269 /** This function must be called in the release of a resource when ref == 0,
7270 * the contents of resource must still be correct,
7271 * any handles to other resource held by the caller must be closed
7272 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7273 *****************************************************/
7274 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7277 TRACE("(%p) : Adding Resource %p\n", This, resource);
7278 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7281 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7284 TRACE("(%p) : Removing resource %p\n", This, resource);
7286 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7290 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7292 int counter;
7294 TRACE("(%p) : resource %p\n", This, resource);
7295 switch(IWineD3DResource_GetType(resource)){
7296 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7297 case WINED3DRTYPE_SURFACE: {
7298 unsigned int i;
7300 /* Cleanup any FBO attachments if d3d is enabled */
7301 if(This->d3d_initialized) {
7302 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7303 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7305 TRACE("Last active render target destroyed\n");
7306 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7307 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7308 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7309 * and the lastActiveRenderTarget member shouldn't matter
7311 if(swapchain) {
7312 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7313 TRACE("Activating primary back buffer\n");
7314 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7315 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7316 /* Single buffering environment */
7317 TRACE("Activating primary front buffer\n");
7318 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7319 } else {
7320 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7321 /* Implicit render target destroyed, that means the device is being destroyed
7322 * whatever we set here, it shouldn't matter
7324 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7326 } else {
7327 /* May happen during ddraw uninitialization */
7328 TRACE("Render target set, but swapchain does not exist!\n");
7329 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7333 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7334 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7335 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7336 set_render_target_fbo(iface, i, NULL);
7337 This->fbo_color_attachments[i] = NULL;
7340 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7341 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7342 set_depth_stencil_fbo(iface, NULL);
7343 This->fbo_depth_attachment = NULL;
7347 break;
7349 case WINED3DRTYPE_TEXTURE:
7350 case WINED3DRTYPE_CUBETEXTURE:
7351 case WINED3DRTYPE_VOLUMETEXTURE:
7352 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7353 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7354 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7355 This->stateBlock->textures[counter] = NULL;
7357 if (This->updateStateBlock != This->stateBlock ){
7358 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7359 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7360 This->updateStateBlock->textures[counter] = NULL;
7364 break;
7365 case WINED3DRTYPE_VOLUME:
7366 /* TODO: nothing really? */
7367 break;
7368 case WINED3DRTYPE_VERTEXBUFFER:
7369 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7371 int streamNumber;
7372 TRACE("Cleaning up stream pointers\n");
7374 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7375 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7376 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7378 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7379 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7380 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7381 This->updateStateBlock->streamSource[streamNumber] = 0;
7382 /* Set changed flag? */
7385 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) */
7386 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7387 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7388 This->stateBlock->streamSource[streamNumber] = 0;
7391 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7392 else { /* This shouldn't happen */
7393 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7395 #endif
7399 break;
7400 case WINED3DRTYPE_INDEXBUFFER:
7401 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7402 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7403 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7404 This->updateStateBlock->pIndexData = NULL;
7407 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7408 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7409 This->stateBlock->pIndexData = NULL;
7413 break;
7414 default:
7415 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7416 break;
7420 /* Remove the resource from the resourceStore */
7421 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7423 TRACE("Resource released\n");
7427 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7429 IWineD3DResourceImpl *resource, *cursor;
7430 HRESULT ret;
7431 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7433 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7434 TRACE("enumerating resource %p\n", resource);
7435 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7436 ret = pCallback((IWineD3DResource *) resource, pData);
7437 if(ret == S_FALSE) {
7438 TRACE("Canceling enumeration\n");
7439 break;
7442 return WINED3D_OK;
7445 /**********************************************************
7446 * IWineD3DDevice VTbl follows
7447 **********************************************************/
7449 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7451 /*** IUnknown methods ***/
7452 IWineD3DDeviceImpl_QueryInterface,
7453 IWineD3DDeviceImpl_AddRef,
7454 IWineD3DDeviceImpl_Release,
7455 /*** IWineD3DDevice methods ***/
7456 IWineD3DDeviceImpl_GetParent,
7457 /*** Creation methods**/
7458 IWineD3DDeviceImpl_CreateVertexBuffer,
7459 IWineD3DDeviceImpl_CreateIndexBuffer,
7460 IWineD3DDeviceImpl_CreateStateBlock,
7461 IWineD3DDeviceImpl_CreateSurface,
7462 IWineD3DDeviceImpl_CreateTexture,
7463 IWineD3DDeviceImpl_CreateVolumeTexture,
7464 IWineD3DDeviceImpl_CreateVolume,
7465 IWineD3DDeviceImpl_CreateCubeTexture,
7466 IWineD3DDeviceImpl_CreateQuery,
7467 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7468 IWineD3DDeviceImpl_CreateVertexDeclaration,
7469 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7470 IWineD3DDeviceImpl_CreateVertexShader,
7471 IWineD3DDeviceImpl_CreatePixelShader,
7472 IWineD3DDeviceImpl_CreatePalette,
7473 /*** Odd functions **/
7474 IWineD3DDeviceImpl_Init3D,
7475 IWineD3DDeviceImpl_Uninit3D,
7476 IWineD3DDeviceImpl_SetFullscreen,
7477 IWineD3DDeviceImpl_SetMultithreaded,
7478 IWineD3DDeviceImpl_EvictManagedResources,
7479 IWineD3DDeviceImpl_GetAvailableTextureMem,
7480 IWineD3DDeviceImpl_GetBackBuffer,
7481 IWineD3DDeviceImpl_GetCreationParameters,
7482 IWineD3DDeviceImpl_GetDeviceCaps,
7483 IWineD3DDeviceImpl_GetDirect3D,
7484 IWineD3DDeviceImpl_GetDisplayMode,
7485 IWineD3DDeviceImpl_SetDisplayMode,
7486 IWineD3DDeviceImpl_GetHWND,
7487 IWineD3DDeviceImpl_SetHWND,
7488 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7489 IWineD3DDeviceImpl_GetRasterStatus,
7490 IWineD3DDeviceImpl_GetSwapChain,
7491 IWineD3DDeviceImpl_Reset,
7492 IWineD3DDeviceImpl_SetDialogBoxMode,
7493 IWineD3DDeviceImpl_SetCursorProperties,
7494 IWineD3DDeviceImpl_SetCursorPosition,
7495 IWineD3DDeviceImpl_ShowCursor,
7496 IWineD3DDeviceImpl_TestCooperativeLevel,
7497 /*** Getters and setters **/
7498 IWineD3DDeviceImpl_SetClipPlane,
7499 IWineD3DDeviceImpl_GetClipPlane,
7500 IWineD3DDeviceImpl_SetClipStatus,
7501 IWineD3DDeviceImpl_GetClipStatus,
7502 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7503 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7504 IWineD3DDeviceImpl_SetDepthStencilSurface,
7505 IWineD3DDeviceImpl_GetDepthStencilSurface,
7506 IWineD3DDeviceImpl_SetFVF,
7507 IWineD3DDeviceImpl_GetFVF,
7508 IWineD3DDeviceImpl_SetGammaRamp,
7509 IWineD3DDeviceImpl_GetGammaRamp,
7510 IWineD3DDeviceImpl_SetIndices,
7511 IWineD3DDeviceImpl_GetIndices,
7512 IWineD3DDeviceImpl_SetBaseVertexIndex,
7513 IWineD3DDeviceImpl_GetBaseVertexIndex,
7514 IWineD3DDeviceImpl_SetLight,
7515 IWineD3DDeviceImpl_GetLight,
7516 IWineD3DDeviceImpl_SetLightEnable,
7517 IWineD3DDeviceImpl_GetLightEnable,
7518 IWineD3DDeviceImpl_SetMaterial,
7519 IWineD3DDeviceImpl_GetMaterial,
7520 IWineD3DDeviceImpl_SetNPatchMode,
7521 IWineD3DDeviceImpl_GetNPatchMode,
7522 IWineD3DDeviceImpl_SetPaletteEntries,
7523 IWineD3DDeviceImpl_GetPaletteEntries,
7524 IWineD3DDeviceImpl_SetPixelShader,
7525 IWineD3DDeviceImpl_GetPixelShader,
7526 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7527 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7528 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7529 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7530 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7531 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7532 IWineD3DDeviceImpl_SetRenderState,
7533 IWineD3DDeviceImpl_GetRenderState,
7534 IWineD3DDeviceImpl_SetRenderTarget,
7535 IWineD3DDeviceImpl_GetRenderTarget,
7536 IWineD3DDeviceImpl_SetFrontBackBuffers,
7537 IWineD3DDeviceImpl_SetSamplerState,
7538 IWineD3DDeviceImpl_GetSamplerState,
7539 IWineD3DDeviceImpl_SetScissorRect,
7540 IWineD3DDeviceImpl_GetScissorRect,
7541 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7542 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7543 IWineD3DDeviceImpl_SetStreamSource,
7544 IWineD3DDeviceImpl_GetStreamSource,
7545 IWineD3DDeviceImpl_SetStreamSourceFreq,
7546 IWineD3DDeviceImpl_GetStreamSourceFreq,
7547 IWineD3DDeviceImpl_SetTexture,
7548 IWineD3DDeviceImpl_GetTexture,
7549 IWineD3DDeviceImpl_SetTextureStageState,
7550 IWineD3DDeviceImpl_GetTextureStageState,
7551 IWineD3DDeviceImpl_SetTransform,
7552 IWineD3DDeviceImpl_GetTransform,
7553 IWineD3DDeviceImpl_SetVertexDeclaration,
7554 IWineD3DDeviceImpl_GetVertexDeclaration,
7555 IWineD3DDeviceImpl_SetVertexShader,
7556 IWineD3DDeviceImpl_GetVertexShader,
7557 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7558 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7559 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7560 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7561 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7562 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7563 IWineD3DDeviceImpl_SetViewport,
7564 IWineD3DDeviceImpl_GetViewport,
7565 IWineD3DDeviceImpl_MultiplyTransform,
7566 IWineD3DDeviceImpl_ValidateDevice,
7567 IWineD3DDeviceImpl_ProcessVertices,
7568 /*** State block ***/
7569 IWineD3DDeviceImpl_BeginStateBlock,
7570 IWineD3DDeviceImpl_EndStateBlock,
7571 /*** Scene management ***/
7572 IWineD3DDeviceImpl_BeginScene,
7573 IWineD3DDeviceImpl_EndScene,
7574 IWineD3DDeviceImpl_Present,
7575 IWineD3DDeviceImpl_Clear,
7576 /*** Drawing ***/
7577 IWineD3DDeviceImpl_DrawPrimitive,
7578 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7579 IWineD3DDeviceImpl_DrawPrimitiveUP,
7580 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7581 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7582 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7583 IWineD3DDeviceImpl_DrawRectPatch,
7584 IWineD3DDeviceImpl_DrawTriPatch,
7585 IWineD3DDeviceImpl_DeletePatch,
7586 IWineD3DDeviceImpl_ColorFill,
7587 IWineD3DDeviceImpl_UpdateTexture,
7588 IWineD3DDeviceImpl_UpdateSurface,
7589 IWineD3DDeviceImpl_GetFrontBufferData,
7590 /*** object tracking ***/
7591 IWineD3DDeviceImpl_ResourceReleased,
7592 IWineD3DDeviceImpl_EnumResources
7595 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7597 /*** IUnknown methods ***/
7598 IWineD3DDeviceImpl_QueryInterface,
7599 IWineD3DDeviceImpl_AddRef,
7600 IWineD3DDeviceImpl_Release,
7601 /*** IWineD3DDevice methods ***/
7602 IWineD3DDeviceImpl_GetParent,
7603 /*** Creation methods**/
7604 IWineD3DDeviceImpl_CreateVertexBuffer,
7605 IWineD3DDeviceImpl_CreateIndexBuffer,
7606 IWineD3DDeviceImpl_CreateStateBlock,
7607 IWineD3DDeviceImpl_CreateSurface,
7608 IWineD3DDeviceImpl_CreateTexture,
7609 IWineD3DDeviceImpl_CreateVolumeTexture,
7610 IWineD3DDeviceImpl_CreateVolume,
7611 IWineD3DDeviceImpl_CreateCubeTexture,
7612 IWineD3DDeviceImpl_CreateQuery,
7613 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7614 IWineD3DDeviceImpl_CreateVertexDeclaration,
7615 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7616 IWineD3DDeviceImpl_CreateVertexShader,
7617 IWineD3DDeviceImpl_CreatePixelShader,
7618 IWineD3DDeviceImpl_CreatePalette,
7619 /*** Odd functions **/
7620 IWineD3DDeviceImpl_Init3D,
7621 IWineD3DDeviceImpl_Uninit3D,
7622 IWineD3DDeviceImpl_SetFullscreen,
7623 IWineD3DDeviceImpl_SetMultithreaded,
7624 IWineD3DDeviceImpl_EvictManagedResources,
7625 IWineD3DDeviceImpl_GetAvailableTextureMem,
7626 IWineD3DDeviceImpl_GetBackBuffer,
7627 IWineD3DDeviceImpl_GetCreationParameters,
7628 IWineD3DDeviceImpl_GetDeviceCaps,
7629 IWineD3DDeviceImpl_GetDirect3D,
7630 IWineD3DDeviceImpl_GetDisplayMode,
7631 IWineD3DDeviceImpl_SetDisplayMode,
7632 IWineD3DDeviceImpl_GetHWND,
7633 IWineD3DDeviceImpl_SetHWND,
7634 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7635 IWineD3DDeviceImpl_GetRasterStatus,
7636 IWineD3DDeviceImpl_GetSwapChain,
7637 IWineD3DDeviceImpl_Reset,
7638 IWineD3DDeviceImpl_SetDialogBoxMode,
7639 IWineD3DDeviceImpl_SetCursorProperties,
7640 IWineD3DDeviceImpl_SetCursorPosition,
7641 IWineD3DDeviceImpl_ShowCursor,
7642 IWineD3DDeviceImpl_TestCooperativeLevel,
7643 /*** Getters and setters **/
7644 IWineD3DDeviceImpl_SetClipPlane,
7645 IWineD3DDeviceImpl_GetClipPlane,
7646 IWineD3DDeviceImpl_SetClipStatus,
7647 IWineD3DDeviceImpl_GetClipStatus,
7648 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7649 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7650 IWineD3DDeviceImpl_SetDepthStencilSurface,
7651 IWineD3DDeviceImpl_GetDepthStencilSurface,
7652 IWineD3DDeviceImpl_SetFVF,
7653 IWineD3DDeviceImpl_GetFVF,
7654 IWineD3DDeviceImpl_SetGammaRamp,
7655 IWineD3DDeviceImpl_GetGammaRamp,
7656 IWineD3DDeviceImpl_SetIndices,
7657 IWineD3DDeviceImpl_GetIndices,
7658 IWineD3DDeviceImpl_SetBaseVertexIndex,
7659 IWineD3DDeviceImpl_GetBaseVertexIndex,
7660 IWineD3DDeviceImpl_SetLight,
7661 IWineD3DDeviceImpl_GetLight,
7662 IWineD3DDeviceImpl_SetLightEnable,
7663 IWineD3DDeviceImpl_GetLightEnable,
7664 IWineD3DDeviceImpl_SetMaterial,
7665 IWineD3DDeviceImpl_GetMaterial,
7666 IWineD3DDeviceImpl_SetNPatchMode,
7667 IWineD3DDeviceImpl_GetNPatchMode,
7668 IWineD3DDeviceImpl_SetPaletteEntries,
7669 IWineD3DDeviceImpl_GetPaletteEntries,
7670 IWineD3DDeviceImpl_SetPixelShader,
7671 IWineD3DDeviceImpl_GetPixelShader,
7672 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7673 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7674 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7675 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7676 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7677 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7678 IWineD3DDeviceImpl_SetRenderState,
7679 IWineD3DDeviceImpl_GetRenderState,
7680 IWineD3DDeviceImpl_SetRenderTarget,
7681 IWineD3DDeviceImpl_GetRenderTarget,
7682 IWineD3DDeviceImpl_SetFrontBackBuffers,
7683 IWineD3DDeviceImpl_SetSamplerState,
7684 IWineD3DDeviceImpl_GetSamplerState,
7685 IWineD3DDeviceImpl_SetScissorRect,
7686 IWineD3DDeviceImpl_GetScissorRect,
7687 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7688 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7689 IWineD3DDeviceImpl_SetStreamSource,
7690 IWineD3DDeviceImpl_GetStreamSource,
7691 IWineD3DDeviceImpl_SetStreamSourceFreq,
7692 IWineD3DDeviceImpl_GetStreamSourceFreq,
7693 IWineD3DDeviceImpl_SetTexture,
7694 IWineD3DDeviceImpl_GetTexture,
7695 IWineD3DDeviceImpl_SetTextureStageState,
7696 IWineD3DDeviceImpl_GetTextureStageState,
7697 IWineD3DDeviceImpl_SetTransform,
7698 IWineD3DDeviceImpl_GetTransform,
7699 IWineD3DDeviceImpl_SetVertexDeclaration,
7700 IWineD3DDeviceImpl_GetVertexDeclaration,
7701 IWineD3DDeviceImpl_SetVertexShader,
7702 IWineD3DDeviceImpl_GetVertexShader,
7703 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7704 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7705 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7706 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7707 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7708 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7709 IWineD3DDeviceImpl_SetViewport,
7710 IWineD3DDeviceImpl_GetViewport,
7711 IWineD3DDeviceImpl_MultiplyTransform,
7712 IWineD3DDeviceImpl_ValidateDevice,
7713 IWineD3DDeviceImpl_ProcessVertices,
7714 /*** State block ***/
7715 IWineD3DDeviceImpl_BeginStateBlock,
7716 IWineD3DDeviceImpl_EndStateBlock,
7717 /*** Scene management ***/
7718 IWineD3DDeviceImpl_BeginScene,
7719 IWineD3DDeviceImpl_EndScene,
7720 IWineD3DDeviceImpl_Present,
7721 IWineD3DDeviceImpl_Clear,
7722 /*** Drawing ***/
7723 IWineD3DDeviceImpl_DrawPrimitive,
7724 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7725 IWineD3DDeviceImpl_DrawPrimitiveUP,
7726 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7727 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7728 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7729 IWineD3DDeviceImpl_DrawRectPatch,
7730 IWineD3DDeviceImpl_DrawTriPatch,
7731 IWineD3DDeviceImpl_DeletePatch,
7732 IWineD3DDeviceImpl_ColorFill,
7733 IWineD3DDeviceImpl_UpdateTexture,
7734 IWineD3DDeviceImpl_UpdateSurface,
7735 IWineD3DDeviceImpl_GetFrontBufferData,
7736 /*** object tracking ***/
7737 IWineD3DDeviceImpl_ResourceReleased,
7738 IWineD3DDeviceImpl_EnumResources
7741 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7742 WINED3DRS_ALPHABLENDENABLE ,
7743 WINED3DRS_ALPHAFUNC ,
7744 WINED3DRS_ALPHAREF ,
7745 WINED3DRS_ALPHATESTENABLE ,
7746 WINED3DRS_BLENDOP ,
7747 WINED3DRS_COLORWRITEENABLE ,
7748 WINED3DRS_DESTBLEND ,
7749 WINED3DRS_DITHERENABLE ,
7750 WINED3DRS_FILLMODE ,
7751 WINED3DRS_FOGDENSITY ,
7752 WINED3DRS_FOGEND ,
7753 WINED3DRS_FOGSTART ,
7754 WINED3DRS_LASTPIXEL ,
7755 WINED3DRS_SHADEMODE ,
7756 WINED3DRS_SRCBLEND ,
7757 WINED3DRS_STENCILENABLE ,
7758 WINED3DRS_STENCILFAIL ,
7759 WINED3DRS_STENCILFUNC ,
7760 WINED3DRS_STENCILMASK ,
7761 WINED3DRS_STENCILPASS ,
7762 WINED3DRS_STENCILREF ,
7763 WINED3DRS_STENCILWRITEMASK ,
7764 WINED3DRS_STENCILZFAIL ,
7765 WINED3DRS_TEXTUREFACTOR ,
7766 WINED3DRS_WRAP0 ,
7767 WINED3DRS_WRAP1 ,
7768 WINED3DRS_WRAP2 ,
7769 WINED3DRS_WRAP3 ,
7770 WINED3DRS_WRAP4 ,
7771 WINED3DRS_WRAP5 ,
7772 WINED3DRS_WRAP6 ,
7773 WINED3DRS_WRAP7 ,
7774 WINED3DRS_ZENABLE ,
7775 WINED3DRS_ZFUNC ,
7776 WINED3DRS_ZWRITEENABLE
7779 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7780 WINED3DTSS_ADDRESSW ,
7781 WINED3DTSS_ALPHAARG0 ,
7782 WINED3DTSS_ALPHAARG1 ,
7783 WINED3DTSS_ALPHAARG2 ,
7784 WINED3DTSS_ALPHAOP ,
7785 WINED3DTSS_BUMPENVLOFFSET ,
7786 WINED3DTSS_BUMPENVLSCALE ,
7787 WINED3DTSS_BUMPENVMAT00 ,
7788 WINED3DTSS_BUMPENVMAT01 ,
7789 WINED3DTSS_BUMPENVMAT10 ,
7790 WINED3DTSS_BUMPENVMAT11 ,
7791 WINED3DTSS_COLORARG0 ,
7792 WINED3DTSS_COLORARG1 ,
7793 WINED3DTSS_COLORARG2 ,
7794 WINED3DTSS_COLOROP ,
7795 WINED3DTSS_RESULTARG ,
7796 WINED3DTSS_TEXCOORDINDEX ,
7797 WINED3DTSS_TEXTURETRANSFORMFLAGS
7800 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7801 WINED3DSAMP_ADDRESSU ,
7802 WINED3DSAMP_ADDRESSV ,
7803 WINED3DSAMP_ADDRESSW ,
7804 WINED3DSAMP_BORDERCOLOR ,
7805 WINED3DSAMP_MAGFILTER ,
7806 WINED3DSAMP_MINFILTER ,
7807 WINED3DSAMP_MIPFILTER ,
7808 WINED3DSAMP_MIPMAPLODBIAS ,
7809 WINED3DSAMP_MAXMIPLEVEL ,
7810 WINED3DSAMP_MAXANISOTROPY ,
7811 WINED3DSAMP_SRGBTEXTURE ,
7812 WINED3DSAMP_ELEMENTINDEX
7815 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7816 WINED3DRS_AMBIENT ,
7817 WINED3DRS_AMBIENTMATERIALSOURCE ,
7818 WINED3DRS_CLIPPING ,
7819 WINED3DRS_CLIPPLANEENABLE ,
7820 WINED3DRS_COLORVERTEX ,
7821 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7822 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7823 WINED3DRS_FOGDENSITY ,
7824 WINED3DRS_FOGEND ,
7825 WINED3DRS_FOGSTART ,
7826 WINED3DRS_FOGTABLEMODE ,
7827 WINED3DRS_FOGVERTEXMODE ,
7828 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7829 WINED3DRS_LIGHTING ,
7830 WINED3DRS_LOCALVIEWER ,
7831 WINED3DRS_MULTISAMPLEANTIALIAS ,
7832 WINED3DRS_MULTISAMPLEMASK ,
7833 WINED3DRS_NORMALIZENORMALS ,
7834 WINED3DRS_PATCHEDGESTYLE ,
7835 WINED3DRS_POINTSCALE_A ,
7836 WINED3DRS_POINTSCALE_B ,
7837 WINED3DRS_POINTSCALE_C ,
7838 WINED3DRS_POINTSCALEENABLE ,
7839 WINED3DRS_POINTSIZE ,
7840 WINED3DRS_POINTSIZE_MAX ,
7841 WINED3DRS_POINTSIZE_MIN ,
7842 WINED3DRS_POINTSPRITEENABLE ,
7843 WINED3DRS_RANGEFOGENABLE ,
7844 WINED3DRS_SPECULARMATERIALSOURCE ,
7845 WINED3DRS_TWEENFACTOR ,
7846 WINED3DRS_VERTEXBLEND ,
7847 WINED3DRS_CULLMODE ,
7848 WINED3DRS_FOGCOLOR
7851 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7852 WINED3DTSS_TEXCOORDINDEX ,
7853 WINED3DTSS_TEXTURETRANSFORMFLAGS
7856 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7857 WINED3DSAMP_DMAPOFFSET
7860 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7861 DWORD rep = This->shader_backend->StateTable[state].representative;
7862 DWORD idx;
7863 BYTE shift;
7864 UINT i;
7865 WineD3DContext *context;
7867 if(!rep) return;
7868 for(i = 0; i < This->numContexts; i++) {
7869 context = This->contexts[i];
7870 if(isStateDirty(context, rep)) continue;
7872 context->dirtyArray[context->numDirtyEntries++] = rep;
7873 idx = rep >> 5;
7874 shift = rep & 0x1f;
7875 context->isStateDirty[idx] |= (1 << shift);
7879 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7880 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7881 /* The drawable size of a pbuffer render target is the current pbuffer size
7883 *width = dev->pbufferWidth;
7884 *height = dev->pbufferHeight;
7887 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7888 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7890 *width = This->pow2Width;
7891 *height = This->pow2Height;
7894 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7895 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7896 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7897 * current context's drawable, which is the size of the back buffer of the swapchain
7898 * the active context belongs to. The back buffer of the swapchain is stored as the
7899 * surface the context belongs to.
7901 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7902 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;