wined3d: Improve detection of device palette change.
[wine.git] / dlls / wined3d / device.c
blob76ab604a0d702bfcfd357bff13d60a64c900b0a3
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-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);
771 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
772 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
773 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
775 if((Usage & (WINED3DUSAGE_AUTOGENMIPMAP | WINED3DUSAGE_RENDERTARGET)) ==
776 (WINED3DUSAGE_AUTOGENMIPMAP | WINED3DUSAGE_RENDERTARGET)) {
777 WARN("Application requests both D3DUSAGE_AUTOGENMIPMAP and D3DUSAGE_RENDERTARGET, which are mutually exclusive\n");
778 return WINED3DERR_INVALIDCALL;
781 /* TODO: It should only be possible to create textures for formats
782 that are reported as supported */
783 if (WINED3DFMT_UNKNOWN >= Format) {
784 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
785 return WINED3DERR_INVALIDCALL;
788 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
789 D3DINITIALIZEBASETEXTURE(object->baseTexture);
790 object->width = Width;
791 object->height = Height;
793 /** Non-power2 support **/
794 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
795 pow2Width = Width;
796 pow2Height = Height;
797 } else {
798 /* Find the nearest pow2 match */
799 pow2Width = pow2Height = 1;
800 while (pow2Width < Width) pow2Width <<= 1;
801 while (pow2Height < Height) pow2Height <<= 1;
803 if(pow2Width != Width || pow2Height != Height) {
804 if(Levels > 1) {
805 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
806 HeapFree(GetProcessHeap(), 0, object);
807 *ppTexture = NULL;
808 return WINED3DERR_INVALIDCALL;
809 } else {
810 Levels = 1;
815 /** FIXME: add support for real non-power-two if it's provided by the video card **/
816 /* Precalculated scaling for 'faked' non power of two texture coords.
817 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
818 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
819 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
821 if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
822 (Width != pow2Width || Height != pow2Height) &&
823 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
825 object->baseTexture.pow2Matrix[0] = (float)Width;
826 object->baseTexture.pow2Matrix[5] = (float)Height;
827 object->baseTexture.pow2Matrix[10] = 1.0;
828 object->baseTexture.pow2Matrix[15] = 1.0;
829 object->target = GL_TEXTURE_RECTANGLE_ARB;
830 } else {
831 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
832 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
833 object->baseTexture.pow2Matrix[10] = 1.0;
834 object->baseTexture.pow2Matrix[15] = 1.0;
835 object->target = GL_TEXTURE_2D;
837 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
839 /* Calculate levels for mip mapping */
840 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
841 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
842 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
843 return WINED3DERR_INVALIDCALL;
845 if(Levels > 1) {
846 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
847 return WINED3DERR_INVALIDCALL;
849 object->baseTexture.levels = 1;
850 } else if (Levels == 0) {
851 TRACE("calculating levels %d\n", object->baseTexture.levels);
852 object->baseTexture.levels++;
853 tmpW = Width;
854 tmpH = Height;
855 while (tmpW > 1 || tmpH > 1) {
856 tmpW = max(1, tmpW >> 1);
857 tmpH = max(1, tmpH >> 1);
858 object->baseTexture.levels++;
860 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
863 /* Generate all the surfaces */
864 tmpW = Width;
865 tmpH = Height;
866 for (i = 0; i < object->baseTexture.levels; i++)
868 /* use the callback to create the texture surface */
869 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
870 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
871 FIXME("Failed to create surface %p\n", object);
872 /* clean up */
873 object->surfaces[i] = NULL;
874 IWineD3DTexture_Release((IWineD3DTexture *)object);
876 *ppTexture = NULL;
877 return hr;
880 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
881 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
882 /* calculate the next mipmap level */
883 tmpW = max(1, tmpW >> 1);
884 tmpH = max(1, tmpH >> 1);
886 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
888 TRACE("(%p) : Created texture %p\n", This, object);
889 return WINED3D_OK;
892 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
893 UINT Width, UINT Height, UINT Depth,
894 UINT Levels, DWORD Usage,
895 WINED3DFORMAT Format, WINED3DPOOL Pool,
896 IWineD3DVolumeTexture **ppVolumeTexture,
897 HANDLE *pSharedHandle, IUnknown *parent,
898 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
901 IWineD3DVolumeTextureImpl *object;
902 unsigned int i;
903 UINT tmpW;
904 UINT tmpH;
905 UINT tmpD;
906 const GlPixelFormatDesc *glDesc;
908 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
910 /* TODO: It should only be possible to create textures for formats
911 that are reported as supported */
912 if (WINED3DFMT_UNKNOWN >= Format) {
913 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
914 return WINED3DERR_INVALIDCALL;
916 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
917 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
918 return WINED3DERR_INVALIDCALL;
921 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
922 D3DINITIALIZEBASETEXTURE(object->baseTexture);
924 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
925 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
927 object->width = Width;
928 object->height = Height;
929 object->depth = Depth;
931 /* Is NP2 support for volumes needed? */
932 object->baseTexture.pow2Matrix[ 0] = 1.0;
933 object->baseTexture.pow2Matrix[ 5] = 1.0;
934 object->baseTexture.pow2Matrix[10] = 1.0;
935 object->baseTexture.pow2Matrix[15] = 1.0;
937 /* Calculate levels for mip mapping */
938 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
939 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
940 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
941 return WINED3DERR_INVALIDCALL;
943 if(Levels > 1) {
944 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
945 return WINED3DERR_INVALIDCALL;
947 Levels = 1;
948 } else if (Levels == 0) {
949 object->baseTexture.levels++;
950 tmpW = Width;
951 tmpH = Height;
952 tmpD = Depth;
953 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
954 tmpW = max(1, tmpW >> 1);
955 tmpH = max(1, tmpH >> 1);
956 tmpD = max(1, tmpD >> 1);
957 object->baseTexture.levels++;
959 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
962 /* Generate all the surfaces */
963 tmpW = Width;
964 tmpH = Height;
965 tmpD = Depth;
967 for (i = 0; i < object->baseTexture.levels; i++)
969 HRESULT hr;
970 /* Create the volume */
971 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
972 &object->volumes[i], pSharedHandle);
974 if(FAILED(hr)) {
975 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
976 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
977 *ppVolumeTexture = NULL;
978 return hr;
981 /* Set its container to this object */
982 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
984 /* calculate the next mipmap level */
985 tmpW = max(1, tmpW >> 1);
986 tmpH = max(1, tmpH >> 1);
987 tmpD = max(1, tmpD >> 1);
989 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
991 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
992 TRACE("(%p) : Created volume texture %p\n", This, object);
993 return WINED3D_OK;
996 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
997 UINT Width, UINT Height, UINT Depth,
998 DWORD Usage,
999 WINED3DFORMAT Format, WINED3DPOOL Pool,
1000 IWineD3DVolume** ppVolume,
1001 HANDLE* pSharedHandle, IUnknown *parent) {
1003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1004 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1005 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1007 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1008 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1009 return WINED3DERR_INVALIDCALL;
1012 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1014 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1015 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1017 object->currentDesc.Width = Width;
1018 object->currentDesc.Height = Height;
1019 object->currentDesc.Depth = Depth;
1020 object->bytesPerPixel = formatDesc->bpp;
1022 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1023 object->lockable = TRUE;
1024 object->locked = FALSE;
1025 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1026 object->dirty = TRUE;
1028 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1031 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1032 UINT Levels, DWORD Usage,
1033 WINED3DFORMAT Format, WINED3DPOOL Pool,
1034 IWineD3DCubeTexture **ppCubeTexture,
1035 HANDLE *pSharedHandle, IUnknown *parent,
1036 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1039 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1040 unsigned int i, j;
1041 UINT tmpW;
1042 HRESULT hr;
1043 unsigned int pow2EdgeLength = EdgeLength;
1044 const GlPixelFormatDesc *glDesc;
1045 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1047 if((Usage & (WINED3DUSAGE_AUTOGENMIPMAP | WINED3DUSAGE_RENDERTARGET)) ==
1048 (WINED3DUSAGE_AUTOGENMIPMAP | WINED3DUSAGE_RENDERTARGET)) {
1049 WARN("Application requests both D3DUSAGE_AUTOGENMIPMAP and D3DUSAGE_RENDERTARGET, which are mutually exclusive\n");
1050 return WINED3DERR_INVALIDCALL;
1053 /* TODO: It should only be possible to create textures for formats
1054 that are reported as supported */
1055 if (WINED3DFMT_UNKNOWN >= Format) {
1056 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1057 return WINED3DERR_INVALIDCALL;
1060 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1061 WARN("(%p) : Tried to create not supported cube texture\n", This);
1062 return WINED3DERR_INVALIDCALL;
1065 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1066 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1068 TRACE("(%p) Create Cube Texture\n", This);
1070 /** Non-power2 support **/
1072 /* Find the nearest pow2 match */
1073 pow2EdgeLength = 1;
1074 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1076 object->edgeLength = EdgeLength;
1077 /* TODO: support for native non-power 2 */
1078 /* Precalculated scaling for 'faked' non power of two texture coords */
1079 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1080 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1081 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1082 object->baseTexture.pow2Matrix[15] = 1.0;
1084 /* Calculate levels for mip mapping */
1085 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1086 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1087 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1088 HeapFree(GetProcessHeap(), 0, object);
1089 *ppCubeTexture = NULL;
1091 return WINED3DERR_INVALIDCALL;
1093 if(Levels > 1) {
1094 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1095 HeapFree(GetProcessHeap(), 0, object);
1096 *ppCubeTexture = NULL;
1098 return WINED3DERR_INVALIDCALL;
1100 Levels = 1;
1101 } else if (Levels == 0) {
1102 object->baseTexture.levels++;
1103 tmpW = EdgeLength;
1104 while (tmpW > 1) {
1105 tmpW = max(1, tmpW >> 1);
1106 object->baseTexture.levels++;
1108 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1111 /* Generate all the surfaces */
1112 tmpW = EdgeLength;
1113 for (i = 0; i < object->baseTexture.levels; i++) {
1115 /* Create the 6 faces */
1116 for (j = 0; j < 6; j++) {
1118 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1119 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1121 if(hr!= WINED3D_OK) {
1122 /* clean up */
1123 int k;
1124 int l;
1125 for (l = 0; l < j; l++) {
1126 IWineD3DSurface_Release(object->surfaces[l][i]);
1128 for (k = 0; k < i; k++) {
1129 for (l = 0; l < 6; l++) {
1130 IWineD3DSurface_Release(object->surfaces[l][k]);
1134 FIXME("(%p) Failed to create surface\n",object);
1135 HeapFree(GetProcessHeap(),0,object);
1136 *ppCubeTexture = NULL;
1137 return hr;
1139 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1140 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1142 tmpW = max(1, tmpW >> 1);
1144 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1146 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1147 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1148 return WINED3D_OK;
1151 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1153 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1154 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1155 const IWineD3DQueryVtbl *vtable;
1157 /* Just a check to see if we support this type of query */
1158 switch(Type) {
1159 case WINED3DQUERYTYPE_OCCLUSION:
1160 TRACE("(%p) occlusion query\n", This);
1161 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1162 hr = WINED3D_OK;
1163 else
1164 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1166 vtable = &IWineD3DOcclusionQuery_Vtbl;
1167 break;
1169 case WINED3DQUERYTYPE_EVENT:
1170 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1171 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1172 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1174 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1176 vtable = &IWineD3DEventQuery_Vtbl;
1177 hr = WINED3D_OK;
1178 break;
1180 case WINED3DQUERYTYPE_VCACHE:
1181 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1182 case WINED3DQUERYTYPE_VERTEXSTATS:
1183 case WINED3DQUERYTYPE_TIMESTAMP:
1184 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1185 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1186 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1187 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1188 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1189 case WINED3DQUERYTYPE_PIXELTIMINGS:
1190 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1191 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1192 default:
1193 /* Use the base Query vtable until we have a special one for each query */
1194 vtable = &IWineD3DQuery_Vtbl;
1195 FIXME("(%p) Unhandled query type %d\n", This, Type);
1197 if(NULL == ppQuery || hr != WINED3D_OK) {
1198 return hr;
1201 D3DCREATEOBJECTINSTANCE(object, Query)
1202 object->lpVtbl = vtable;
1203 object->type = Type;
1204 object->state = QUERY_CREATED;
1205 /* allocated the 'extended' data based on the type of query requested */
1206 switch(Type){
1207 case WINED3DQUERYTYPE_OCCLUSION:
1208 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1209 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1211 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1212 TRACE("(%p) Allocating data for an occlusion query\n", This);
1213 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1214 break;
1216 case WINED3DQUERYTYPE_EVENT:
1217 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1218 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1220 if(GL_SUPPORT(APPLE_FENCE)) {
1221 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1222 checkGLcall("glGenFencesAPPLE");
1223 } else if(GL_SUPPORT(NV_FENCE)) {
1224 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1225 checkGLcall("glGenFencesNV");
1227 break;
1229 case WINED3DQUERYTYPE_VCACHE:
1230 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1231 case WINED3DQUERYTYPE_VERTEXSTATS:
1232 case WINED3DQUERYTYPE_TIMESTAMP:
1233 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1234 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1235 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1236 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1237 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1238 case WINED3DQUERYTYPE_PIXELTIMINGS:
1239 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1240 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1241 default:
1242 object->extendedData = 0;
1243 FIXME("(%p) Unhandled query type %d\n",This , Type);
1245 TRACE("(%p) : Created Query %p\n", This, object);
1246 return WINED3D_OK;
1249 /*****************************************************************************
1250 * IWineD3DDeviceImpl_SetupFullscreenWindow
1252 * Helper function that modifies a HWND's Style and ExStyle for proper
1253 * fullscreen use.
1255 * Params:
1256 * iface: Pointer to the IWineD3DDevice interface
1257 * window: Window to setup
1259 *****************************************************************************/
1260 static LONG fullscreen_style(LONG orig_style) {
1261 LONG style = orig_style;
1262 style &= ~WS_CAPTION;
1263 style &= ~WS_THICKFRAME;
1265 /* Make sure the window is managed, otherwise we won't get keyboard input */
1266 style |= WS_POPUP | WS_SYSMENU;
1268 return style;
1271 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1272 LONG exStyle = orig_exStyle;
1274 /* Filter out window decorations */
1275 exStyle &= ~WS_EX_WINDOWEDGE;
1276 exStyle &= ~WS_EX_CLIENTEDGE;
1278 return exStyle;
1281 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1284 LONG style, exStyle;
1285 /* Don't do anything if an original style is stored.
1286 * That shouldn't happen
1288 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1289 if (This->style || This->exStyle) {
1290 ERR("(%p): Want to change the window parameters of HWND %p, but "
1291 "another style is stored for restoration afterwards\n", This, window);
1294 /* Get the parameters and save them */
1295 style = GetWindowLongW(window, GWL_STYLE);
1296 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1297 This->style = style;
1298 This->exStyle = exStyle;
1300 style = fullscreen_style(style);
1301 exStyle = fullscreen_exStyle(exStyle);
1303 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1304 This->style, This->exStyle, style, exStyle);
1306 SetWindowLongW(window, GWL_STYLE, style);
1307 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1309 /* Inform the window about the update. */
1310 SetWindowPos(window, HWND_TOP, 0, 0,
1311 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1312 ShowWindow(window, SW_NORMAL);
1315 /*****************************************************************************
1316 * IWineD3DDeviceImpl_RestoreWindow
1318 * Helper function that restores a windows' properties when taking it out
1319 * of fullscreen mode
1321 * Params:
1322 * iface: Pointer to the IWineD3DDevice interface
1323 * window: Window to setup
1325 *****************************************************************************/
1326 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1327 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1328 LONG style, exStyle;
1330 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1331 * switch, do nothing
1333 if (!This->style && !This->exStyle) return;
1335 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1336 This, window, This->style, This->exStyle);
1338 style = GetWindowLongW(window, GWL_STYLE);
1339 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1341 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1342 * Some applications change it before calling Reset() when switching between windowed and
1343 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1345 if(style == fullscreen_style(This->style) &&
1346 exStyle == fullscreen_style(This->exStyle)) {
1347 SetWindowLongW(window, GWL_STYLE, This->style);
1348 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1351 /* Delete the old values */
1352 This->style = 0;
1353 This->exStyle = 0;
1355 /* Inform the window about the update */
1356 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1357 0, 0, 0, 0, /* Pos, Size, ignored */
1358 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1361 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1362 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1363 IUnknown* parent,
1364 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1365 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1368 HDC hDc;
1369 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1370 HRESULT hr = WINED3D_OK;
1371 IUnknown *bufferParent;
1372 BOOL displaymode_set = FALSE;
1373 WINED3DDISPLAYMODE Mode;
1374 const StaticPixelFormatDesc *formatDesc;
1376 TRACE("(%p) : Created Additional Swap Chain\n", This);
1378 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1379 * does a device hold a reference to a swap chain giving them a lifetime of the device
1380 * or does the swap chain notify the device of its destruction.
1381 *******************************/
1383 /* Check the params */
1384 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1385 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1386 return WINED3DERR_INVALIDCALL;
1387 } else if (pPresentationParameters->BackBufferCount > 1) {
1388 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");
1391 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1393 /*********************
1394 * Lookup the window Handle and the relating X window handle
1395 ********************/
1397 /* Setup hwnd we are using, plus which display this equates to */
1398 object->win_handle = pPresentationParameters->hDeviceWindow;
1399 if (!object->win_handle) {
1400 object->win_handle = This->createParms.hFocusWindow;
1402 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1404 hDc = GetDC(object->win_handle);
1405 TRACE("Using hDc %p\n", hDc);
1407 if (NULL == hDc) {
1408 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1409 return WINED3DERR_NOTAVAILABLE;
1412 /* Get info on the current display setup */
1413 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1414 object->orig_width = Mode.Width;
1415 object->orig_height = Mode.Height;
1416 object->orig_fmt = Mode.Format;
1417 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1419 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1420 * then the corresponding dimension of the client area of the hDeviceWindow
1421 * (or the focus window, if hDeviceWindow is NULL) is taken.
1422 **********************/
1424 if (pPresentationParameters->Windowed &&
1425 ((pPresentationParameters->BackBufferWidth == 0) ||
1426 (pPresentationParameters->BackBufferHeight == 0) ||
1427 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1429 RECT Rect;
1430 GetClientRect(object->win_handle, &Rect);
1432 if (pPresentationParameters->BackBufferWidth == 0) {
1433 pPresentationParameters->BackBufferWidth = Rect.right;
1434 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1436 if (pPresentationParameters->BackBufferHeight == 0) {
1437 pPresentationParameters->BackBufferHeight = Rect.bottom;
1438 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1440 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1441 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1442 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1446 /* Put the correct figures in the presentation parameters */
1447 TRACE("Copying across presentation parameters\n");
1448 object->presentParms = *pPresentationParameters;
1450 TRACE("calling rendertarget CB\n");
1451 hr = D3DCB_CreateRenderTarget(This->parent,
1452 parent,
1453 object->presentParms.BackBufferWidth,
1454 object->presentParms.BackBufferHeight,
1455 object->presentParms.BackBufferFormat,
1456 object->presentParms.MultiSampleType,
1457 object->presentParms.MultiSampleQuality,
1458 TRUE /* Lockable */,
1459 &object->frontBuffer,
1460 NULL /* pShared (always null)*/);
1461 if (object->frontBuffer != NULL) {
1462 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1463 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1464 } else {
1465 ERR("Failed to create the front buffer\n");
1466 goto error;
1469 /*********************
1470 * Windowed / Fullscreen
1471 *******************/
1474 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1475 * so we should really check to see if there is a fullscreen swapchain already
1476 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1477 **************************************/
1479 if (!pPresentationParameters->Windowed) {
1480 WINED3DDISPLAYMODE mode;
1483 /* Change the display settings */
1484 mode.Width = pPresentationParameters->BackBufferWidth;
1485 mode.Height = pPresentationParameters->BackBufferHeight;
1486 mode.Format = pPresentationParameters->BackBufferFormat;
1487 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1489 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1490 displaymode_set = TRUE;
1491 IWineD3DDevice_SetFullscreen(iface, TRUE);
1495 * Create an opengl context for the display visual
1496 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1497 * use different properties after that point in time. FIXME: How to handle when requested format
1498 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1499 * it chooses is identical to the one already being used!
1500 **********************************/
1501 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1503 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1504 if(!object->context)
1505 return E_OUTOFMEMORY;
1506 object->num_contexts = 1;
1508 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1509 if (!object->context[0]) {
1510 ERR("Failed to create a new context\n");
1511 hr = WINED3DERR_NOTAVAILABLE;
1512 goto error;
1513 } else {
1514 TRACE("Context created (HWND=%p, glContext=%p)\n",
1515 object->win_handle, object->context[0]->glCtx);
1518 /*********************
1519 * Create the back, front and stencil buffers
1520 *******************/
1521 if(object->presentParms.BackBufferCount > 0) {
1522 int i;
1524 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1525 if(!object->backBuffer) {
1526 ERR("Out of memory\n");
1527 hr = E_OUTOFMEMORY;
1528 goto error;
1531 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1532 TRACE("calling rendertarget CB\n");
1533 hr = D3DCB_CreateRenderTarget(This->parent,
1534 parent,
1535 object->presentParms.BackBufferWidth,
1536 object->presentParms.BackBufferHeight,
1537 object->presentParms.BackBufferFormat,
1538 object->presentParms.MultiSampleType,
1539 object->presentParms.MultiSampleQuality,
1540 TRUE /* Lockable */,
1541 &object->backBuffer[i],
1542 NULL /* pShared (always null)*/);
1543 if(hr == WINED3D_OK && object->backBuffer[i]) {
1544 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1545 } else {
1546 ERR("Cannot create new back buffer\n");
1547 goto error;
1549 ENTER_GL();
1550 glDrawBuffer(GL_BACK);
1551 checkGLcall("glDrawBuffer(GL_BACK)");
1552 LEAVE_GL();
1554 } else {
1555 object->backBuffer = NULL;
1557 /* Single buffering - draw to front buffer */
1558 ENTER_GL();
1559 glDrawBuffer(GL_FRONT);
1560 checkGLcall("glDrawBuffer(GL_FRONT)");
1561 LEAVE_GL();
1564 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1565 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1566 TRACE("Creating depth stencil buffer\n");
1567 if (This->auto_depth_stencil_buffer == NULL ) {
1568 hr = D3DCB_CreateDepthStencil(This->parent,
1569 parent,
1570 object->presentParms.BackBufferWidth,
1571 object->presentParms.BackBufferHeight,
1572 object->presentParms.AutoDepthStencilFormat,
1573 object->presentParms.MultiSampleType,
1574 object->presentParms.MultiSampleQuality,
1575 FALSE /* FIXME: Discard */,
1576 &This->auto_depth_stencil_buffer,
1577 NULL /* pShared (always null)*/ );
1578 if (This->auto_depth_stencil_buffer != NULL)
1579 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1582 /** TODO: A check on width, height and multisample types
1583 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1584 ****************************/
1585 object->wantsDepthStencilBuffer = TRUE;
1586 } else {
1587 object->wantsDepthStencilBuffer = FALSE;
1590 TRACE("Created swapchain %p\n", object);
1591 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1592 return WINED3D_OK;
1594 error:
1595 if (displaymode_set) {
1596 DEVMODEW devmode;
1597 RECT clip_rc;
1599 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1600 ClipCursor(NULL);
1602 /* Change the display settings */
1603 memset(&devmode, 0, sizeof(devmode));
1604 devmode.dmSize = sizeof(devmode);
1605 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1606 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1607 devmode.dmPelsWidth = object->orig_width;
1608 devmode.dmPelsHeight = object->orig_height;
1609 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1612 if (object->backBuffer) {
1613 int i;
1614 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1615 if(object->backBuffer[i]) {
1616 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1617 IUnknown_Release(bufferParent); /* once for the get parent */
1618 if (IUnknown_Release(bufferParent) > 0) {
1619 FIXME("(%p) Something's still holding the back buffer\n",This);
1623 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1624 object->backBuffer = NULL;
1626 if(object->context[0])
1627 DestroyContext(This, object->context[0]);
1628 if(object->frontBuffer) {
1629 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1630 IUnknown_Release(bufferParent); /* once for the get parent */
1631 if (IUnknown_Release(bufferParent) > 0) {
1632 FIXME("(%p) Something's still holding the front buffer\n",This);
1635 HeapFree(GetProcessHeap(), 0, object);
1636 return hr;
1639 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1640 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1642 TRACE("(%p)\n", This);
1644 return This->NumberOfSwapChains;
1647 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1649 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1651 if(iSwapChain < This->NumberOfSwapChains) {
1652 *pSwapChain = This->swapchains[iSwapChain];
1653 IWineD3DSwapChain_AddRef(*pSwapChain);
1654 TRACE("(%p) returning %p\n", This, *pSwapChain);
1655 return WINED3D_OK;
1656 } else {
1657 TRACE("Swapchain out of range\n");
1658 *pSwapChain = NULL;
1659 return WINED3DERR_INVALIDCALL;
1663 /*****
1664 * Vertex Declaration
1665 *****/
1666 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1667 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1669 IWineD3DVertexDeclarationImpl *object = NULL;
1670 HRESULT hr = WINED3D_OK;
1672 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1673 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1675 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1677 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1678 if(FAILED(hr)) {
1679 *ppVertexDeclaration = NULL;
1680 HeapFree(GetProcessHeap(), 0, object);
1683 return hr;
1686 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1687 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1689 unsigned int idx, idx2;
1690 unsigned int offset;
1691 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1692 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1693 BOOL has_blend_idx = has_blend &&
1694 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1695 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1696 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1697 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1698 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1699 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1700 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1702 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1703 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1705 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1706 WINED3DVERTEXELEMENT *elements = NULL;
1708 unsigned int size;
1709 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1710 if (has_blend_idx) num_blends--;
1712 /* Compute declaration size */
1713 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1714 has_psize + has_diffuse + has_specular + num_textures + 1;
1716 /* convert the declaration */
1717 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1718 if (!elements)
1719 return 0;
1721 elements[size-1] = end_element;
1722 idx = 0;
1723 if (has_pos) {
1724 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1725 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1726 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1728 else {
1729 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1730 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1732 elements[idx].UsageIndex = 0;
1733 idx++;
1735 if (has_blend && (num_blends > 0)) {
1736 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1737 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1738 else
1739 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1740 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1741 elements[idx].UsageIndex = 0;
1742 idx++;
1744 if (has_blend_idx) {
1745 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1746 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1747 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1748 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1749 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1750 else
1751 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1752 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1753 elements[idx].UsageIndex = 0;
1754 idx++;
1756 if (has_normal) {
1757 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1758 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1759 elements[idx].UsageIndex = 0;
1760 idx++;
1762 if (has_psize) {
1763 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1764 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1765 elements[idx].UsageIndex = 0;
1766 idx++;
1768 if (has_diffuse) {
1769 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1770 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1771 elements[idx].UsageIndex = 0;
1772 idx++;
1774 if (has_specular) {
1775 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1776 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1777 elements[idx].UsageIndex = 1;
1778 idx++;
1780 for (idx2 = 0; idx2 < num_textures; idx2++) {
1781 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1782 switch (numcoords) {
1783 case WINED3DFVF_TEXTUREFORMAT1:
1784 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1785 break;
1786 case WINED3DFVF_TEXTUREFORMAT2:
1787 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1788 break;
1789 case WINED3DFVF_TEXTUREFORMAT3:
1790 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1791 break;
1792 case WINED3DFVF_TEXTUREFORMAT4:
1793 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1794 break;
1796 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1797 elements[idx].UsageIndex = idx2;
1798 idx++;
1801 /* Now compute offsets, and initialize the rest of the fields */
1802 for (idx = 0, offset = 0; idx < size-1; idx++) {
1803 elements[idx].Stream = 0;
1804 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1805 elements[idx].Offset = offset;
1806 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1809 *ppVertexElements = elements;
1810 return size;
1813 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1814 WINED3DVERTEXELEMENT* elements = NULL;
1815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1816 unsigned int size;
1817 DWORD hr;
1819 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1820 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1822 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1823 HeapFree(GetProcessHeap(), 0, elements);
1824 if (hr != S_OK) return hr;
1826 return WINED3D_OK;
1829 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1831 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1832 HRESULT hr = WINED3D_OK;
1833 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1834 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1836 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1838 if (vertex_declaration) {
1839 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1842 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1844 if (WINED3D_OK != hr) {
1845 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1846 IWineD3DVertexShader_Release(*ppVertexShader);
1847 return WINED3DERR_INVALIDCALL;
1849 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1851 return WINED3D_OK;
1854 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1856 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1857 HRESULT hr = WINED3D_OK;
1859 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1860 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1861 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1862 if (WINED3D_OK == hr) {
1863 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1864 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1865 } else {
1866 WARN("(%p) : Failed to create pixel shader\n", This);
1869 return hr;
1872 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1874 IWineD3DPaletteImpl *object;
1875 HRESULT hr;
1876 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1878 /* Create the new object */
1879 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1880 if(!object) {
1881 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1882 return E_OUTOFMEMORY;
1885 object->lpVtbl = &IWineD3DPalette_Vtbl;
1886 object->ref = 1;
1887 object->Flags = Flags;
1888 object->parent = Parent;
1889 object->wineD3DDevice = This;
1890 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1892 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1894 if(!object->hpal) {
1895 HeapFree( GetProcessHeap(), 0, object);
1896 return E_OUTOFMEMORY;
1899 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1900 if(FAILED(hr)) {
1901 IWineD3DPalette_Release((IWineD3DPalette *) object);
1902 return hr;
1905 *Palette = (IWineD3DPalette *) object;
1907 return WINED3D_OK;
1910 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1911 HBITMAP hbm;
1912 BITMAP bm;
1913 HRESULT hr;
1914 HDC dcb = NULL, dcs = NULL;
1915 WINEDDCOLORKEY colorkey;
1917 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1918 if(hbm)
1920 GetObjectA(hbm, sizeof(BITMAP), &bm);
1921 dcb = CreateCompatibleDC(NULL);
1922 if(!dcb) goto out;
1923 SelectObject(dcb, hbm);
1925 else
1927 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1928 * couldn't be loaded
1930 memset(&bm, 0, sizeof(bm));
1931 bm.bmWidth = 32;
1932 bm.bmHeight = 32;
1935 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1936 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1937 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1938 if(FAILED(hr)) {
1939 ERR("Wine logo requested, but failed to create surface\n");
1940 goto out;
1943 if(dcb) {
1944 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1945 if(FAILED(hr)) goto out;
1946 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1947 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1949 colorkey.dwColorSpaceLowValue = 0;
1950 colorkey.dwColorSpaceHighValue = 0;
1951 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1952 } else {
1953 /* Fill the surface with a white color to show that wined3d is there */
1954 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1957 out:
1958 if(dcb) {
1959 DeleteDC(dcb);
1961 if(hbm) {
1962 DeleteObject(hbm);
1964 return;
1967 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1968 unsigned int i;
1969 /* Under DirectX you can have texture stage operations even if no texture is
1970 bound, whereas opengl will only do texture operations when a valid texture is
1971 bound. We emulate this by creating dummy textures and binding them to each
1972 texture stage, but disable all stages by default. Hence if a stage is enabled
1973 then the default texture will kick in until replaced by a SetTexture call */
1974 ENTER_GL();
1976 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1977 /* The dummy texture does not have client storage backing */
1978 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1979 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1981 for (i = 0; i < GL_LIMITS(textures); i++) {
1982 GLubyte white = 255;
1984 /* Make appropriate texture active */
1985 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1986 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1987 checkGLcall("glActiveTextureARB");
1988 } else if (i > 0) {
1989 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1992 /* Generate an opengl texture name */
1993 glGenTextures(1, &This->dummyTextureName[i]);
1994 checkGLcall("glGenTextures");
1995 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1997 /* Generate a dummy 2d texture (not using 1d because they cause many
1998 * DRI drivers fall back to sw) */
1999 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2000 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2001 checkGLcall("glBindTexture");
2003 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2004 checkGLcall("glTexImage2D");
2006 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2007 /* Reenable because if supported it is enabled by default */
2008 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2009 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2012 LEAVE_GL();
2015 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2017 IWineD3DSwapChainImpl *swapchain = NULL;
2018 HRESULT hr;
2019 DWORD state;
2020 unsigned int i;
2022 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2023 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2024 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2026 /* TODO: Test if OpenGL is compiled in and loaded */
2028 TRACE("(%p) : Creating stateblock\n", This);
2029 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2030 hr = IWineD3DDevice_CreateStateBlock(iface,
2031 WINED3DSBT_INIT,
2032 (IWineD3DStateBlock **)&This->stateBlock,
2033 NULL);
2034 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2035 WARN("Failed to create stateblock\n");
2036 goto err_out;
2038 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2039 This->updateStateBlock = This->stateBlock;
2040 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2042 hr = allocate_shader_constants(This->updateStateBlock);
2043 if (WINED3D_OK != hr) {
2044 goto err_out;
2047 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2048 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2049 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2051 This->NumberOfPalettes = 1;
2052 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2053 if(!This->palettes || !This->render_targets || !This->fbo_color_attachments || !This->draw_buffers) {
2054 ERR("Out of memory!\n");
2055 goto err_out;
2057 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2058 if(!This->palettes[0]) {
2059 ERR("Out of memory!\n");
2060 goto err_out;
2062 for (i = 0; i < 256; ++i) {
2063 This->palettes[0][i].peRed = 0xFF;
2064 This->palettes[0][i].peGreen = 0xFF;
2065 This->palettes[0][i].peBlue = 0xFF;
2066 This->palettes[0][i].peFlags = 0xFF;
2068 This->currentPalette = 0;
2070 /* Initialize the texture unit mapping to a 1:1 mapping */
2071 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2072 if (state < GL_LIMITS(fragment_samplers)) {
2073 This->texUnitMap[state] = state;
2074 This->rev_tex_unit_map[state] = state;
2075 } else {
2076 This->texUnitMap[state] = -1;
2077 This->rev_tex_unit_map[state] = -1;
2081 /* Setup the implicit swapchain */
2082 TRACE("Creating implicit swapchain\n");
2083 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2084 if (FAILED(hr) || !swapchain) {
2085 WARN("Failed to create implicit swapchain\n");
2086 goto err_out;
2089 This->NumberOfSwapChains = 1;
2090 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2091 if(!This->swapchains) {
2092 ERR("Out of memory!\n");
2093 goto err_out;
2095 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2097 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2098 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2099 This->render_targets[0] = swapchain->backBuffer[0];
2100 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2102 else {
2103 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2104 This->render_targets[0] = swapchain->frontBuffer;
2105 This->lastActiveRenderTarget = swapchain->frontBuffer;
2107 IWineD3DSurface_AddRef(This->render_targets[0]);
2108 This->activeContext = swapchain->context[0];
2109 This->lastThread = GetCurrentThreadId();
2111 /* Depth Stencil support */
2112 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2113 if (NULL != This->stencilBufferTarget) {
2114 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2117 hr = This->shader_backend->shader_alloc_private(iface);
2118 if(FAILED(hr)) {
2119 TRACE("Shader private data couldn't be allocated\n");
2120 goto err_out;
2123 /* Set up some starting GL setup */
2124 ENTER_GL();
2126 /* Setup all the devices defaults */
2127 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2128 create_dummy_textures(This);
2129 #if 0
2130 IWineD3DImpl_CheckGraphicsMemory();
2131 #endif
2133 { /* Set a default viewport */
2134 WINED3DVIEWPORT vp;
2135 vp.X = 0;
2136 vp.Y = 0;
2137 vp.Width = pPresentationParameters->BackBufferWidth;
2138 vp.Height = pPresentationParameters->BackBufferHeight;
2139 vp.MinZ = 0.0f;
2140 vp.MaxZ = 1.0f;
2141 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2144 /* Initialize the current view state */
2145 This->view_ident = 1;
2146 This->contexts[0]->last_was_rhw = 0;
2147 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2148 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2150 switch(wined3d_settings.offscreen_rendering_mode) {
2151 case ORM_FBO:
2152 case ORM_PBUFFER:
2153 This->offscreenBuffer = GL_BACK;
2154 break;
2156 case ORM_BACKBUFFER:
2158 if(GL_LIMITS(aux_buffers) > 0) {
2159 TRACE("Using auxilliary buffer for offscreen rendering\n");
2160 This->offscreenBuffer = GL_AUX0;
2161 } else {
2162 TRACE("Using back buffer for offscreen rendering\n");
2163 This->offscreenBuffer = GL_BACK;
2168 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2169 LEAVE_GL();
2171 /* Clear the screen */
2172 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2173 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2174 0x00, 1.0, 0);
2176 This->d3d_initialized = TRUE;
2178 if(wined3d_settings.logo) {
2179 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2181 This->highest_dirty_ps_const = 0;
2182 This->highest_dirty_vs_const = 0;
2183 return WINED3D_OK;
2185 err_out:
2186 This->shader_backend->shader_free_private(iface);
2187 HeapFree(GetProcessHeap(), 0, This->render_targets);
2188 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2189 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2190 HeapFree(GetProcessHeap(), 0, This->swapchains);
2191 This->NumberOfSwapChains = 0;
2192 if(This->palettes) {
2193 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2194 HeapFree(GetProcessHeap(), 0, This->palettes);
2196 This->NumberOfPalettes = 0;
2197 if(swapchain) {
2198 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2200 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2201 if(This->stateBlock) {
2202 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2203 This->stateBlock = NULL;
2205 return hr;
2208 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2210 int sampler;
2211 UINT i;
2212 TRACE("(%p)\n", This);
2214 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2216 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2217 * it was created. Thus make sure a context is active for the glDelete* calls
2219 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2221 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2223 TRACE("Deleting high order patches\n");
2224 for(i = 0; i < PATCHMAP_SIZE; i++) {
2225 struct list *e1, *e2;
2226 struct WineD3DRectPatch *patch;
2227 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2228 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2229 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2233 /* Delete the palette conversion shader if it is around */
2234 if(This->paletteConversionShader) {
2235 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2236 This->paletteConversionShader = 0;
2239 /* Delete the pbuffer context if there is any */
2240 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2242 /* Delete the mouse cursor texture */
2243 if(This->cursorTexture) {
2244 ENTER_GL();
2245 glDeleteTextures(1, &This->cursorTexture);
2246 LEAVE_GL();
2247 This->cursorTexture = 0;
2250 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2251 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2253 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2254 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2257 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2258 * private data, it might contain opengl pointers
2260 This->shader_backend->shader_destroy_depth_blt(iface);
2261 This->shader_backend->shader_free_private(iface);
2263 /* Release the update stateblock */
2264 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2265 if(This->updateStateBlock != This->stateBlock)
2266 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2268 This->updateStateBlock = NULL;
2270 { /* because were not doing proper internal refcounts releasing the primary state block
2271 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2272 to set this->stateBlock = NULL; first */
2273 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2274 This->stateBlock = NULL;
2276 /* Release the stateblock */
2277 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2278 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2282 /* Release the buffers (with sanity checks)*/
2283 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2284 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2285 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2286 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2288 This->stencilBufferTarget = NULL;
2290 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2291 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2292 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2294 TRACE("Setting rendertarget to NULL\n");
2295 This->render_targets[0] = NULL;
2297 if (This->auto_depth_stencil_buffer) {
2298 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2299 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2301 This->auto_depth_stencil_buffer = NULL;
2304 for(i=0; i < This->NumberOfSwapChains; i++) {
2305 TRACE("Releasing the implicit swapchain %d\n", i);
2306 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2307 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2311 HeapFree(GetProcessHeap(), 0, This->swapchains);
2312 This->swapchains = NULL;
2313 This->NumberOfSwapChains = 0;
2315 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2316 HeapFree(GetProcessHeap(), 0, This->palettes);
2317 This->palettes = NULL;
2318 This->NumberOfPalettes = 0;
2320 HeapFree(GetProcessHeap(), 0, This->render_targets);
2321 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2322 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2323 This->render_targets = NULL;
2324 This->fbo_color_attachments = NULL;
2325 This->draw_buffers = NULL;
2327 This->d3d_initialized = FALSE;
2328 return WINED3D_OK;
2331 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2333 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2335 /* Setup the window for fullscreen mode */
2336 if(fullscreen && !This->ddraw_fullscreen) {
2337 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2338 } else if(!fullscreen && This->ddraw_fullscreen) {
2339 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2342 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2343 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2344 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2345 * separately.
2347 This->ddraw_fullscreen = fullscreen;
2350 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2351 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2352 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2354 * There is no way to deactivate thread safety once it is enabled.
2356 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2359 /*For now just store the flag(needed in case of ddraw) */
2360 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2362 return;
2365 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2366 DEVMODEW devmode;
2367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2368 LONG ret;
2369 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2370 RECT clip_rc;
2372 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2374 /* Resize the screen even without a window:
2375 * The app could have unset it with SetCooperativeLevel, but not called
2376 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2377 * but we don't have any hwnd
2380 memset(&devmode, 0, sizeof(devmode));
2381 devmode.dmSize = sizeof(devmode);
2382 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2383 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2384 devmode.dmPelsWidth = pMode->Width;
2385 devmode.dmPelsHeight = pMode->Height;
2387 devmode.dmDisplayFrequency = pMode->RefreshRate;
2388 if (pMode->RefreshRate != 0) {
2389 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2392 /* Only change the mode if necessary */
2393 if( (This->ddraw_width == pMode->Width) &&
2394 (This->ddraw_height == pMode->Height) &&
2395 (This->ddraw_format == pMode->Format) &&
2396 (pMode->RefreshRate == 0) ) {
2397 return WINED3D_OK;
2400 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2401 if (ret != DISP_CHANGE_SUCCESSFUL) {
2402 if(devmode.dmDisplayFrequency != 0) {
2403 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2404 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2405 devmode.dmDisplayFrequency = 0;
2406 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2408 if(ret != DISP_CHANGE_SUCCESSFUL) {
2409 return WINED3DERR_NOTAVAILABLE;
2413 /* Store the new values */
2414 This->ddraw_width = pMode->Width;
2415 This->ddraw_height = pMode->Height;
2416 This->ddraw_format = pMode->Format;
2418 /* Only do this with a window of course, and only if we're fullscreened */
2419 if(This->ddraw_window && This->ddraw_fullscreen)
2420 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2422 /* And finally clip mouse to our screen */
2423 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2424 ClipCursor(&clip_rc);
2426 return WINED3D_OK;
2429 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2431 *ppD3D= This->wineD3D;
2432 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2433 IWineD3D_AddRef(*ppD3D);
2434 return WINED3D_OK;
2437 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2440 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2441 (This->adapter->TextureRam/(1024*1024)),
2442 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2443 /* return simulated texture memory left */
2444 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2449 /*****
2450 * Get / Set FVF
2451 *****/
2452 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2455 /* Update the current state block */
2456 This->updateStateBlock->changed.fvf = TRUE;
2458 if(This->updateStateBlock->fvf == fvf) {
2459 TRACE("Application is setting the old fvf over, nothing to do\n");
2460 return WINED3D_OK;
2463 This->updateStateBlock->fvf = fvf;
2464 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2465 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2466 return WINED3D_OK;
2470 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2472 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2473 *pfvf = This->stateBlock->fvf;
2474 return WINED3D_OK;
2477 /*****
2478 * Get / Set Stream Source
2479 *****/
2480 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2482 IWineD3DVertexBuffer *oldSrc;
2484 if (StreamNumber >= MAX_STREAMS) {
2485 WARN("Stream out of range %d\n", StreamNumber);
2486 return WINED3DERR_INVALIDCALL;
2487 } else if(OffsetInBytes & 0x3) {
2488 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2489 return WINED3DERR_INVALIDCALL;
2492 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2493 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2495 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2497 if(oldSrc == pStreamData &&
2498 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2499 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2500 TRACE("Application is setting the old values over, nothing to do\n");
2501 return WINED3D_OK;
2504 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2505 if (pStreamData) {
2506 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2507 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2510 /* Handle recording of state blocks */
2511 if (This->isRecordingState) {
2512 TRACE("Recording... not performing anything\n");
2513 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2514 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2515 return WINED3D_OK;
2518 /* Need to do a getParent and pass the references up */
2519 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2520 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2521 so for now, just count internally */
2522 if (pStreamData != NULL) {
2523 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2524 InterlockedIncrement(&vbImpl->bindCount);
2525 IWineD3DVertexBuffer_AddRef(pStreamData);
2527 if (oldSrc != NULL) {
2528 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2529 IWineD3DVertexBuffer_Release(oldSrc);
2532 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2534 return WINED3D_OK;
2537 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2540 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2541 This->stateBlock->streamSource[StreamNumber],
2542 This->stateBlock->streamOffset[StreamNumber],
2543 This->stateBlock->streamStride[StreamNumber]);
2545 if (StreamNumber >= MAX_STREAMS) {
2546 WARN("Stream out of range %d\n", StreamNumber);
2547 return WINED3DERR_INVALIDCALL;
2549 *pStream = This->stateBlock->streamSource[StreamNumber];
2550 *pStride = This->stateBlock->streamStride[StreamNumber];
2551 if (pOffset) {
2552 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2555 if (*pStream != NULL) {
2556 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2558 return WINED3D_OK;
2561 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2563 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2564 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2566 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2567 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2569 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2570 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2572 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2573 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2574 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2577 return WINED3D_OK;
2580 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2583 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2584 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2586 TRACE("(%p) : returning %d\n", This, *Divider);
2588 return WINED3D_OK;
2591 /*****
2592 * Get / Set & Multiply Transform
2593 *****/
2594 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2597 /* Most of this routine, comments included copied from ddraw tree initially: */
2598 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2600 /* Handle recording of state blocks */
2601 if (This->isRecordingState) {
2602 TRACE("Recording... not performing anything\n");
2603 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2604 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2605 return WINED3D_OK;
2609 * If the new matrix is the same as the current one,
2610 * we cut off any further processing. this seems to be a reasonable
2611 * optimization because as was noticed, some apps (warcraft3 for example)
2612 * tend towards setting the same matrix repeatedly for some reason.
2614 * From here on we assume that the new matrix is different, wherever it matters.
2616 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2617 TRACE("The app is setting the same matrix over again\n");
2618 return WINED3D_OK;
2619 } else {
2620 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2624 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2625 where ViewMat = Camera space, WorldMat = world space.
2627 In OpenGL, camera and world space is combined into GL_MODELVIEW
2628 matrix. The Projection matrix stay projection matrix.
2631 /* Capture the times we can just ignore the change for now */
2632 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2633 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2634 /* Handled by the state manager */
2637 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2638 return WINED3D_OK;
2641 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2643 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2644 *pMatrix = This->stateBlock->transforms[State];
2645 return WINED3D_OK;
2648 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2649 WINED3DMATRIX *mat = NULL;
2650 WINED3DMATRIX temp;
2652 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2653 * below means it will be recorded in a state block change, but it
2654 * works regardless where it is recorded.
2655 * If this is found to be wrong, change to StateBlock.
2657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2658 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2660 if (State < HIGHEST_TRANSFORMSTATE)
2662 mat = &This->updateStateBlock->transforms[State];
2663 } else {
2664 FIXME("Unhandled transform state!!\n");
2667 multiply_matrix(&temp, mat, pMatrix);
2669 /* Apply change via set transform - will reapply to eg. lights this way */
2670 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2673 /*****
2674 * Get / Set Light
2675 *****/
2676 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2677 you can reference any indexes you want as long as that number max are enabled at any
2678 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2679 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2680 but when recording, just build a chain pretty much of commands to be replayed. */
2682 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2683 float rho;
2684 PLIGHTINFOEL *object = NULL;
2685 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2686 struct list *e;
2688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2689 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2691 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2692 * the gl driver.
2694 if(!pLight) {
2695 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2696 return WINED3DERR_INVALIDCALL;
2699 switch(pLight->Type) {
2700 case WINED3DLIGHT_POINT:
2701 case WINED3DLIGHT_SPOT:
2702 case WINED3DLIGHT_PARALLELPOINT:
2703 case WINED3DLIGHT_GLSPOT:
2704 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2705 * most wanted
2707 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2708 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2709 return WINED3DERR_INVALIDCALL;
2711 break;
2713 case WINED3DLIGHT_DIRECTIONAL:
2714 /* Ignores attenuation */
2715 break;
2717 default:
2718 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2719 return WINED3DERR_INVALIDCALL;
2722 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2723 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2724 if(object->OriginalIndex == Index) break;
2725 object = NULL;
2728 if(!object) {
2729 TRACE("Adding new light\n");
2730 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2731 if(!object) {
2732 ERR("Out of memory error when allocating a light\n");
2733 return E_OUTOFMEMORY;
2735 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2736 object->glIndex = -1;
2737 object->OriginalIndex = Index;
2738 object->changed = TRUE;
2741 /* Initialize the object */
2742 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,
2743 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2744 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2745 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2746 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2747 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2748 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2750 /* Save away the information */
2751 object->OriginalParms = *pLight;
2753 switch (pLight->Type) {
2754 case WINED3DLIGHT_POINT:
2755 /* Position */
2756 object->lightPosn[0] = pLight->Position.x;
2757 object->lightPosn[1] = pLight->Position.y;
2758 object->lightPosn[2] = pLight->Position.z;
2759 object->lightPosn[3] = 1.0f;
2760 object->cutoff = 180.0f;
2761 /* FIXME: Range */
2762 break;
2764 case WINED3DLIGHT_DIRECTIONAL:
2765 /* Direction */
2766 object->lightPosn[0] = -pLight->Direction.x;
2767 object->lightPosn[1] = -pLight->Direction.y;
2768 object->lightPosn[2] = -pLight->Direction.z;
2769 object->lightPosn[3] = 0.0;
2770 object->exponent = 0.0f;
2771 object->cutoff = 180.0f;
2772 break;
2774 case WINED3DLIGHT_SPOT:
2775 /* Position */
2776 object->lightPosn[0] = pLight->Position.x;
2777 object->lightPosn[1] = pLight->Position.y;
2778 object->lightPosn[2] = pLight->Position.z;
2779 object->lightPosn[3] = 1.0;
2781 /* Direction */
2782 object->lightDirn[0] = pLight->Direction.x;
2783 object->lightDirn[1] = pLight->Direction.y;
2784 object->lightDirn[2] = pLight->Direction.z;
2785 object->lightDirn[3] = 1.0;
2788 * opengl-ish and d3d-ish spot lights use too different models for the
2789 * light "intensity" as a function of the angle towards the main light direction,
2790 * so we only can approximate very roughly.
2791 * however spot lights are rather rarely used in games (if ever used at all).
2792 * furthermore if still used, probably nobody pays attention to such details.
2794 if (pLight->Falloff == 0) {
2795 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2796 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2797 * will always be 1.0 for both of them, and we don't have to care for the
2798 * rest of the rather complex calculation
2800 object->exponent = 0;
2801 } else {
2802 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2803 if (rho < 0.0001) rho = 0.0001f;
2804 object->exponent = -0.3/log(cos(rho/2));
2806 if (object->exponent > 128.0) {
2807 object->exponent = 128.0;
2809 object->cutoff = pLight->Phi*90/M_PI;
2811 /* FIXME: Range */
2812 break;
2814 default:
2815 FIXME("Unrecognized light type %d\n", pLight->Type);
2818 /* Update the live definitions if the light is currently assigned a glIndex */
2819 if (object->glIndex != -1 && !This->isRecordingState) {
2820 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2822 return WINED3D_OK;
2825 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2826 PLIGHTINFOEL *lightInfo = NULL;
2827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2828 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2829 struct list *e;
2830 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2832 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2833 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2834 if(lightInfo->OriginalIndex == Index) break;
2835 lightInfo = NULL;
2838 if (lightInfo == NULL) {
2839 TRACE("Light information requested but light not defined\n");
2840 return WINED3DERR_INVALIDCALL;
2843 *pLight = lightInfo->OriginalParms;
2844 return WINED3D_OK;
2847 /*****
2848 * Get / Set Light Enable
2849 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2850 *****/
2851 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2852 PLIGHTINFOEL *lightInfo = NULL;
2853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2854 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2855 struct list *e;
2856 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2858 /* Tests show true = 128...not clear why */
2859 Enable = Enable? 128: 0;
2861 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2862 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2863 if(lightInfo->OriginalIndex == Index) break;
2864 lightInfo = NULL;
2866 TRACE("Found light: %p\n", lightInfo);
2868 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2869 if (lightInfo == NULL) {
2871 TRACE("Light enabled requested but light not defined, so defining one!\n");
2872 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2874 /* Search for it again! Should be fairly quick as near head of list */
2875 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2876 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2877 if(lightInfo->OriginalIndex == Index) break;
2878 lightInfo = NULL;
2880 if (lightInfo == NULL) {
2881 FIXME("Adding default lights has failed dismally\n");
2882 return WINED3DERR_INVALIDCALL;
2886 lightInfo->enabledChanged = TRUE;
2887 if(!Enable) {
2888 if(lightInfo->glIndex != -1) {
2889 if(!This->isRecordingState) {
2890 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2893 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2894 lightInfo->glIndex = -1;
2895 } else {
2896 TRACE("Light already disabled, nothing to do\n");
2898 lightInfo->enabled = FALSE;
2899 } else {
2900 lightInfo->enabled = TRUE;
2901 if (lightInfo->glIndex != -1) {
2902 /* nop */
2903 TRACE("Nothing to do as light was enabled\n");
2904 } else {
2905 int i;
2906 /* Find a free gl light */
2907 for(i = 0; i < This->maxConcurrentLights; i++) {
2908 if(This->stateBlock->activeLights[i] == NULL) {
2909 This->stateBlock->activeLights[i] = lightInfo;
2910 lightInfo->glIndex = i;
2911 break;
2914 if(lightInfo->glIndex == -1) {
2915 /* Our tests show that Windows returns D3D_OK in this situation, even with
2916 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2917 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2918 * as well for those lights.
2920 * TODO: Test how this affects rendering
2922 FIXME("Too many concurrently active lights\n");
2923 return WINED3D_OK;
2926 /* i == lightInfo->glIndex */
2927 if(!This->isRecordingState) {
2928 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2933 return WINED3D_OK;
2936 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2938 PLIGHTINFOEL *lightInfo = NULL;
2939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2940 struct list *e;
2941 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2942 TRACE("(%p) : for idx(%d)\n", This, Index);
2944 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2945 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2946 if(lightInfo->OriginalIndex == Index) break;
2947 lightInfo = NULL;
2950 if (lightInfo == NULL) {
2951 TRACE("Light enabled state requested but light not defined\n");
2952 return WINED3DERR_INVALIDCALL;
2954 /* true is 128 according to SetLightEnable */
2955 *pEnable = lightInfo->enabled ? 128 : 0;
2956 return WINED3D_OK;
2959 /*****
2960 * Get / Set Clip Planes
2961 *****/
2962 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2964 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2966 /* Validate Index */
2967 if (Index >= GL_LIMITS(clipplanes)) {
2968 TRACE("Application has requested clipplane this device doesn't support\n");
2969 return WINED3DERR_INVALIDCALL;
2972 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2974 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2975 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2976 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2977 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2978 TRACE("Application is setting old values over, nothing to do\n");
2979 return WINED3D_OK;
2982 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2983 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2984 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2985 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2987 /* Handle recording of state blocks */
2988 if (This->isRecordingState) {
2989 TRACE("Recording... not performing anything\n");
2990 return WINED3D_OK;
2993 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2995 return WINED3D_OK;
2998 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3000 TRACE("(%p) : for idx %d\n", This, Index);
3002 /* Validate Index */
3003 if (Index >= GL_LIMITS(clipplanes)) {
3004 TRACE("Application has requested clipplane this device doesn't support\n");
3005 return WINED3DERR_INVALIDCALL;
3008 pPlane[0] = This->stateBlock->clipplane[Index][0];
3009 pPlane[1] = This->stateBlock->clipplane[Index][1];
3010 pPlane[2] = This->stateBlock->clipplane[Index][2];
3011 pPlane[3] = This->stateBlock->clipplane[Index][3];
3012 return WINED3D_OK;
3015 /*****
3016 * Get / Set Clip Plane Status
3017 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3018 *****/
3019 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3021 FIXME("(%p) : stub\n", This);
3022 if (NULL == pClipStatus) {
3023 return WINED3DERR_INVALIDCALL;
3025 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3026 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3027 return WINED3D_OK;
3030 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3032 FIXME("(%p) : stub\n", This);
3033 if (NULL == pClipStatus) {
3034 return WINED3DERR_INVALIDCALL;
3036 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3037 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3038 return WINED3D_OK;
3041 /*****
3042 * Get / Set Material
3043 *****/
3044 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3047 This->updateStateBlock->changed.material = TRUE;
3048 This->updateStateBlock->material = *pMaterial;
3050 /* Handle recording of state blocks */
3051 if (This->isRecordingState) {
3052 TRACE("Recording... not performing anything\n");
3053 return WINED3D_OK;
3056 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3057 return WINED3D_OK;
3060 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3062 *pMaterial = This->updateStateBlock->material;
3063 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3064 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3065 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3066 pMaterial->Ambient.b, pMaterial->Ambient.a);
3067 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3068 pMaterial->Specular.b, pMaterial->Specular.a);
3069 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3070 pMaterial->Emissive.b, pMaterial->Emissive.a);
3071 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3073 return WINED3D_OK;
3076 /*****
3077 * Get / Set Indices
3078 *****/
3079 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3080 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3081 IWineD3DIndexBuffer *oldIdxs;
3083 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3084 oldIdxs = This->updateStateBlock->pIndexData;
3086 This->updateStateBlock->changed.indices = TRUE;
3087 This->updateStateBlock->pIndexData = pIndexData;
3089 /* Handle recording of state blocks */
3090 if (This->isRecordingState) {
3091 TRACE("Recording... not performing anything\n");
3092 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3093 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3094 return WINED3D_OK;
3097 if(oldIdxs != pIndexData) {
3098 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3099 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3100 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3102 return WINED3D_OK;
3105 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3108 *ppIndexData = This->stateBlock->pIndexData;
3110 /* up ref count on ppindexdata */
3111 if (*ppIndexData) {
3112 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3113 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3114 }else{
3115 TRACE("(%p) No index data set\n", This);
3117 TRACE("Returning %p\n", *ppIndexData);
3119 return WINED3D_OK;
3122 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3123 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3125 TRACE("(%p)->(%d)\n", This, BaseIndex);
3127 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3128 TRACE("Application is setting the old value over, nothing to do\n");
3129 return WINED3D_OK;
3132 This->updateStateBlock->baseVertexIndex = BaseIndex;
3134 if (This->isRecordingState) {
3135 TRACE("Recording... not performing anything\n");
3136 return WINED3D_OK;
3138 /* The base vertex index affects the stream sources */
3139 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3140 return WINED3D_OK;
3143 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3145 TRACE("(%p) : base_index %p\n", This, base_index);
3147 *base_index = This->stateBlock->baseVertexIndex;
3149 TRACE("Returning %u\n", *base_index);
3151 return WINED3D_OK;
3154 /*****
3155 * Get / Set Viewports
3156 *****/
3157 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3160 TRACE("(%p)\n", This);
3161 This->updateStateBlock->changed.viewport = TRUE;
3162 This->updateStateBlock->viewport = *pViewport;
3164 /* Handle recording of state blocks */
3165 if (This->isRecordingState) {
3166 TRACE("Recording... not performing anything\n");
3167 return WINED3D_OK;
3170 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3171 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3173 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3174 return WINED3D_OK;
3178 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3180 TRACE("(%p)\n", This);
3181 *pViewport = This->stateBlock->viewport;
3182 return WINED3D_OK;
3185 /*****
3186 * Get / Set Render States
3187 * TODO: Verify against dx9 definitions
3188 *****/
3189 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3192 DWORD oldValue = This->stateBlock->renderState[State];
3194 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3196 This->updateStateBlock->changed.renderState[State] = TRUE;
3197 This->updateStateBlock->renderState[State] = Value;
3199 /* Handle recording of state blocks */
3200 if (This->isRecordingState) {
3201 TRACE("Recording... not performing anything\n");
3202 return WINED3D_OK;
3205 /* Compared here and not before the assignment to allow proper stateblock recording */
3206 if(Value == oldValue) {
3207 TRACE("Application is setting the old value over, nothing to do\n");
3208 } else {
3209 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3212 return WINED3D_OK;
3215 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3217 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3218 *pValue = This->stateBlock->renderState[State];
3219 return WINED3D_OK;
3222 /*****
3223 * Get / Set Sampler States
3224 * TODO: Verify against dx9 definitions
3225 *****/
3227 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3229 DWORD oldValue;
3231 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3232 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3234 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3235 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3238 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3239 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3240 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3243 * SetSampler is designed to allow for more than the standard up to 8 textures
3244 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3245 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3247 * http://developer.nvidia.com/object/General_FAQ.html#t6
3249 * There are two new settings for GForce
3250 * the sampler one:
3251 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3252 * and the texture one:
3253 * GL_MAX_TEXTURE_COORDS_ARB.
3254 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3255 ******************/
3257 oldValue = This->stateBlock->samplerState[Sampler][Type];
3258 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3259 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3261 /* Handle recording of state blocks */
3262 if (This->isRecordingState) {
3263 TRACE("Recording... not performing anything\n");
3264 return WINED3D_OK;
3267 if(oldValue == Value) {
3268 TRACE("Application is setting the old value over, nothing to do\n");
3269 return WINED3D_OK;
3272 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3274 return WINED3D_OK;
3277 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3280 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3281 This, Sampler, debug_d3dsamplerstate(Type), Type);
3283 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3284 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3287 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3288 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3289 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3291 *Value = This->stateBlock->samplerState[Sampler][Type];
3292 TRACE("(%p) : Returning %#x\n", This, *Value);
3294 return WINED3D_OK;
3297 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3300 This->updateStateBlock->changed.scissorRect = TRUE;
3301 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3302 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3303 return WINED3D_OK;
3305 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3307 if(This->isRecordingState) {
3308 TRACE("Recording... not performing anything\n");
3309 return WINED3D_OK;
3312 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3314 return WINED3D_OK;
3317 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3320 *pRect = This->updateStateBlock->scissorRect;
3321 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3322 return WINED3D_OK;
3325 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3327 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3329 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3331 This->updateStateBlock->vertexDecl = pDecl;
3332 This->updateStateBlock->changed.vertexDecl = TRUE;
3334 if (This->isRecordingState) {
3335 TRACE("Recording... not performing anything\n");
3336 return WINED3D_OK;
3337 } else if(pDecl == oldDecl) {
3338 /* Checked after the assignment to allow proper stateblock recording */
3339 TRACE("Application is setting the old declaration over, nothing to do\n");
3340 return WINED3D_OK;
3343 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3344 return WINED3D_OK;
3347 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3350 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3352 *ppDecl = This->stateBlock->vertexDecl;
3353 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3354 return WINED3D_OK;
3357 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3359 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3361 This->updateStateBlock->vertexShader = pShader;
3362 This->updateStateBlock->changed.vertexShader = TRUE;
3364 if (This->isRecordingState) {
3365 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3366 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3367 TRACE("Recording... not performing anything\n");
3368 return WINED3D_OK;
3369 } else if(oldShader == pShader) {
3370 /* Checked here to allow proper stateblock recording */
3371 TRACE("App is setting the old shader over, nothing to do\n");
3372 return WINED3D_OK;
3375 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3376 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3377 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3379 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3381 return WINED3D_OK;
3384 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3387 if (NULL == ppShader) {
3388 return WINED3DERR_INVALIDCALL;
3390 *ppShader = This->stateBlock->vertexShader;
3391 if( NULL != *ppShader)
3392 IWineD3DVertexShader_AddRef(*ppShader);
3394 TRACE("(%p) : returning %p\n", This, *ppShader);
3395 return WINED3D_OK;
3398 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3399 IWineD3DDevice *iface,
3400 UINT start,
3401 CONST BOOL *srcData,
3402 UINT count) {
3404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3405 int i, cnt = min(count, MAX_CONST_B - start);
3407 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3408 iface, srcData, start, count);
3410 if (srcData == NULL || cnt < 0)
3411 return WINED3DERR_INVALIDCALL;
3413 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3414 for (i = 0; i < cnt; i++)
3415 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3417 for (i = start; i < cnt + start; ++i) {
3418 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3421 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3423 return WINED3D_OK;
3426 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3427 IWineD3DDevice *iface,
3428 UINT start,
3429 BOOL *dstData,
3430 UINT count) {
3432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3433 int cnt = min(count, MAX_CONST_B - start);
3435 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3436 iface, dstData, start, count);
3438 if (dstData == NULL || cnt < 0)
3439 return WINED3DERR_INVALIDCALL;
3441 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3442 return WINED3D_OK;
3445 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3446 IWineD3DDevice *iface,
3447 UINT start,
3448 CONST int *srcData,
3449 UINT count) {
3451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3452 int i, cnt = min(count, MAX_CONST_I - start);
3454 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3455 iface, srcData, start, count);
3457 if (srcData == NULL || cnt < 0)
3458 return WINED3DERR_INVALIDCALL;
3460 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3461 for (i = 0; i < cnt; i++)
3462 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3463 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3465 for (i = start; i < cnt + start; ++i) {
3466 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3469 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3471 return WINED3D_OK;
3474 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3475 IWineD3DDevice *iface,
3476 UINT start,
3477 int *dstData,
3478 UINT count) {
3480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3481 int cnt = min(count, MAX_CONST_I - start);
3483 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3484 iface, dstData, start, count);
3486 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3487 return WINED3DERR_INVALIDCALL;
3489 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3490 return WINED3D_OK;
3493 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3494 IWineD3DDevice *iface,
3495 UINT start,
3496 CONST float *srcData,
3497 UINT count) {
3499 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3500 int i;
3502 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3503 iface, srcData, start, count);
3505 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3506 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3507 return WINED3DERR_INVALIDCALL;
3509 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3510 if(TRACE_ON(d3d)) {
3511 for (i = 0; i < count; i++)
3512 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3513 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3516 for (i = start; i < count + start; ++i) {
3517 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3518 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3519 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3520 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3521 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3523 ptr->idx[ptr->count++] = i;
3524 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3528 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3530 return WINED3D_OK;
3533 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3534 IWineD3DDevice *iface,
3535 UINT start,
3536 CONST float *srcData,
3537 UINT count) {
3539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3540 int i;
3542 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3543 iface, srcData, start, count);
3545 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3546 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3547 return WINED3DERR_INVALIDCALL;
3549 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3550 if(TRACE_ON(d3d)) {
3551 for (i = 0; i < count; i++)
3552 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3553 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3556 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3557 * context. On a context switch the old context will be fully dirtified
3559 memset(This->activeContext->vshader_const_dirty + start, 1,
3560 sizeof(*This->activeContext->vshader_const_dirty) * count);
3561 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count);
3563 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3565 return WINED3D_OK;
3568 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3569 IWineD3DDevice *iface,
3570 UINT start,
3571 float *dstData,
3572 UINT count) {
3574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3575 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3577 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3578 iface, dstData, start, count);
3580 if (dstData == NULL || cnt < 0)
3581 return WINED3DERR_INVALIDCALL;
3583 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3584 return WINED3D_OK;
3587 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3588 DWORD i;
3589 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3590 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3594 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3595 int i = This->rev_tex_unit_map[unit];
3596 int j = This->texUnitMap[stage];
3598 This->texUnitMap[stage] = unit;
3599 if (i != -1 && i != stage) {
3600 This->texUnitMap[i] = -1;
3603 This->rev_tex_unit_map[unit] = stage;
3604 if (j != -1 && j != unit) {
3605 This->rev_tex_unit_map[j] = -1;
3609 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3610 int i;
3612 for (i = 0; i < MAX_TEXTURES; ++i) {
3613 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3614 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3615 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3616 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3617 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3618 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3619 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3620 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3622 if (color_op == WINED3DTOP_DISABLE) {
3623 /* Not used, and disable higher stages */
3624 while (i < MAX_TEXTURES) {
3625 This->fixed_function_usage_map[i] = FALSE;
3626 ++i;
3628 break;
3631 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3632 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3633 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3634 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3635 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3636 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3637 This->fixed_function_usage_map[i] = TRUE;
3638 } else {
3639 This->fixed_function_usage_map[i] = FALSE;
3642 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3643 This->fixed_function_usage_map[i+1] = TRUE;
3648 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3649 int i, tex;
3651 device_update_fixed_function_usage_map(This);
3653 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3654 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3655 if (!This->fixed_function_usage_map[i]) continue;
3657 if (This->texUnitMap[i] != i) {
3658 device_map_stage(This, i, i);
3659 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3660 markTextureStagesDirty(This, i);
3663 return;
3666 /* Now work out the mapping */
3667 tex = 0;
3668 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3669 if (!This->fixed_function_usage_map[i]) continue;
3671 if (This->texUnitMap[i] != tex) {
3672 device_map_stage(This, i, tex);
3673 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3674 markTextureStagesDirty(This, i);
3677 ++tex;
3681 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3682 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3683 int i;
3685 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3686 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3687 device_map_stage(This, i, i);
3688 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3689 if (i < MAX_TEXTURES) {
3690 markTextureStagesDirty(This, i);
3696 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3697 int current_mapping = This->rev_tex_unit_map[unit];
3699 if (current_mapping == -1) {
3700 /* Not currently used */
3701 return TRUE;
3704 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3705 /* Used by a fragment sampler */
3707 if (!pshader_sampler_tokens) {
3708 /* No pixel shader, check fixed function */
3709 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3712 /* Pixel shader, check the shader's sampler map */
3713 return !pshader_sampler_tokens[current_mapping];
3716 /* Used by a vertex sampler */
3717 return !vshader_sampler_tokens[current_mapping];
3720 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3721 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3722 DWORD *pshader_sampler_tokens = NULL;
3723 int start = GL_LIMITS(combined_samplers) - 1;
3724 int i;
3726 if (ps) {
3727 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3729 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3730 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3731 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3734 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3735 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3736 if (vshader_sampler_tokens[i]) {
3737 if (This->texUnitMap[vsampler_idx] != -1) {
3738 /* Already mapped somewhere */
3739 continue;
3742 while (start >= 0) {
3743 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3744 device_map_stage(This, vsampler_idx, start);
3745 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3747 --start;
3748 break;
3751 --start;
3757 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3758 BOOL vs = use_vs(This);
3759 BOOL ps = use_ps(This);
3761 * Rules are:
3762 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3763 * that would be really messy and require shader recompilation
3764 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3765 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3767 if (ps) {
3768 device_map_psamplers(This);
3769 } else {
3770 device_map_fixed_function_samplers(This);
3773 if (vs) {
3774 device_map_vsamplers(This, ps);
3778 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3780 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3781 This->updateStateBlock->pixelShader = pShader;
3782 This->updateStateBlock->changed.pixelShader = TRUE;
3784 /* Handle recording of state blocks */
3785 if (This->isRecordingState) {
3786 TRACE("Recording... not performing anything\n");
3789 if (This->isRecordingState) {
3790 TRACE("Recording... not performing anything\n");
3791 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3792 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3793 return WINED3D_OK;
3796 if(pShader == oldShader) {
3797 TRACE("App is setting the old pixel shader over, nothing to do\n");
3798 return WINED3D_OK;
3801 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3802 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3804 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3805 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3807 return WINED3D_OK;
3810 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3813 if (NULL == ppShader) {
3814 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3815 return WINED3DERR_INVALIDCALL;
3818 *ppShader = This->stateBlock->pixelShader;
3819 if (NULL != *ppShader) {
3820 IWineD3DPixelShader_AddRef(*ppShader);
3822 TRACE("(%p) : returning %p\n", This, *ppShader);
3823 return WINED3D_OK;
3826 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3827 IWineD3DDevice *iface,
3828 UINT start,
3829 CONST BOOL *srcData,
3830 UINT count) {
3832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3833 int i, cnt = min(count, MAX_CONST_B - start);
3835 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3836 iface, srcData, start, count);
3838 if (srcData == NULL || cnt < 0)
3839 return WINED3DERR_INVALIDCALL;
3841 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3842 for (i = 0; i < cnt; i++)
3843 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3845 for (i = start; i < cnt + start; ++i) {
3846 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3849 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3851 return WINED3D_OK;
3854 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3855 IWineD3DDevice *iface,
3856 UINT start,
3857 BOOL *dstData,
3858 UINT count) {
3860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3861 int cnt = min(count, MAX_CONST_B - start);
3863 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3864 iface, dstData, start, count);
3866 if (dstData == NULL || cnt < 0)
3867 return WINED3DERR_INVALIDCALL;
3869 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3870 return WINED3D_OK;
3873 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3874 IWineD3DDevice *iface,
3875 UINT start,
3876 CONST int *srcData,
3877 UINT count) {
3879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3880 int i, cnt = min(count, MAX_CONST_I - start);
3882 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3883 iface, srcData, start, count);
3885 if (srcData == NULL || cnt < 0)
3886 return WINED3DERR_INVALIDCALL;
3888 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3889 for (i = 0; i < cnt; i++)
3890 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3891 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3893 for (i = start; i < cnt + start; ++i) {
3894 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3897 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3899 return WINED3D_OK;
3902 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3903 IWineD3DDevice *iface,
3904 UINT start,
3905 int *dstData,
3906 UINT count) {
3908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3909 int cnt = min(count, MAX_CONST_I - start);
3911 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3912 iface, dstData, start, count);
3914 if (dstData == NULL || cnt < 0)
3915 return WINED3DERR_INVALIDCALL;
3917 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3918 return WINED3D_OK;
3921 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3922 IWineD3DDevice *iface,
3923 UINT start,
3924 CONST float *srcData,
3925 UINT count) {
3927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3928 int i;
3930 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3931 iface, srcData, start, count);
3933 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3934 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3935 return WINED3DERR_INVALIDCALL;
3937 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3938 if(TRACE_ON(d3d)) {
3939 for (i = 0; i < count; i++)
3940 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3941 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3944 for (i = start; i < count + start; ++i) {
3945 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3946 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3947 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3948 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3949 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3951 ptr->idx[ptr->count++] = i;
3952 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3956 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3958 return WINED3D_OK;
3961 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
3962 IWineD3DDevice *iface,
3963 UINT start,
3964 CONST float *srcData,
3965 UINT count) {
3967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3968 int i;
3970 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3971 iface, srcData, start, count);
3973 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3974 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3975 return WINED3DERR_INVALIDCALL;
3977 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3978 if(TRACE_ON(d3d)) {
3979 for (i = 0; i < count; i++)
3980 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3981 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3984 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3985 * context. On a context switch the old context will be fully dirtified
3987 memset(This->activeContext->pshader_const_dirty + start, 1,
3988 sizeof(*This->activeContext->pshader_const_dirty) * count);
3989 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count);
3991 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3993 return WINED3D_OK;
3996 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3997 IWineD3DDevice *iface,
3998 UINT start,
3999 float *dstData,
4000 UINT count) {
4002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4003 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4005 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4006 iface, dstData, start, count);
4008 if (dstData == NULL || cnt < 0)
4009 return WINED3DERR_INVALIDCALL;
4011 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4012 return WINED3D_OK;
4015 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4016 static HRESULT
4017 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4018 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4019 unsigned int i;
4020 DWORD DestFVF = dest->fvf;
4021 WINED3DVIEWPORT vp;
4022 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4023 BOOL doClip;
4024 int numTextures;
4026 if (lpStrideData->u.s.normal.lpData) {
4027 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4030 if (lpStrideData->u.s.position.lpData == NULL) {
4031 ERR("Source has no position mask\n");
4032 return WINED3DERR_INVALIDCALL;
4035 /* We might access VBOs from this code, so hold the lock */
4036 ENTER_GL();
4038 if (dest->resource.allocatedMemory == NULL) {
4039 /* This may happen if we do direct locking into a vbo. Unlikely,
4040 * but theoretically possible(ddraw processvertices test)
4042 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4043 if(!dest->resource.allocatedMemory) {
4044 LEAVE_GL();
4045 ERR("Out of memory\n");
4046 return E_OUTOFMEMORY;
4048 if(dest->vbo) {
4049 void *src;
4050 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4051 checkGLcall("glBindBufferARB");
4052 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4053 if(src) {
4054 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4056 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4057 checkGLcall("glUnmapBufferARB");
4061 /* Get a pointer into the destination vbo(create one if none exists) and
4062 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4064 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4065 dest->Flags |= VBFLAG_CREATEVBO;
4066 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4069 if(dest->vbo) {
4070 unsigned char extrabytes = 0;
4071 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4072 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4073 * this may write 4 extra bytes beyond the area that should be written
4075 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4076 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4077 if(!dest_conv_addr) {
4078 ERR("Out of memory\n");
4079 /* Continue without storing converted vertices */
4081 dest_conv = dest_conv_addr;
4084 /* Should I clip?
4085 * a) WINED3DRS_CLIPPING is enabled
4086 * b) WINED3DVOP_CLIP is passed
4088 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4089 static BOOL warned = FALSE;
4091 * The clipping code is not quite correct. Some things need
4092 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4093 * so disable clipping for now.
4094 * (The graphics in Half-Life are broken, and my processvertices
4095 * test crashes with IDirect3DDevice3)
4096 doClip = TRUE;
4098 doClip = FALSE;
4099 if(!warned) {
4100 warned = TRUE;
4101 FIXME("Clipping is broken and disabled for now\n");
4103 } else doClip = FALSE;
4104 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4106 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4107 WINED3DTS_VIEW,
4108 &view_mat);
4109 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4110 WINED3DTS_PROJECTION,
4111 &proj_mat);
4112 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4113 WINED3DTS_WORLDMATRIX(0),
4114 &world_mat);
4116 TRACE("View mat:\n");
4117 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);
4118 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);
4119 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);
4120 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);
4122 TRACE("Proj mat:\n");
4123 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);
4124 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);
4125 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);
4126 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);
4128 TRACE("World mat:\n");
4129 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);
4130 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);
4131 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);
4132 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);
4134 /* Get the viewport */
4135 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4136 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4137 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4139 multiply_matrix(&mat,&view_mat,&world_mat);
4140 multiply_matrix(&mat,&proj_mat,&mat);
4142 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4144 for (i = 0; i < dwCount; i+= 1) {
4145 unsigned int tex_index;
4147 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4148 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4149 /* The position first */
4150 float *p =
4151 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4152 float x, y, z, rhw;
4153 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4155 /* Multiplication with world, view and projection matrix */
4156 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);
4157 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);
4158 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);
4159 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);
4161 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4163 /* WARNING: The following things are taken from d3d7 and were not yet checked
4164 * against d3d8 or d3d9!
4167 /* Clipping conditions: From msdn
4169 * A vertex is clipped if it does not match the following requirements
4170 * -rhw < x <= rhw
4171 * -rhw < y <= rhw
4172 * 0 < z <= rhw
4173 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4175 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4176 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4180 if( !doClip ||
4181 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4182 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4183 ( rhw > eps ) ) ) {
4185 /* "Normal" viewport transformation (not clipped)
4186 * 1) The values are divided by rhw
4187 * 2) The y axis is negative, so multiply it with -1
4188 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4189 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4190 * 4) Multiply x with Width/2 and add Width/2
4191 * 5) The same for the height
4192 * 6) Add the viewpoint X and Y to the 2D coordinates and
4193 * The minimum Z value to z
4194 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4196 * Well, basically it's simply a linear transformation into viewport
4197 * coordinates
4200 x /= rhw;
4201 y /= rhw;
4202 z /= rhw;
4204 y *= -1;
4206 x *= vp.Width / 2;
4207 y *= vp.Height / 2;
4208 z *= vp.MaxZ - vp.MinZ;
4210 x += vp.Width / 2 + vp.X;
4211 y += vp.Height / 2 + vp.Y;
4212 z += vp.MinZ;
4214 rhw = 1 / rhw;
4215 } else {
4216 /* That vertex got clipped
4217 * Contrary to OpenGL it is not dropped completely, it just
4218 * undergoes a different calculation.
4220 TRACE("Vertex got clipped\n");
4221 x += rhw;
4222 y += rhw;
4224 x /= 2;
4225 y /= 2;
4227 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4228 * outside of the main vertex buffer memory. That needs some more
4229 * investigation...
4233 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4236 ( (float *) dest_ptr)[0] = x;
4237 ( (float *) dest_ptr)[1] = y;
4238 ( (float *) dest_ptr)[2] = z;
4239 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4241 dest_ptr += 3 * sizeof(float);
4243 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4244 dest_ptr += sizeof(float);
4247 if(dest_conv) {
4248 float w = 1 / rhw;
4249 ( (float *) dest_conv)[0] = x * w;
4250 ( (float *) dest_conv)[1] = y * w;
4251 ( (float *) dest_conv)[2] = z * w;
4252 ( (float *) dest_conv)[3] = w;
4254 dest_conv += 3 * sizeof(float);
4256 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4257 dest_conv += sizeof(float);
4261 if (DestFVF & WINED3DFVF_PSIZE) {
4262 dest_ptr += sizeof(DWORD);
4263 if(dest_conv) dest_conv += sizeof(DWORD);
4265 if (DestFVF & WINED3DFVF_NORMAL) {
4266 float *normal =
4267 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4268 /* AFAIK this should go into the lighting information */
4269 FIXME("Didn't expect the destination to have a normal\n");
4270 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4271 if(dest_conv) {
4272 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4276 if (DestFVF & WINED3DFVF_DIFFUSE) {
4277 DWORD *color_d =
4278 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4279 if(!color_d) {
4280 static BOOL warned = FALSE;
4282 if(!warned) {
4283 ERR("No diffuse color in source, but destination has one\n");
4284 warned = TRUE;
4287 *( (DWORD *) dest_ptr) = 0xffffffff;
4288 dest_ptr += sizeof(DWORD);
4290 if(dest_conv) {
4291 *( (DWORD *) dest_conv) = 0xffffffff;
4292 dest_conv += sizeof(DWORD);
4295 else {
4296 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4297 if(dest_conv) {
4298 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4299 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4300 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4301 dest_conv += sizeof(DWORD);
4306 if (DestFVF & WINED3DFVF_SPECULAR) {
4307 /* What's the color value in the feedback buffer? */
4308 DWORD *color_s =
4309 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4310 if(!color_s) {
4311 static BOOL warned = FALSE;
4313 if(!warned) {
4314 ERR("No specular color in source, but destination has one\n");
4315 warned = TRUE;
4318 *( (DWORD *) dest_ptr) = 0xFF000000;
4319 dest_ptr += sizeof(DWORD);
4321 if(dest_conv) {
4322 *( (DWORD *) dest_conv) = 0xFF000000;
4323 dest_conv += sizeof(DWORD);
4326 else {
4327 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4328 if(dest_conv) {
4329 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4330 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4331 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4332 dest_conv += sizeof(DWORD);
4337 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4338 float *tex_coord =
4339 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4340 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4341 if(!tex_coord) {
4342 ERR("No source texture, but destination requests one\n");
4343 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4344 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4346 else {
4347 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4348 if(dest_conv) {
4349 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4355 if(dest_conv) {
4356 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4357 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4358 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4359 dwCount * get_flexible_vertex_size(DestFVF),
4360 dest_conv_addr));
4361 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4362 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4365 LEAVE_GL();
4367 return WINED3D_OK;
4369 #undef copy_and_next
4371 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4373 WineDirect3DVertexStridedData strided;
4374 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4375 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4377 if(pVertexDecl) {
4378 ERR("Output vertex declaration not implemented yet\n");
4381 /* Need any context to write to the vbo. */
4382 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4384 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4385 * control the streamIsUP flag, thus restore it afterwards.
4387 This->stateBlock->streamIsUP = FALSE;
4388 memset(&strided, 0, sizeof(strided));
4389 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4390 This->stateBlock->streamIsUP = streamWasUP;
4392 if(vbo || SrcStartIndex) {
4393 unsigned int i;
4394 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4395 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4397 * Also get the start index in, but only loop over all elements if there's something to add at all.
4399 #define FIXSRC(type) \
4400 if(strided.u.s.type.VBO) { \
4401 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4402 strided.u.s.type.VBO = 0; \
4403 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4404 ENTER_GL(); \
4405 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4406 vb->vbo = 0; \
4407 LEAVE_GL(); \
4409 if(strided.u.s.type.lpData) { \
4410 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4412 FIXSRC(position);
4413 FIXSRC(blendWeights);
4414 FIXSRC(blendMatrixIndices);
4415 FIXSRC(normal);
4416 FIXSRC(pSize);
4417 FIXSRC(diffuse);
4418 FIXSRC(specular);
4419 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4420 FIXSRC(texCoords[i]);
4422 FIXSRC(position2);
4423 FIXSRC(normal2);
4424 FIXSRC(tangent);
4425 FIXSRC(binormal);
4426 FIXSRC(tessFactor);
4427 FIXSRC(fog);
4428 FIXSRC(depth);
4429 FIXSRC(sample);
4430 #undef FIXSRC
4433 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4436 /*****
4437 * Get / Set Texture Stage States
4438 * TODO: Verify against dx9 definitions
4439 *****/
4440 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4442 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4444 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4446 if (Stage >= MAX_TEXTURES) {
4447 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4448 return WINED3D_OK;
4451 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4452 This->updateStateBlock->textureState[Stage][Type] = Value;
4454 if (This->isRecordingState) {
4455 TRACE("Recording... not performing anything\n");
4456 return WINED3D_OK;
4459 /* Checked after the assignments to allow proper stateblock recording */
4460 if(oldValue == Value) {
4461 TRACE("App is setting the old value over, nothing to do\n");
4462 return WINED3D_OK;
4465 if(Stage > This->stateBlock->lowest_disabled_stage &&
4466 This->shader_backend->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4467 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4468 * Changes in other states are important on disabled stages too
4470 return WINED3D_OK;
4473 if(Type == WINED3DTSS_COLOROP) {
4474 int i;
4476 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4477 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4478 * they have to be disabled
4480 * The current stage is dirtified below.
4482 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4483 TRACE("Additionally dirtifying stage %d\n", i);
4484 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4486 This->stateBlock->lowest_disabled_stage = Stage;
4487 TRACE("New lowest disabled: %d\n", Stage);
4488 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4489 /* Previously disabled stage enabled. Stages above it may need enabling
4490 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4491 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4493 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4496 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4497 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4498 break;
4500 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4501 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4503 This->stateBlock->lowest_disabled_stage = i;
4504 TRACE("New lowest disabled: %d\n", i);
4506 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4507 /* TODO: Built a stage -> texture unit mapping for register combiners */
4511 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4513 return WINED3D_OK;
4516 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4518 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4519 *pValue = This->updateStateBlock->textureState[Stage][Type];
4520 return WINED3D_OK;
4523 /*****
4524 * Get / Set Texture
4525 *****/
4526 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4528 IWineD3DBaseTexture *oldTexture;
4530 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4532 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4533 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4536 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4537 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4538 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4541 oldTexture = This->updateStateBlock->textures[Stage];
4543 if(pTexture != NULL) {
4544 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4546 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4547 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4548 return WINED3DERR_INVALIDCALL;
4550 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4553 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4554 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4556 This->updateStateBlock->changed.textures[Stage] = TRUE;
4557 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4558 This->updateStateBlock->textures[Stage] = pTexture;
4560 /* Handle recording of state blocks */
4561 if (This->isRecordingState) {
4562 TRACE("Recording... not performing anything\n");
4563 return WINED3D_OK;
4566 if(oldTexture == pTexture) {
4567 TRACE("App is setting the same texture again, nothing to do\n");
4568 return WINED3D_OK;
4571 /** NOTE: MSDN says that setTexture increases the reference count,
4572 * and that the application must set the texture back to null (or have a leaky application),
4573 * This means we should pass the refcount up to the parent
4574 *******************************/
4575 if (NULL != This->updateStateBlock->textures[Stage]) {
4576 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4577 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4579 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4580 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4581 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4582 * so the COLOROP and ALPHAOP have to be dirtified.
4584 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4585 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4587 if(bindCount == 1) {
4588 new->baseTexture.sampler = Stage;
4590 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4594 if (NULL != oldTexture) {
4595 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4596 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4598 IWineD3DBaseTexture_Release(oldTexture);
4599 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4600 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4601 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4604 if(bindCount && old->baseTexture.sampler == Stage) {
4605 int i;
4606 /* Have to do a search for the other sampler(s) where the texture is bound to
4607 * Shouldn't happen as long as apps bind a texture only to one stage
4609 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4610 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4611 if(This->updateStateBlock->textures[i] == oldTexture) {
4612 old->baseTexture.sampler = i;
4613 break;
4619 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4621 return WINED3D_OK;
4624 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4627 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4629 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4630 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4633 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4634 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4635 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4638 *ppTexture=This->stateBlock->textures[Stage];
4639 if (*ppTexture)
4640 IWineD3DBaseTexture_AddRef(*ppTexture);
4642 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4644 return WINED3D_OK;
4647 /*****
4648 * Get Back Buffer
4649 *****/
4650 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4651 IWineD3DSurface **ppBackBuffer) {
4652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4653 IWineD3DSwapChain *swapChain;
4654 HRESULT hr;
4656 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4658 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4659 if (hr == WINED3D_OK) {
4660 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4661 IWineD3DSwapChain_Release(swapChain);
4662 } else {
4663 *ppBackBuffer = NULL;
4665 return hr;
4668 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4670 WARN("(%p) : stub, calling idirect3d for now\n", This);
4671 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4674 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4676 IWineD3DSwapChain *swapChain;
4677 HRESULT hr;
4679 if(iSwapChain > 0) {
4680 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4681 if (hr == WINED3D_OK) {
4682 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4683 IWineD3DSwapChain_Release(swapChain);
4684 } else {
4685 FIXME("(%p) Error getting display mode\n", This);
4687 } else {
4688 /* Don't read the real display mode,
4689 but return the stored mode instead. X11 can't change the color
4690 depth, and some apps are pretty angry if they SetDisplayMode from
4691 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4693 Also don't relay to the swapchain because with ddraw it's possible
4694 that there isn't a swapchain at all */
4695 pMode->Width = This->ddraw_width;
4696 pMode->Height = This->ddraw_height;
4697 pMode->Format = This->ddraw_format;
4698 pMode->RefreshRate = 0;
4699 hr = WINED3D_OK;
4702 return hr;
4705 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4707 TRACE("(%p)->(%p)\n", This, hWnd);
4709 if(This->ddraw_fullscreen) {
4710 if(This->ddraw_window && This->ddraw_window != hWnd) {
4711 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4713 if(hWnd && This->ddraw_window != hWnd) {
4714 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4718 This->ddraw_window = hWnd;
4719 return WINED3D_OK;
4722 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4724 TRACE("(%p)->(%p)\n", This, hWnd);
4726 *hWnd = This->ddraw_window;
4727 return WINED3D_OK;
4730 /*****
4731 * Stateblock related functions
4732 *****/
4734 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4736 IWineD3DStateBlockImpl *object;
4737 HRESULT temp_result;
4738 int i;
4740 TRACE("(%p)\n", This);
4742 if (This->isRecordingState) {
4743 return WINED3DERR_INVALIDCALL;
4746 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4747 if (NULL == object ) {
4748 FIXME("(%p)Error allocating memory for stateblock\n", This);
4749 return E_OUTOFMEMORY;
4751 TRACE("(%p) created object %p\n", This, object);
4752 object->wineD3DDevice= This;
4753 /** FIXME: object->parent = parent; **/
4754 object->parent = NULL;
4755 object->blockType = WINED3DSBT_RECORDED;
4756 object->ref = 1;
4757 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4759 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4760 list_init(&object->lightMap[i]);
4763 temp_result = allocate_shader_constants(object);
4764 if (WINED3D_OK != temp_result)
4765 return temp_result;
4767 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4768 This->updateStateBlock = object;
4769 This->isRecordingState = TRUE;
4771 TRACE("(%p) recording stateblock %p\n",This , object);
4772 return WINED3D_OK;
4775 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4777 unsigned int i, j;
4778 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4780 if (!This->isRecordingState) {
4781 FIXME("(%p) not recording! returning error\n", This);
4782 *ppStateBlock = NULL;
4783 return WINED3DERR_INVALIDCALL;
4786 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4787 if(object->changed.renderState[i]) {
4788 object->contained_render_states[object->num_contained_render_states] = i;
4789 object->num_contained_render_states++;
4792 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4793 if(object->changed.transform[i]) {
4794 object->contained_transform_states[object->num_contained_transform_states] = i;
4795 object->num_contained_transform_states++;
4798 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4799 if(object->changed.vertexShaderConstantsF[i]) {
4800 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4801 object->num_contained_vs_consts_f++;
4804 for(i = 0; i < MAX_CONST_I; i++) {
4805 if(object->changed.vertexShaderConstantsI[i]) {
4806 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4807 object->num_contained_vs_consts_i++;
4810 for(i = 0; i < MAX_CONST_B; i++) {
4811 if(object->changed.vertexShaderConstantsB[i]) {
4812 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4813 object->num_contained_vs_consts_b++;
4816 for(i = 0; i < MAX_CONST_I; i++) {
4817 if(object->changed.pixelShaderConstantsI[i]) {
4818 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4819 object->num_contained_ps_consts_i++;
4822 for(i = 0; i < MAX_CONST_B; i++) {
4823 if(object->changed.pixelShaderConstantsB[i]) {
4824 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4825 object->num_contained_ps_consts_b++;
4828 for(i = 0; i < MAX_TEXTURES; i++) {
4829 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4830 if(object->changed.textureState[i][j]) {
4831 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4832 object->contained_tss_states[object->num_contained_tss_states].state = j;
4833 object->num_contained_tss_states++;
4837 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4838 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4839 if(object->changed.samplerState[i][j]) {
4840 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4841 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4842 object->num_contained_sampler_states++;
4847 *ppStateBlock = (IWineD3DStateBlock*) object;
4848 This->isRecordingState = FALSE;
4849 This->updateStateBlock = This->stateBlock;
4850 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4851 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4852 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4853 return WINED3D_OK;
4856 /*****
4857 * Scene related functions
4858 *****/
4859 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4860 /* At the moment we have no need for any functionality at the beginning
4861 of a scene */
4862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4863 TRACE("(%p)\n", This);
4865 if(This->inScene) {
4866 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4867 return WINED3DERR_INVALIDCALL;
4869 This->inScene = TRUE;
4870 return WINED3D_OK;
4873 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4875 TRACE("(%p)\n", This);
4877 if(!This->inScene) {
4878 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4879 return WINED3DERR_INVALIDCALL;
4882 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4883 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4884 ENTER_GL();
4885 glFlush();
4886 checkGLcall("glFlush");
4887 LEAVE_GL();
4889 This->inScene = FALSE;
4890 return WINED3D_OK;
4893 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4894 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4895 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4897 IWineD3DSwapChain *swapChain = NULL;
4898 int i;
4899 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4901 TRACE("(%p) Presenting the frame\n", This);
4903 for(i = 0 ; i < swapchains ; i ++) {
4905 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4906 TRACE("presentinng chain %d, %p\n", i, swapChain);
4907 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4908 IWineD3DSwapChain_Release(swapChain);
4911 return WINED3D_OK;
4914 /* Not called from the VTable (internal subroutine) */
4915 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4916 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4917 float Z, DWORD Stencil) {
4918 GLbitfield glMask = 0;
4919 unsigned int i;
4920 WINED3DRECT curRect;
4921 RECT vp_rect;
4922 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4923 UINT drawable_width, drawable_height;
4924 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4926 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4927 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4928 * for the cleared parts, and the untouched parts.
4930 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4931 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4932 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4933 * checking all this if the dest surface is in the drawable anyway.
4935 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4936 while(1) {
4937 if(vp->X != 0 || vp->Y != 0 ||
4938 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4939 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4940 break;
4942 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4943 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4944 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4945 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4946 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4947 break;
4949 if(Count > 0 && pRects && (
4950 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4951 pRects[0].x2 < target->currentDesc.Width ||
4952 pRects[0].y2 < target->currentDesc.Height)) {
4953 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4954 break;
4956 break;
4960 target->get_drawable_size(target, &drawable_width, &drawable_height);
4962 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4963 ENTER_GL();
4965 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4966 apply_fbo_state((IWineD3DDevice *) This);
4969 /* Only set the values up once, as they are not changing */
4970 if (Flags & WINED3DCLEAR_STENCIL) {
4971 glClearStencil(Stencil);
4972 checkGLcall("glClearStencil");
4973 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4974 glStencilMask(0xFFFFFFFF);
4977 if (Flags & WINED3DCLEAR_ZBUFFER) {
4978 glDepthMask(GL_TRUE);
4979 glClearDepth(Z);
4980 checkGLcall("glClearDepth");
4981 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4982 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4984 if(This->depth_copy_state == WINED3D_DCS_COPY) {
4985 if(vp->X != 0 || vp->Y != 0 ||
4986 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4987 depth_copy((IWineD3DDevice *) This);
4989 else if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4990 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4991 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4992 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4993 depth_copy((IWineD3DDevice *) This);
4995 else if(Count > 0 && pRects && (
4996 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4997 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4998 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4999 depth_copy((IWineD3DDevice *) This);
5002 This->depth_copy_state = WINED3D_DCS_INITIAL;
5005 if (Flags & WINED3DCLEAR_TARGET) {
5006 TRACE("Clearing screen with glClear to color %x\n", Color);
5007 glClearColor(D3DCOLOR_R(Color),
5008 D3DCOLOR_G(Color),
5009 D3DCOLOR_B(Color),
5010 D3DCOLOR_A(Color));
5011 checkGLcall("glClearColor");
5013 /* Clear ALL colors! */
5014 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5015 glMask = glMask | GL_COLOR_BUFFER_BIT;
5018 vp_rect.left = vp->X;
5019 vp_rect.top = vp->Y;
5020 vp_rect.right = vp->X + vp->Width;
5021 vp_rect.bottom = vp->Y + vp->Height;
5022 if (!(Count > 0 && pRects)) {
5023 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5024 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5026 if(This->render_offscreen) {
5027 glScissor(vp_rect.left, vp_rect.top,
5028 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5029 } else {
5030 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5031 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5033 checkGLcall("glScissor");
5034 glClear(glMask);
5035 checkGLcall("glClear");
5036 } else {
5037 /* Now process each rect in turn */
5038 for (i = 0; i < Count; i++) {
5039 /* Note gl uses lower left, width/height */
5040 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5041 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5042 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5044 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5045 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5046 curRect.x1, (target->currentDesc.Height - curRect.y2),
5047 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5049 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5050 * The rectangle is not cleared, no error is returned, but further rectanlges are
5051 * still cleared if they are valid
5053 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5054 TRACE("Rectangle with negative dimensions, ignoring\n");
5055 continue;
5058 if(This->render_offscreen) {
5059 glScissor(curRect.x1, curRect.y1,
5060 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5061 } else {
5062 glScissor(curRect.x1, drawable_height - curRect.y2,
5063 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5065 checkGLcall("glScissor");
5067 glClear(glMask);
5068 checkGLcall("glClear");
5072 /* Restore the old values (why..?) */
5073 if (Flags & WINED3DCLEAR_STENCIL) {
5074 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5076 if (Flags & WINED3DCLEAR_TARGET) {
5077 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5078 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5079 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5080 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5081 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5083 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5084 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5086 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5087 /* TODO: Move the fbo logic into ModifyLocation() */
5088 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5089 target->Flags |= SFLAG_INTEXTURE;
5092 LEAVE_GL();
5094 return WINED3D_OK;
5097 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5098 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5100 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5102 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5103 Count, pRects, Flags, Color, Z, Stencil);
5105 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5106 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5107 /* TODO: What about depth stencil buffers without stencil bits? */
5108 return WINED3DERR_INVALIDCALL;
5111 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5114 /*****
5115 * Drawing functions
5116 *****/
5117 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5118 UINT PrimitiveCount) {
5120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5122 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5123 debug_d3dprimitivetype(PrimitiveType),
5124 StartVertex, PrimitiveCount);
5126 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5127 if(This->stateBlock->streamIsUP) {
5128 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5129 This->stateBlock->streamIsUP = FALSE;
5132 if(This->stateBlock->loadBaseVertexIndex != 0) {
5133 This->stateBlock->loadBaseVertexIndex = 0;
5134 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5136 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5137 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5138 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5139 return WINED3D_OK;
5142 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5143 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5144 WINED3DPRIMITIVETYPE PrimitiveType,
5145 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5148 UINT idxStride = 2;
5149 IWineD3DIndexBuffer *pIB;
5150 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5151 GLuint vbo;
5153 pIB = This->stateBlock->pIndexData;
5154 if (!pIB) {
5155 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5156 * without an index buffer set. (The first time at least...)
5157 * D3D8 simply dies, but I doubt it can do much harm to return
5158 * D3DERR_INVALIDCALL there as well. */
5159 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5160 return WINED3DERR_INVALIDCALL;
5163 if(This->stateBlock->streamIsUP) {
5164 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5165 This->stateBlock->streamIsUP = FALSE;
5167 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5169 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5170 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5171 minIndex, NumVertices, startIndex, primCount);
5173 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5174 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5175 idxStride = 2;
5176 } else {
5177 idxStride = 4;
5180 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5181 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5182 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5185 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5186 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5188 return WINED3D_OK;
5191 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5192 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5193 UINT VertexStreamZeroStride) {
5194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5195 IWineD3DVertexBuffer *vb;
5197 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5198 debug_d3dprimitivetype(PrimitiveType),
5199 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5201 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5202 vb = This->stateBlock->streamSource[0];
5203 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5204 if(vb) IWineD3DVertexBuffer_Release(vb);
5205 This->stateBlock->streamOffset[0] = 0;
5206 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5207 This->stateBlock->streamIsUP = TRUE;
5208 This->stateBlock->loadBaseVertexIndex = 0;
5210 /* TODO: Only mark dirty if drawing from a different UP address */
5211 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5213 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5214 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5216 /* MSDN specifies stream zero settings must be set to NULL */
5217 This->stateBlock->streamStride[0] = 0;
5218 This->stateBlock->streamSource[0] = NULL;
5220 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5221 * the new stream sources or use UP drawing again
5223 return WINED3D_OK;
5226 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5227 UINT MinVertexIndex, UINT NumVertices,
5228 UINT PrimitiveCount, CONST void* pIndexData,
5229 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5230 UINT VertexStreamZeroStride) {
5231 int idxStride;
5232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5233 IWineD3DVertexBuffer *vb;
5234 IWineD3DIndexBuffer *ib;
5236 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5237 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5238 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5239 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5241 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5242 idxStride = 2;
5243 } else {
5244 idxStride = 4;
5247 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5248 vb = This->stateBlock->streamSource[0];
5249 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5250 if(vb) IWineD3DVertexBuffer_Release(vb);
5251 This->stateBlock->streamIsUP = TRUE;
5252 This->stateBlock->streamOffset[0] = 0;
5253 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5255 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5256 This->stateBlock->baseVertexIndex = 0;
5257 This->stateBlock->loadBaseVertexIndex = 0;
5258 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5259 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5260 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5262 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5264 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5265 This->stateBlock->streamSource[0] = NULL;
5266 This->stateBlock->streamStride[0] = 0;
5267 ib = This->stateBlock->pIndexData;
5268 if(ib) {
5269 IWineD3DIndexBuffer_Release(ib);
5270 This->stateBlock->pIndexData = NULL;
5272 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5273 * SetStreamSource to specify a vertex buffer
5276 return WINED3D_OK;
5279 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5282 /* Mark the state dirty until we have nicer tracking
5283 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5284 * that value.
5286 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5287 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5288 This->stateBlock->baseVertexIndex = 0;
5289 This->up_strided = DrawPrimStrideData;
5290 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5291 This->up_strided = NULL;
5292 return WINED3D_OK;
5295 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5297 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5299 /* Mark the state dirty until we have nicer tracking
5300 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5301 * that value.
5303 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5304 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5305 This->stateBlock->streamIsUP = TRUE;
5306 This->stateBlock->baseVertexIndex = 0;
5307 This->up_strided = DrawPrimStrideData;
5308 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5309 This->up_strided = NULL;
5310 return WINED3D_OK;
5313 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5314 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5315 * not callable by the app directly no parameter validation checks are needed here.
5317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5318 WINED3DLOCKED_BOX src;
5319 WINED3DLOCKED_BOX dst;
5320 HRESULT hr;
5321 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5323 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5324 * dirtification to improve loading performance.
5326 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5327 if(FAILED(hr)) return hr;
5328 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5329 if(FAILED(hr)) {
5330 IWineD3DVolume_UnlockBox(pSourceVolume);
5331 return hr;
5334 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5336 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5337 if(FAILED(hr)) {
5338 IWineD3DVolume_UnlockBox(pSourceVolume);
5339 } else {
5340 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5342 return hr;
5345 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5346 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5347 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5348 HRESULT hr = WINED3D_OK;
5349 WINED3DRESOURCETYPE sourceType;
5350 WINED3DRESOURCETYPE destinationType;
5351 int i ,levels;
5353 /* TODO: think about moving the code into IWineD3DBaseTexture */
5355 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5357 /* verify that the source and destination textures aren't NULL */
5358 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5359 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5360 This, pSourceTexture, pDestinationTexture);
5361 hr = WINED3DERR_INVALIDCALL;
5364 if (pSourceTexture == pDestinationTexture) {
5365 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5366 This, pSourceTexture, pDestinationTexture);
5367 hr = WINED3DERR_INVALIDCALL;
5369 /* Verify that the source and destination textures are the same type */
5370 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5371 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5373 if (sourceType != destinationType) {
5374 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5375 This);
5376 hr = WINED3DERR_INVALIDCALL;
5379 /* check that both textures have the identical numbers of levels */
5380 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5381 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5382 hr = WINED3DERR_INVALIDCALL;
5385 if (WINED3D_OK == hr) {
5387 /* Make sure that the destination texture is loaded */
5388 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5390 /* Update every surface level of the texture */
5391 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5393 switch (sourceType) {
5394 case WINED3DRTYPE_TEXTURE:
5396 IWineD3DSurface *srcSurface;
5397 IWineD3DSurface *destSurface;
5399 for (i = 0 ; i < levels ; ++i) {
5400 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5401 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5402 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5403 IWineD3DSurface_Release(srcSurface);
5404 IWineD3DSurface_Release(destSurface);
5405 if (WINED3D_OK != hr) {
5406 WARN("(%p) : Call to update surface failed\n", This);
5407 return hr;
5411 break;
5412 case WINED3DRTYPE_CUBETEXTURE:
5414 IWineD3DSurface *srcSurface;
5415 IWineD3DSurface *destSurface;
5416 WINED3DCUBEMAP_FACES faceType;
5418 for (i = 0 ; i < levels ; ++i) {
5419 /* Update each cube face */
5420 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5421 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5422 if (WINED3D_OK != hr) {
5423 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5424 } else {
5425 TRACE("Got srcSurface %p\n", srcSurface);
5427 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5428 if (WINED3D_OK != hr) {
5429 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5430 } else {
5431 TRACE("Got desrSurface %p\n", destSurface);
5433 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5434 IWineD3DSurface_Release(srcSurface);
5435 IWineD3DSurface_Release(destSurface);
5436 if (WINED3D_OK != hr) {
5437 WARN("(%p) : Call to update surface failed\n", This);
5438 return hr;
5443 break;
5445 case WINED3DRTYPE_VOLUMETEXTURE:
5447 IWineD3DVolume *srcVolume = NULL;
5448 IWineD3DVolume *destVolume = NULL;
5450 for (i = 0 ; i < levels ; ++i) {
5451 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5452 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5453 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5454 IWineD3DVolume_Release(srcVolume);
5455 IWineD3DVolume_Release(destVolume);
5456 if (WINED3D_OK != hr) {
5457 WARN("(%p) : Call to update volume failed\n", This);
5458 return hr;
5462 break;
5464 default:
5465 FIXME("(%p) : Unsupported source and destination type\n", This);
5466 hr = WINED3DERR_INVALIDCALL;
5470 return hr;
5473 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5474 IWineD3DSwapChain *swapChain;
5475 HRESULT hr;
5476 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5477 if(hr == WINED3D_OK) {
5478 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5479 IWineD3DSwapChain_Release(swapChain);
5481 return hr;
5484 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5486 /* return a sensible default */
5487 *pNumPasses = 1;
5488 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5489 FIXME("(%p) : stub\n", This);
5490 return WINED3D_OK;
5493 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5495 int i;
5497 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5498 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5499 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5500 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5505 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5507 int j;
5508 UINT NewSize;
5509 PALETTEENTRY **palettes;
5511 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5513 if (PaletteNumber >= MAX_PALETTES) {
5514 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5515 return WINED3DERR_INVALIDCALL;
5518 if (PaletteNumber >= This->NumberOfPalettes) {
5519 NewSize = This->NumberOfPalettes;
5520 do {
5521 NewSize *= 2;
5522 } while(PaletteNumber >= NewSize);
5523 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5524 if (!palettes) {
5525 ERR("Out of memory!\n");
5526 return E_OUTOFMEMORY;
5528 This->palettes = palettes;
5529 This->NumberOfPalettes = NewSize;
5532 if (!This->palettes[PaletteNumber]) {
5533 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5534 if (!This->palettes[PaletteNumber]) {
5535 ERR("Out of memory!\n");
5536 return E_OUTOFMEMORY;
5540 for (j = 0; j < 256; ++j) {
5541 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5542 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5543 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5544 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5546 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5547 TRACE("(%p) : returning\n", This);
5548 return WINED3D_OK;
5551 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5553 int j;
5554 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5555 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5556 /* What happens in such situation isn't documented; Native seems to silently abort
5557 on such conditions. Return Invalid Call. */
5558 ERR("(%p) : (%u) Non-existent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5559 return WINED3DERR_INVALIDCALL;
5561 for (j = 0; j < 256; ++j) {
5562 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5563 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5564 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5565 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5567 TRACE("(%p) : returning\n", This);
5568 return WINED3D_OK;
5571 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5573 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5574 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5575 (tested with reference rasterizer). Return Invalid Call. */
5576 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5577 ERR("(%p) : (%u) Non-existent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5578 return WINED3DERR_INVALIDCALL;
5580 /*TODO: stateblocks */
5581 if (This->currentPalette != PaletteNumber) {
5582 This->currentPalette = PaletteNumber;
5583 dirtify_p8_texture_samplers(This);
5585 TRACE("(%p) : returning\n", This);
5586 return WINED3D_OK;
5589 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5591 if (PaletteNumber == NULL) {
5592 WARN("(%p) : returning Invalid Call\n", This);
5593 return WINED3DERR_INVALIDCALL;
5595 /*TODO: stateblocks */
5596 *PaletteNumber = This->currentPalette;
5597 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5598 return WINED3D_OK;
5601 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5603 static BOOL showFixmes = TRUE;
5604 if (showFixmes) {
5605 FIXME("(%p) : stub\n", This);
5606 showFixmes = FALSE;
5609 This->softwareVertexProcessing = bSoftware;
5610 return WINED3D_OK;
5614 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5616 static BOOL showFixmes = TRUE;
5617 if (showFixmes) {
5618 FIXME("(%p) : stub\n", This);
5619 showFixmes = FALSE;
5621 return This->softwareVertexProcessing;
5625 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5627 IWineD3DSwapChain *swapChain;
5628 HRESULT hr;
5630 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5632 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5633 if(hr == WINED3D_OK){
5634 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5635 IWineD3DSwapChain_Release(swapChain);
5636 }else{
5637 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5639 return hr;
5643 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5645 static BOOL showfixmes = TRUE;
5646 if(nSegments != 0.0f) {
5647 if( showfixmes) {
5648 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5649 showfixmes = FALSE;
5652 return WINED3D_OK;
5655 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5657 static BOOL showfixmes = TRUE;
5658 if( showfixmes) {
5659 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5660 showfixmes = FALSE;
5662 return 0.0f;
5665 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5666 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5667 /** TODO: remove casts to IWineD3DSurfaceImpl
5668 * NOTE: move code to surface to accomplish this
5669 ****************************************/
5670 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5671 int srcWidth, srcHeight;
5672 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5673 WINED3DFORMAT destFormat, srcFormat;
5674 UINT destSize;
5675 int srcLeft, destLeft, destTop;
5676 WINED3DPOOL srcPool, destPool;
5677 int offset = 0;
5678 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5679 glDescriptor *glDescription = NULL;
5680 GLenum dummy;
5681 int bpp;
5682 CONVERT_TYPES convert = NO_CONVERSION;
5684 WINED3DSURFACE_DESC winedesc;
5686 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5687 memset(&winedesc, 0, sizeof(winedesc));
5688 winedesc.Width = &srcSurfaceWidth;
5689 winedesc.Height = &srcSurfaceHeight;
5690 winedesc.Pool = &srcPool;
5691 winedesc.Format = &srcFormat;
5693 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5695 winedesc.Width = &destSurfaceWidth;
5696 winedesc.Height = &destSurfaceHeight;
5697 winedesc.Pool = &destPool;
5698 winedesc.Format = &destFormat;
5699 winedesc.Size = &destSize;
5701 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5703 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5704 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5705 return WINED3DERR_INVALIDCALL;
5708 /* This call loads the opengl surface directly, instead of copying the surface to the
5709 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5710 * copy in sysmem and use regular surface loading.
5712 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5713 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5714 if(convert != NO_CONVERSION) {
5715 return IWineD3DSurface_BltFast(pDestinationSurface,
5716 pDestPoint ? pDestPoint->x : 0,
5717 pDestPoint ? pDestPoint->y : 0,
5718 pSourceSurface, (RECT *) pSourceRect, 0);
5721 if (destFormat == WINED3DFMT_UNKNOWN) {
5722 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5723 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5725 /* Get the update surface description */
5726 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5729 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5731 ENTER_GL();
5733 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5734 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5735 checkGLcall("glActiveTextureARB");
5738 /* Make sure the surface is loaded and up to date */
5739 IWineD3DSurface_PreLoad(pDestinationSurface);
5741 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5743 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5744 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5745 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5746 srcLeft = pSourceRect ? pSourceRect->left : 0;
5747 destLeft = pDestPoint ? pDestPoint->x : 0;
5748 destTop = pDestPoint ? pDestPoint->y : 0;
5751 /* This function doesn't support compressed textures
5752 the pitch is just bytesPerPixel * width */
5753 if(srcWidth != srcSurfaceWidth || srcLeft ){
5754 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5755 offset += srcLeft * pSrcSurface->bytesPerPixel;
5756 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5758 /* TODO DXT formats */
5760 if(pSourceRect != NULL && pSourceRect->top != 0){
5761 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5763 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5764 ,This
5765 ,glDescription->level
5766 ,destLeft
5767 ,destTop
5768 ,srcWidth
5769 ,srcHeight
5770 ,glDescription->glFormat
5771 ,glDescription->glType
5772 ,IWineD3DSurface_GetData(pSourceSurface)
5775 /* Sanity check */
5776 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5778 /* need to lock the surface to get the data */
5779 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5782 /* TODO: Cube and volume support */
5783 if(rowoffset != 0){
5784 /* not a whole row so we have to do it a line at a time */
5785 int j;
5787 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5788 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5790 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5792 glTexSubImage2D(glDescription->target
5793 ,glDescription->level
5794 ,destLeft
5796 ,srcWidth
5798 ,glDescription->glFormat
5799 ,glDescription->glType
5800 ,data /* could be quicker using */
5802 data += rowoffset;
5805 } else { /* Full width, so just write out the whole texture */
5807 if (WINED3DFMT_DXT1 == destFormat ||
5808 WINED3DFMT_DXT2 == destFormat ||
5809 WINED3DFMT_DXT3 == destFormat ||
5810 WINED3DFMT_DXT4 == destFormat ||
5811 WINED3DFMT_DXT5 == destFormat) {
5812 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5813 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5814 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5815 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5816 } if (destFormat != srcFormat) {
5817 FIXME("Updating mixed format compressed texture is not curretly support\n");
5818 } else {
5819 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5820 glDescription->level,
5821 glDescription->glFormatInternal,
5822 srcWidth,
5823 srcHeight,
5825 destSize,
5826 IWineD3DSurface_GetData(pSourceSurface));
5828 } else {
5829 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5833 } else {
5834 glTexSubImage2D(glDescription->target
5835 ,glDescription->level
5836 ,destLeft
5837 ,destTop
5838 ,srcWidth
5839 ,srcHeight
5840 ,glDescription->glFormat
5841 ,glDescription->glType
5842 ,IWineD3DSurface_GetData(pSourceSurface)
5846 checkGLcall("glTexSubImage2D");
5848 LEAVE_GL();
5850 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5851 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5853 return WINED3D_OK;
5856 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5858 struct WineD3DRectPatch *patch;
5859 unsigned int i;
5860 struct list *e;
5861 BOOL found;
5862 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5864 if(!(Handle || pRectPatchInfo)) {
5865 /* TODO: Write a test for the return value, thus the FIXME */
5866 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5867 return WINED3DERR_INVALIDCALL;
5870 if(Handle) {
5871 i = PATCHMAP_HASHFUNC(Handle);
5872 found = FALSE;
5873 LIST_FOR_EACH(e, &This->patches[i]) {
5874 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5875 if(patch->Handle == Handle) {
5876 found = TRUE;
5877 break;
5881 if(!found) {
5882 TRACE("Patch does not exist. Creating a new one\n");
5883 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5884 patch->Handle = Handle;
5885 list_add_head(&This->patches[i], &patch->entry);
5886 } else {
5887 TRACE("Found existing patch %p\n", patch);
5889 } else {
5890 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5891 * attributes we have to tesselate, read back, and draw. This needs a patch
5892 * management structure instance. Create one.
5894 * A possible improvement is to check if a vertex shader is used, and if not directly
5895 * draw the patch.
5897 FIXME("Drawing an uncached patch. This is slow\n");
5898 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5901 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5902 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5903 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5904 HRESULT hr;
5905 TRACE("Tesselation density or patch info changed, retesselating\n");
5907 if(pRectPatchInfo) {
5908 patch->RectPatchInfo = *pRectPatchInfo;
5910 patch->numSegs[0] = pNumSegs[0];
5911 patch->numSegs[1] = pNumSegs[1];
5912 patch->numSegs[2] = pNumSegs[2];
5913 patch->numSegs[3] = pNumSegs[3];
5915 hr = tesselate_rectpatch(This, patch);
5916 if(FAILED(hr)) {
5917 WARN("Patch tesselation failed\n");
5919 /* Do not release the handle to store the params of the patch */
5920 if(!Handle) {
5921 HeapFree(GetProcessHeap(), 0, patch);
5923 return hr;
5927 This->currentPatch = patch;
5928 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5929 This->currentPatch = NULL;
5931 /* Destroy uncached patches */
5932 if(!Handle) {
5933 HeapFree(GetProcessHeap(), 0, patch->mem);
5934 HeapFree(GetProcessHeap(), 0, patch);
5936 return WINED3D_OK;
5939 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5941 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5942 FIXME("(%p) : Stub\n", This);
5943 return WINED3D_OK;
5946 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5948 int i;
5949 struct WineD3DRectPatch *patch;
5950 struct list *e;
5951 TRACE("(%p) Handle(%d)\n", This, Handle);
5953 i = PATCHMAP_HASHFUNC(Handle);
5954 LIST_FOR_EACH(e, &This->patches[i]) {
5955 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5956 if(patch->Handle == Handle) {
5957 TRACE("Deleting patch %p\n", patch);
5958 list_remove(&patch->entry);
5959 HeapFree(GetProcessHeap(), 0, patch->mem);
5960 HeapFree(GetProcessHeap(), 0, patch);
5961 return WINED3D_OK;
5965 /* TODO: Write a test for the return value */
5966 FIXME("Attempt to destroy nonexistent patch\n");
5967 return WINED3DERR_INVALIDCALL;
5970 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5971 HRESULT hr;
5972 IWineD3DSwapChain *swapchain;
5974 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5975 if (SUCCEEDED(hr)) {
5976 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5977 return swapchain;
5980 return NULL;
5983 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5984 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5986 if (!*fbo) {
5987 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5988 checkGLcall("glGenFramebuffersEXT()");
5990 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5991 checkGLcall("glBindFramebuffer()");
5994 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5995 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5996 IWineD3DBaseTextureImpl *texture_impl;
5997 GLenum texttarget, target;
5998 GLint old_binding;
6000 texttarget = surface_impl->glDescription.target;
6001 if(texttarget == GL_TEXTURE_2D) {
6002 target = GL_TEXTURE_2D;
6003 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6004 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6005 target = GL_TEXTURE_RECTANGLE_ARB;
6006 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6007 } else {
6008 target = GL_TEXTURE_CUBE_MAP_ARB;
6009 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6012 IWineD3DSurface_PreLoad(surface);
6014 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6015 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6016 glBindTexture(target, old_binding);
6018 /* Update base texture states array */
6019 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6020 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6021 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6022 if (texture_impl->baseTexture.bindCount) {
6023 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6026 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6029 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6030 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6032 checkGLcall("attach_surface_fbo");
6035 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6037 IWineD3DSwapChain *swapchain;
6039 swapchain = get_swapchain(surface);
6040 if (swapchain) {
6041 GLenum buffer;
6043 TRACE("Surface %p is onscreen\n", surface);
6045 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6046 buffer = surface_get_gl_buffer(surface, swapchain);
6047 glDrawBuffer(buffer);
6048 checkGLcall("glDrawBuffer()");
6049 } else {
6050 TRACE("Surface %p is offscreen\n", surface);
6051 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
6052 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6055 if (rect) {
6056 glEnable(GL_SCISSOR_TEST);
6057 if(!swapchain) {
6058 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6059 } else {
6060 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6061 rect->x2 - rect->x1, rect->y2 - rect->y1);
6063 checkGLcall("glScissor");
6064 } else {
6065 glDisable(GL_SCISSOR_TEST);
6067 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6069 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6070 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6072 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6073 glClear(GL_COLOR_BUFFER_BIT);
6074 checkGLcall("glClear");
6076 if (This->render_offscreen) {
6077 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6078 } else {
6079 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6080 checkGLcall("glBindFramebuffer()");
6083 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6084 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6085 glDrawBuffer(GL_BACK);
6086 checkGLcall("glDrawBuffer()");
6090 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6091 unsigned int r, g, b, a;
6092 DWORD ret;
6094 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6095 destfmt == WINED3DFMT_R8G8B8)
6096 return color;
6098 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6100 a = (color & 0xff000000) >> 24;
6101 r = (color & 0x00ff0000) >> 16;
6102 g = (color & 0x0000ff00) >> 8;
6103 b = (color & 0x000000ff) >> 0;
6105 switch(destfmt)
6107 case WINED3DFMT_R5G6B5:
6108 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6109 r = (r * 32) / 256;
6110 g = (g * 64) / 256;
6111 b = (b * 32) / 256;
6112 ret = r << 11;
6113 ret |= g << 5;
6114 ret |= b;
6115 TRACE("Returning %08x\n", ret);
6116 return ret;
6118 case WINED3DFMT_X1R5G5B5:
6119 case WINED3DFMT_A1R5G5B5:
6120 a = (a * 2) / 256;
6121 r = (r * 32) / 256;
6122 g = (g * 32) / 256;
6123 b = (b * 32) / 256;
6124 ret = a << 15;
6125 ret |= r << 10;
6126 ret |= g << 5;
6127 ret |= b << 0;
6128 TRACE("Returning %08x\n", ret);
6129 return ret;
6131 case WINED3DFMT_A8:
6132 TRACE("Returning %08x\n", a);
6133 return a;
6135 case WINED3DFMT_X4R4G4B4:
6136 case WINED3DFMT_A4R4G4B4:
6137 a = (a * 16) / 256;
6138 r = (r * 16) / 256;
6139 g = (g * 16) / 256;
6140 b = (b * 16) / 256;
6141 ret = a << 12;
6142 ret |= r << 8;
6143 ret |= g << 4;
6144 ret |= b << 0;
6145 TRACE("Returning %08x\n", ret);
6146 return ret;
6148 case WINED3DFMT_R3G3B2:
6149 r = (r * 8) / 256;
6150 g = (g * 8) / 256;
6151 b = (b * 4) / 256;
6152 ret = r << 5;
6153 ret |= g << 2;
6154 ret |= b << 0;
6155 TRACE("Returning %08x\n", ret);
6156 return ret;
6158 case WINED3DFMT_X8B8G8R8:
6159 case WINED3DFMT_A8B8G8R8:
6160 ret = a << 24;
6161 ret |= b << 16;
6162 ret |= g << 8;
6163 ret |= r << 0;
6164 TRACE("Returning %08x\n", ret);
6165 return ret;
6167 case WINED3DFMT_A2R10G10B10:
6168 a = (a * 4) / 256;
6169 r = (r * 1024) / 256;
6170 g = (g * 1024) / 256;
6171 b = (b * 1024) / 256;
6172 ret = a << 30;
6173 ret |= r << 20;
6174 ret |= g << 10;
6175 ret |= b << 0;
6176 TRACE("Returning %08x\n", ret);
6177 return ret;
6179 case WINED3DFMT_A2B10G10R10:
6180 a = (a * 4) / 256;
6181 r = (r * 1024) / 256;
6182 g = (g * 1024) / 256;
6183 b = (b * 1024) / 256;
6184 ret = a << 30;
6185 ret |= b << 20;
6186 ret |= g << 10;
6187 ret |= r << 0;
6188 TRACE("Returning %08x\n", ret);
6189 return ret;
6191 default:
6192 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6193 return 0;
6197 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6199 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6200 WINEDDBLTFX BltFx;
6201 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6203 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6204 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6205 return WINED3DERR_INVALIDCALL;
6208 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6209 color_fill_fbo(iface, pSurface, pRect, color);
6210 return WINED3D_OK;
6211 } else {
6212 /* Just forward this to the DirectDraw blitting engine */
6213 memset(&BltFx, 0, sizeof(BltFx));
6214 BltFx.dwSize = sizeof(BltFx);
6215 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6216 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6220 /* rendertarget and depth stencil functions */
6221 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6224 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6225 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6226 return WINED3DERR_INVALIDCALL;
6229 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6230 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6231 /* Note inc ref on returned surface */
6232 if(*ppRenderTarget != NULL)
6233 IWineD3DSurface_AddRef(*ppRenderTarget);
6234 return WINED3D_OK;
6237 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6238 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6239 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6240 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6241 IWineD3DSwapChainImpl *Swapchain;
6242 HRESULT hr;
6244 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6246 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6247 if(hr != WINED3D_OK) {
6248 ERR("Can't get the swapchain\n");
6249 return hr;
6252 /* Make sure to release the swapchain */
6253 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6255 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6256 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6257 return WINED3DERR_INVALIDCALL;
6259 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6260 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6261 return WINED3DERR_INVALIDCALL;
6264 if(Swapchain->frontBuffer != Front) {
6265 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6267 if(Swapchain->frontBuffer)
6268 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6269 Swapchain->frontBuffer = Front;
6271 if(Swapchain->frontBuffer) {
6272 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6276 if(Back && !Swapchain->backBuffer) {
6277 /* We need memory for the back buffer array - only one back buffer this way */
6278 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6279 if(!Swapchain->backBuffer) {
6280 ERR("Out of memory\n");
6281 return E_OUTOFMEMORY;
6285 if(Swapchain->backBuffer[0] != Back) {
6286 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6288 /* What to do about the context here in the case of multithreading? Not sure.
6289 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6291 ENTER_GL();
6292 if(!Swapchain->backBuffer[0]) {
6293 /* GL was told to draw to the front buffer at creation,
6294 * undo that
6296 glDrawBuffer(GL_BACK);
6297 checkGLcall("glDrawBuffer(GL_BACK)");
6298 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6299 Swapchain->presentParms.BackBufferCount = 1;
6300 } else if (!Back) {
6301 /* That makes problems - disable for now */
6302 /* glDrawBuffer(GL_FRONT); */
6303 checkGLcall("glDrawBuffer(GL_FRONT)");
6304 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6305 Swapchain->presentParms.BackBufferCount = 0;
6307 LEAVE_GL();
6309 if(Swapchain->backBuffer[0])
6310 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6311 Swapchain->backBuffer[0] = Back;
6313 if(Swapchain->backBuffer[0]) {
6314 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6315 } else {
6316 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6317 Swapchain->backBuffer = NULL;
6322 return WINED3D_OK;
6325 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6327 *ppZStencilSurface = This->stencilBufferTarget;
6328 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6330 if(*ppZStencilSurface != NULL) {
6331 /* Note inc ref on returned surface */
6332 IWineD3DSurface_AddRef(*ppZStencilSurface);
6333 return WINED3D_OK;
6334 } else {
6335 return WINED3DERR_NOTFOUND;
6339 /* TODO: Handle stencil attachments */
6340 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6341 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6342 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6344 TRACE("Set depth stencil to %p\n", depth_stencil);
6346 if (depth_stencil_impl) {
6347 if (depth_stencil_impl->current_renderbuffer) {
6348 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6349 checkGLcall("glFramebufferRenderbufferEXT()");
6350 } else {
6351 IWineD3DBaseTextureImpl *texture_impl;
6352 GLenum texttarget, target;
6353 GLint old_binding = 0;
6355 texttarget = depth_stencil_impl->glDescription.target;
6356 if(texttarget == GL_TEXTURE_2D) {
6357 target = GL_TEXTURE_2D;
6358 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6359 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6360 target = GL_TEXTURE_RECTANGLE_ARB;
6361 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6362 } else {
6363 target = GL_TEXTURE_CUBE_MAP_ARB;
6364 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6367 IWineD3DSurface_PreLoad(depth_stencil);
6369 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6370 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6371 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6372 glBindTexture(target, old_binding);
6374 /* Update base texture states array */
6375 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6376 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6377 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6378 if (texture_impl->baseTexture.bindCount) {
6379 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6382 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6385 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6386 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6387 checkGLcall("glFramebufferTexture2DEXT()");
6389 } else {
6390 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6391 checkGLcall("glFramebufferTexture2DEXT()");
6395 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6397 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6399 TRACE("Set render target %u to %p\n", idx, render_target);
6401 if (rtimpl) {
6402 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6403 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6404 } else {
6405 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6406 checkGLcall("glFramebufferTexture2DEXT()");
6408 This->draw_buffers[idx] = GL_NONE;
6412 static void check_fbo_status(IWineD3DDevice *iface) {
6413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6414 GLenum status;
6416 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6417 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6418 TRACE("FBO complete\n");
6419 } else {
6420 IWineD3DSurfaceImpl *attachment;
6421 int i;
6422 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6424 /* Dump the FBO attachments */
6425 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6426 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6427 if (attachment) {
6428 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6429 attachment->pow2Width, attachment->pow2Height);
6432 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6433 if (attachment) {
6434 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6435 attachment->pow2Width, attachment->pow2Height);
6440 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6442 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6443 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6445 if (!ds_impl) return FALSE;
6447 if (ds_impl->current_renderbuffer) {
6448 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6449 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6452 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6453 rt_impl->pow2Height != ds_impl->pow2Height);
6456 void apply_fbo_state(IWineD3DDevice *iface) {
6457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6458 unsigned int i;
6460 if (This->render_offscreen) {
6461 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6463 /* Apply render targets */
6464 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6465 IWineD3DSurface *render_target = This->render_targets[i];
6466 if (This->fbo_color_attachments[i] != render_target) {
6467 set_render_target_fbo(iface, i, render_target);
6468 This->fbo_color_attachments[i] = render_target;
6472 /* Apply depth targets */
6473 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6474 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6475 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6477 if (This->stencilBufferTarget) {
6478 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6480 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6481 This->fbo_depth_attachment = This->stencilBufferTarget;
6484 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6485 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6486 checkGLcall("glDrawBuffers()");
6487 } else {
6488 glDrawBuffer(This->draw_buffers[0]);
6489 checkGLcall("glDrawBuffer()");
6491 } else {
6492 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6495 check_fbo_status(iface);
6498 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6499 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6500 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6501 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6502 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6503 GLenum gl_filter;
6505 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6506 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6507 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6508 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6510 switch (filter) {
6511 case WINED3DTEXF_LINEAR:
6512 gl_filter = GL_LINEAR;
6513 break;
6515 default:
6516 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6517 case WINED3DTEXF_NONE:
6518 case WINED3DTEXF_POINT:
6519 gl_filter = GL_NEAREST;
6520 break;
6523 /* Attach src surface to src fbo */
6524 src_swapchain = get_swapchain(src_surface);
6525 if (src_swapchain) {
6526 GLenum buffer;
6528 TRACE("Source surface %p is onscreen\n", src_surface);
6529 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6530 /* Make sure the drawable is up to date. In the offscreen case
6531 * attach_surface_fbo() implicitly takes care of this. */
6532 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6534 ENTER_GL();
6535 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6536 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6537 glReadBuffer(buffer);
6538 checkGLcall("glReadBuffer()");
6540 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6541 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6542 } else {
6543 TRACE("Source surface %p is offscreen\n", src_surface);
6544 ENTER_GL();
6545 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6546 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6547 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6548 checkGLcall("glReadBuffer()");
6550 LEAVE_GL();
6552 /* Attach dst surface to dst fbo */
6553 dst_swapchain = get_swapchain(dst_surface);
6554 if (dst_swapchain) {
6555 GLenum buffer;
6557 TRACE("Destination surface %p is onscreen\n", dst_surface);
6558 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6559 /* Make sure the drawable is up to date. In the offscreen case
6560 * attach_surface_fbo() implicitly takes care of this. */
6561 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6563 ENTER_GL();
6564 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6565 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6566 glDrawBuffer(buffer);
6567 checkGLcall("glDrawBuffer()");
6569 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6570 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6571 } else {
6572 TRACE("Destination surface %p is offscreen\n", dst_surface);
6574 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6575 if(!src_swapchain) {
6576 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6579 ENTER_GL();
6580 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6581 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6582 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6583 checkGLcall("glDrawBuffer()");
6585 glDisable(GL_SCISSOR_TEST);
6586 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6588 if (flip) {
6589 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6590 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6591 checkGLcall("glBlitFramebuffer()");
6592 } else {
6593 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6594 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6595 checkGLcall("glBlitFramebuffer()");
6598 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6600 if (This->render_offscreen) {
6601 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6602 } else {
6603 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6604 checkGLcall("glBindFramebuffer()");
6607 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6608 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6609 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6610 glDrawBuffer(GL_BACK);
6611 checkGLcall("glDrawBuffer()");
6613 LEAVE_GL();
6616 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6618 WINED3DVIEWPORT viewport;
6620 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6622 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6623 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6624 This, RenderTargetIndex, GL_LIMITS(buffers));
6625 return WINED3DERR_INVALIDCALL;
6628 /* MSDN says that null disables the render target
6629 but a device must always be associated with a render target
6630 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6632 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6633 FIXME("Trying to set render target 0 to NULL\n");
6634 return WINED3DERR_INVALIDCALL;
6636 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6637 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);
6638 return WINED3DERR_INVALIDCALL;
6641 /* If we are trying to set what we already have, don't bother */
6642 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6643 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6644 return WINED3D_OK;
6646 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6647 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6648 This->render_targets[RenderTargetIndex] = pRenderTarget;
6650 /* Render target 0 is special */
6651 if(RenderTargetIndex == 0) {
6652 /* Finally, reset the viewport as the MSDN states. */
6653 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6654 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6655 viewport.X = 0;
6656 viewport.Y = 0;
6657 viewport.MaxZ = 1.0f;
6658 viewport.MinZ = 0.0f;
6659 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6660 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6661 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6663 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6665 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6666 * ctx properly.
6667 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6668 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6670 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6672 return WINED3D_OK;
6675 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6677 HRESULT hr = WINED3D_OK;
6678 IWineD3DSurface *tmp;
6680 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6682 if (pNewZStencil == This->stencilBufferTarget) {
6683 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6684 } else {
6685 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6686 * depending on the renter target implementation being used.
6687 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6688 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6689 * stencil buffer and incur an extra memory overhead
6690 ******************************************************/
6692 tmp = This->stencilBufferTarget;
6693 This->stencilBufferTarget = pNewZStencil;
6694 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6695 /* should we be calling the parent or the wined3d surface? */
6696 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6697 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6698 hr = WINED3D_OK;
6700 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6701 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6702 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6703 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6704 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6708 return hr;
6711 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6712 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6714 /* TODO: the use of Impl is deprecated. */
6715 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6716 WINED3DLOCKED_RECT lockedRect;
6718 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6720 /* some basic validation checks */
6721 if(This->cursorTexture) {
6722 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6723 ENTER_GL();
6724 glDeleteTextures(1, &This->cursorTexture);
6725 LEAVE_GL();
6726 This->cursorTexture = 0;
6729 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6730 This->haveHardwareCursor = TRUE;
6731 else
6732 This->haveHardwareCursor = FALSE;
6734 if(pCursorBitmap) {
6735 WINED3DLOCKED_RECT rect;
6737 /* MSDN: Cursor must be A8R8G8B8 */
6738 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6739 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6740 return WINED3DERR_INVALIDCALL;
6743 /* MSDN: Cursor must be smaller than the display mode */
6744 if(pSur->currentDesc.Width > This->ddraw_width ||
6745 pSur->currentDesc.Height > This->ddraw_height) {
6746 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);
6747 return WINED3DERR_INVALIDCALL;
6750 if (!This->haveHardwareCursor) {
6751 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6753 /* Do not store the surface's pointer because the application may
6754 * release it after setting the cursor image. Windows doesn't
6755 * addref the set surface, so we can't do this either without
6756 * creating circular refcount dependencies. Copy out the gl texture
6757 * instead.
6759 This->cursorWidth = pSur->currentDesc.Width;
6760 This->cursorHeight = pSur->currentDesc.Height;
6761 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6763 const GlPixelFormatDesc *glDesc;
6764 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6765 char *mem, *bits = (char *)rect.pBits;
6766 GLint intfmt = glDesc->glInternal;
6767 GLint format = glDesc->glFormat;
6768 GLint type = glDesc->glType;
6769 INT height = This->cursorHeight;
6770 INT width = This->cursorWidth;
6771 INT bpp = tableEntry->bpp;
6772 INT i;
6774 /* Reformat the texture memory (pitch and width can be
6775 * different) */
6776 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6777 for(i = 0; i < height; i++)
6778 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6779 IWineD3DSurface_UnlockRect(pCursorBitmap);
6780 ENTER_GL();
6782 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6783 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6784 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6787 /* Make sure that a proper texture unit is selected */
6788 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6789 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6790 checkGLcall("glActiveTextureARB");
6792 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6793 /* Create a new cursor texture */
6794 glGenTextures(1, &This->cursorTexture);
6795 checkGLcall("glGenTextures");
6796 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6797 checkGLcall("glBindTexture");
6798 /* Copy the bitmap memory into the cursor texture */
6799 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6800 HeapFree(GetProcessHeap(), 0, mem);
6801 checkGLcall("glTexImage2D");
6803 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6804 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6805 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6808 LEAVE_GL();
6810 else
6812 FIXME("A cursor texture was not returned.\n");
6813 This->cursorTexture = 0;
6816 else
6818 /* Draw a hardware cursor */
6819 ICONINFO cursorInfo;
6820 HCURSOR cursor;
6821 /* Create and clear maskBits because it is not needed for
6822 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6823 * chunks. */
6824 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6825 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6826 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6827 WINED3DLOCK_NO_DIRTY_UPDATE |
6828 WINED3DLOCK_READONLY
6830 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6831 pSur->currentDesc.Height);
6833 cursorInfo.fIcon = FALSE;
6834 cursorInfo.xHotspot = XHotSpot;
6835 cursorInfo.yHotspot = YHotSpot;
6836 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6837 pSur->currentDesc.Height, 1,
6838 1, &maskBits);
6839 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6840 pSur->currentDesc.Height, 1,
6841 32, lockedRect.pBits);
6842 IWineD3DSurface_UnlockRect(pCursorBitmap);
6843 /* Create our cursor and clean up. */
6844 cursor = CreateIconIndirect(&cursorInfo);
6845 SetCursor(cursor);
6846 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6847 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6848 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6849 This->hardwareCursor = cursor;
6850 HeapFree(GetProcessHeap(), 0, maskBits);
6854 This->xHotSpot = XHotSpot;
6855 This->yHotSpot = YHotSpot;
6856 return WINED3D_OK;
6859 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6861 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6863 This->xScreenSpace = XScreenSpace;
6864 This->yScreenSpace = YScreenSpace;
6866 return;
6870 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6872 BOOL oldVisible = This->bCursorVisible;
6873 POINT pt;
6875 TRACE("(%p) : visible(%d)\n", This, bShow);
6878 * When ShowCursor is first called it should make the cursor appear at the OS's last
6879 * known cursor position. Because of this, some applications just repetitively call
6880 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6882 GetCursorPos(&pt);
6883 This->xScreenSpace = pt.x;
6884 This->yScreenSpace = pt.y;
6886 if (This->haveHardwareCursor) {
6887 This->bCursorVisible = bShow;
6888 if (bShow)
6889 SetCursor(This->hardwareCursor);
6890 else
6891 SetCursor(NULL);
6893 else
6895 if (This->cursorTexture)
6896 This->bCursorVisible = bShow;
6899 return oldVisible;
6902 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6904 IWineD3DResourceImpl *resource;
6905 TRACE("(%p) : state (%u)\n", This, This->state);
6907 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6908 switch (This->state) {
6909 case WINED3D_OK:
6910 return WINED3D_OK;
6911 case WINED3DERR_DEVICELOST:
6913 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6914 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6915 return WINED3DERR_DEVICENOTRESET;
6917 return WINED3DERR_DEVICELOST;
6919 case WINED3DERR_DRIVERINTERNALERROR:
6920 return WINED3DERR_DRIVERINTERNALERROR;
6923 /* Unknown state */
6924 return WINED3DERR_DRIVERINTERNALERROR;
6928 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6930 /** FIXME: Resource tracking needs to be done,
6931 * The closes we can do to this is set the priorities of all managed textures low
6932 * and then reset them.
6933 ***********************************************************/
6934 FIXME("(%p) : stub\n", This);
6935 return WINED3D_OK;
6938 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6939 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6941 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6942 if(surface->Flags & SFLAG_DIBSECTION) {
6943 /* Release the DC */
6944 SelectObject(surface->hDC, surface->dib.holdbitmap);
6945 DeleteDC(surface->hDC);
6946 /* Release the DIB section */
6947 DeleteObject(surface->dib.DIBsection);
6948 surface->dib.bitmap_data = NULL;
6949 surface->resource.allocatedMemory = NULL;
6950 surface->Flags &= ~SFLAG_DIBSECTION;
6952 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6953 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6954 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE)) {
6955 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6956 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6957 } else {
6958 surface->pow2Width = surface->pow2Height = 1;
6959 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6960 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6962 surface->glRect.left = 0;
6963 surface->glRect.top = 0;
6964 surface->glRect.right = surface->pow2Width;
6965 surface->glRect.bottom = surface->pow2Height;
6967 if(surface->glDescription.textureName) {
6968 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6969 ENTER_GL();
6970 glDeleteTextures(1, &surface->glDescription.textureName);
6971 LEAVE_GL();
6972 surface->glDescription.textureName = 0;
6973 surface->Flags &= ~SFLAG_CLIENT;
6975 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6976 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6977 surface->Flags |= SFLAG_NONPOW2;
6978 } else {
6979 surface->Flags &= ~SFLAG_NONPOW2;
6981 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6982 surface->resource.allocatedMemory = NULL;
6983 surface->resource.heapMemory = NULL;
6984 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6987 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6988 TRACE("Unloading resource %p\n", resource);
6989 IWineD3DResource_UnLoad(resource);
6990 IWineD3DResource_Release(resource);
6991 return S_OK;
6994 static void reset_fbo_state(IWineD3DDevice *iface) {
6995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6996 unsigned int i;
6998 ENTER_GL();
6999 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7000 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
7002 if (This->fbo) {
7003 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
7004 This->fbo = 0;
7006 if (This->src_fbo) {
7007 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
7008 This->src_fbo = 0;
7010 if (This->dst_fbo) {
7011 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
7012 This->dst_fbo = 0;
7014 checkGLcall("Tear down fbos\n");
7015 LEAVE_GL();
7017 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7018 This->fbo_color_attachments[i] = NULL;
7020 This->fbo_depth_attachment = NULL;
7023 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7024 UINT i, count;
7025 WINED3DDISPLAYMODE m;
7026 HRESULT hr;
7028 /* All Windowed modes are supported, as is leaving the current mode */
7029 if(pp->Windowed) return TRUE;
7030 if(!pp->BackBufferWidth) return TRUE;
7031 if(!pp->BackBufferHeight) return TRUE;
7033 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7034 for(i = 0; i < count; i++) {
7035 memset(&m, 0, sizeof(m));
7036 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7037 if(FAILED(hr)) {
7038 ERR("EnumAdapterModes failed\n");
7040 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7041 /* Mode found, it is supported */
7042 return TRUE;
7045 /* Mode not found -> not supported */
7046 return FALSE;
7049 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7051 IWineD3DSwapChainImpl *swapchain;
7052 HRESULT hr;
7053 BOOL DisplayModeChanged = FALSE;
7054 WINED3DDISPLAYMODE mode;
7055 IWineD3DBaseShaderImpl *shader;
7056 IWineD3DSurfaceImpl *target;
7057 UINT i;
7058 TRACE("(%p)\n", This);
7060 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7061 if(FAILED(hr)) {
7062 ERR("Failed to get the first implicit swapchain\n");
7063 return hr;
7066 if(!is_display_mode_supported(This, pPresentationParameters)) {
7067 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7068 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7069 pPresentationParameters->BackBufferHeight);
7070 return WINED3DERR_INVALIDCALL;
7073 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7074 * on an existing gl context, so there's no real need for recreation.
7076 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7078 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7080 TRACE("New params:\n");
7081 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7082 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7083 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7084 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7085 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7086 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7087 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7088 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7089 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7090 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7091 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7092 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7093 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7095 /* No special treatment of these parameters. Just store them */
7096 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7097 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7098 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7099 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7101 /* What to do about these? */
7102 if(pPresentationParameters->BackBufferCount != 0 &&
7103 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7104 ERR("Cannot change the back buffer count yet\n");
7106 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7107 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7108 ERR("Cannot change the back buffer format yet\n");
7110 if(pPresentationParameters->hDeviceWindow != NULL &&
7111 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7112 ERR("Cannot change the device window yet\n");
7114 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7115 ERR("What do do about a changed auto depth stencil parameter?\n");
7118 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7119 reset_fbo_state((IWineD3DDevice *) This);
7122 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7123 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7124 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7127 ENTER_GL();
7128 if(This->depth_blt_texture) {
7129 glDeleteTextures(1, &This->depth_blt_texture);
7130 This->depth_blt_texture = 0;
7132 This->shader_backend->shader_destroy_depth_blt(iface);
7133 This->shader_backend->shader_free_private(iface);
7135 for (i = 0; i < GL_LIMITS(textures); i++) {
7136 /* Textures are recreated below */
7137 glDeleteTextures(1, &This->dummyTextureName[i]);
7138 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7139 This->dummyTextureName[i] = 0;
7141 LEAVE_GL();
7143 while(This->numContexts) {
7144 DestroyContext(This, This->contexts[0]);
7146 This->activeContext = NULL;
7147 HeapFree(GetProcessHeap(), 0, swapchain->context);
7148 swapchain->context = NULL;
7149 swapchain->num_contexts = 0;
7151 if(pPresentationParameters->Windowed) {
7152 mode.Width = swapchain->orig_width;
7153 mode.Height = swapchain->orig_height;
7154 mode.RefreshRate = 0;
7155 mode.Format = swapchain->presentParms.BackBufferFormat;
7156 } else {
7157 mode.Width = pPresentationParameters->BackBufferWidth;
7158 mode.Height = pPresentationParameters->BackBufferHeight;
7159 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7160 mode.Format = swapchain->presentParms.BackBufferFormat;
7163 /* Should Width == 800 && Height == 0 set 800x600? */
7164 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7165 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7166 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7168 WINED3DVIEWPORT vp;
7169 int i;
7171 vp.X = 0;
7172 vp.Y = 0;
7173 vp.Width = pPresentationParameters->BackBufferWidth;
7174 vp.Height = pPresentationParameters->BackBufferHeight;
7175 vp.MinZ = 0;
7176 vp.MaxZ = 1;
7178 if(!pPresentationParameters->Windowed) {
7179 DisplayModeChanged = TRUE;
7181 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7182 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7184 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7185 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7186 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7188 if(This->auto_depth_stencil_buffer) {
7189 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7193 /* Now set the new viewport */
7194 IWineD3DDevice_SetViewport(iface, &vp);
7197 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7198 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7199 DisplayModeChanged) {
7201 IWineD3DDevice_SetFullscreen(iface, !pPresentationParameters->Windowed);
7202 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7203 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7204 } else if(!pPresentationParameters->Windowed) {
7205 DWORD style = This->style, exStyle = This->exStyle;
7206 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7207 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7208 * Reset to clear up their mess. Guild Wars also loses the device during that.
7210 This->style = 0;
7211 This->exStyle = 0;
7212 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
7213 This->style = style;
7214 This->exStyle = exStyle;
7217 /* Recreate the primary swapchain's context */
7218 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7219 if(swapchain->backBuffer) {
7220 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7221 } else {
7222 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7224 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7225 &swapchain->presentParms);
7226 swapchain->num_contexts = 1;
7227 This->activeContext = swapchain->context[0];
7228 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7230 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7231 if(FAILED(hr)) {
7232 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7234 create_dummy_textures(This);
7237 hr = This->shader_backend->shader_alloc_private(iface);
7238 if(FAILED(hr)) {
7239 ERR("Failed to recreate shader private data\n");
7240 return hr;
7243 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7244 * first use
7246 return WINED3D_OK;
7249 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7251 /** FIXME: always true at the moment **/
7252 if(!bEnableDialogs) {
7253 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7255 return WINED3D_OK;
7259 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7261 TRACE("(%p) : pParameters %p\n", This, pParameters);
7263 *pParameters = This->createParms;
7264 return WINED3D_OK;
7267 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7268 IWineD3DSwapChain *swapchain;
7269 HRESULT hrc = WINED3D_OK;
7271 TRACE("Relaying to swapchain\n");
7273 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7274 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7275 IWineD3DSwapChain_Release(swapchain);
7277 return;
7280 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7281 IWineD3DSwapChain *swapchain;
7282 HRESULT hrc = WINED3D_OK;
7284 TRACE("Relaying to swapchain\n");
7286 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7287 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7288 IWineD3DSwapChain_Release(swapchain);
7290 return;
7294 /** ********************************************************
7295 * Notification functions
7296 ** ********************************************************/
7297 /** This function must be called in the release of a resource when ref == 0,
7298 * the contents of resource must still be correct,
7299 * any handles to other resource held by the caller must be closed
7300 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7301 *****************************************************/
7302 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7305 TRACE("(%p) : Adding Resource %p\n", This, resource);
7306 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7309 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7310 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7312 TRACE("(%p) : Removing resource %p\n", This, resource);
7314 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7318 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7320 int counter;
7322 TRACE("(%p) : resource %p\n", This, resource);
7323 switch(IWineD3DResource_GetType(resource)){
7324 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7325 case WINED3DRTYPE_SURFACE: {
7326 unsigned int i;
7328 /* Cleanup any FBO attachments if d3d is enabled */
7329 if(This->d3d_initialized) {
7330 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7331 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7333 TRACE("Last active render target destroyed\n");
7334 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7335 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7336 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7337 * and the lastActiveRenderTarget member shouldn't matter
7339 if(swapchain) {
7340 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7341 TRACE("Activating primary back buffer\n");
7342 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7343 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7344 /* Single buffering environment */
7345 TRACE("Activating primary front buffer\n");
7346 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7347 } else {
7348 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7349 /* Implicit render target destroyed, that means the device is being destroyed
7350 * whatever we set here, it shouldn't matter
7352 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7354 } else {
7355 /* May happen during ddraw uninitialization */
7356 TRACE("Render target set, but swapchain does not exist!\n");
7357 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7361 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7362 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7363 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7364 set_render_target_fbo(iface, i, NULL);
7365 This->fbo_color_attachments[i] = NULL;
7368 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7369 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7370 set_depth_stencil_fbo(iface, NULL);
7371 This->fbo_depth_attachment = NULL;
7375 break;
7377 case WINED3DRTYPE_TEXTURE:
7378 case WINED3DRTYPE_CUBETEXTURE:
7379 case WINED3DRTYPE_VOLUMETEXTURE:
7380 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7381 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7382 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7383 This->stateBlock->textures[counter] = NULL;
7385 if (This->updateStateBlock != This->stateBlock ){
7386 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7387 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7388 This->updateStateBlock->textures[counter] = NULL;
7392 break;
7393 case WINED3DRTYPE_VOLUME:
7394 /* TODO: nothing really? */
7395 break;
7396 case WINED3DRTYPE_VERTEXBUFFER:
7397 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7399 int streamNumber;
7400 TRACE("Cleaning up stream pointers\n");
7402 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7403 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7404 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7406 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7407 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7408 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7409 This->updateStateBlock->streamSource[streamNumber] = 0;
7410 /* Set changed flag? */
7413 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) */
7414 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7415 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7416 This->stateBlock->streamSource[streamNumber] = 0;
7419 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7420 else { /* This shouldn't happen */
7421 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7423 #endif
7427 break;
7428 case WINED3DRTYPE_INDEXBUFFER:
7429 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7430 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7431 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7432 This->updateStateBlock->pIndexData = NULL;
7435 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7436 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7437 This->stateBlock->pIndexData = NULL;
7441 break;
7442 default:
7443 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7444 break;
7448 /* Remove the resource from the resourceStore */
7449 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7451 TRACE("Resource released\n");
7455 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7457 IWineD3DResourceImpl *resource, *cursor;
7458 HRESULT ret;
7459 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7461 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7462 TRACE("enumerating resource %p\n", resource);
7463 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7464 ret = pCallback((IWineD3DResource *) resource, pData);
7465 if(ret == S_FALSE) {
7466 TRACE("Canceling enumeration\n");
7467 break;
7470 return WINED3D_OK;
7473 /**********************************************************
7474 * IWineD3DDevice VTbl follows
7475 **********************************************************/
7477 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7479 /*** IUnknown methods ***/
7480 IWineD3DDeviceImpl_QueryInterface,
7481 IWineD3DDeviceImpl_AddRef,
7482 IWineD3DDeviceImpl_Release,
7483 /*** IWineD3DDevice methods ***/
7484 IWineD3DDeviceImpl_GetParent,
7485 /*** Creation methods**/
7486 IWineD3DDeviceImpl_CreateVertexBuffer,
7487 IWineD3DDeviceImpl_CreateIndexBuffer,
7488 IWineD3DDeviceImpl_CreateStateBlock,
7489 IWineD3DDeviceImpl_CreateSurface,
7490 IWineD3DDeviceImpl_CreateTexture,
7491 IWineD3DDeviceImpl_CreateVolumeTexture,
7492 IWineD3DDeviceImpl_CreateVolume,
7493 IWineD3DDeviceImpl_CreateCubeTexture,
7494 IWineD3DDeviceImpl_CreateQuery,
7495 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7496 IWineD3DDeviceImpl_CreateVertexDeclaration,
7497 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7498 IWineD3DDeviceImpl_CreateVertexShader,
7499 IWineD3DDeviceImpl_CreatePixelShader,
7500 IWineD3DDeviceImpl_CreatePalette,
7501 /*** Odd functions **/
7502 IWineD3DDeviceImpl_Init3D,
7503 IWineD3DDeviceImpl_Uninit3D,
7504 IWineD3DDeviceImpl_SetFullscreen,
7505 IWineD3DDeviceImpl_SetMultithreaded,
7506 IWineD3DDeviceImpl_EvictManagedResources,
7507 IWineD3DDeviceImpl_GetAvailableTextureMem,
7508 IWineD3DDeviceImpl_GetBackBuffer,
7509 IWineD3DDeviceImpl_GetCreationParameters,
7510 IWineD3DDeviceImpl_GetDeviceCaps,
7511 IWineD3DDeviceImpl_GetDirect3D,
7512 IWineD3DDeviceImpl_GetDisplayMode,
7513 IWineD3DDeviceImpl_SetDisplayMode,
7514 IWineD3DDeviceImpl_GetHWND,
7515 IWineD3DDeviceImpl_SetHWND,
7516 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7517 IWineD3DDeviceImpl_GetRasterStatus,
7518 IWineD3DDeviceImpl_GetSwapChain,
7519 IWineD3DDeviceImpl_Reset,
7520 IWineD3DDeviceImpl_SetDialogBoxMode,
7521 IWineD3DDeviceImpl_SetCursorProperties,
7522 IWineD3DDeviceImpl_SetCursorPosition,
7523 IWineD3DDeviceImpl_ShowCursor,
7524 IWineD3DDeviceImpl_TestCooperativeLevel,
7525 /*** Getters and setters **/
7526 IWineD3DDeviceImpl_SetClipPlane,
7527 IWineD3DDeviceImpl_GetClipPlane,
7528 IWineD3DDeviceImpl_SetClipStatus,
7529 IWineD3DDeviceImpl_GetClipStatus,
7530 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7531 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7532 IWineD3DDeviceImpl_SetDepthStencilSurface,
7533 IWineD3DDeviceImpl_GetDepthStencilSurface,
7534 IWineD3DDeviceImpl_SetFVF,
7535 IWineD3DDeviceImpl_GetFVF,
7536 IWineD3DDeviceImpl_SetGammaRamp,
7537 IWineD3DDeviceImpl_GetGammaRamp,
7538 IWineD3DDeviceImpl_SetIndices,
7539 IWineD3DDeviceImpl_GetIndices,
7540 IWineD3DDeviceImpl_SetBaseVertexIndex,
7541 IWineD3DDeviceImpl_GetBaseVertexIndex,
7542 IWineD3DDeviceImpl_SetLight,
7543 IWineD3DDeviceImpl_GetLight,
7544 IWineD3DDeviceImpl_SetLightEnable,
7545 IWineD3DDeviceImpl_GetLightEnable,
7546 IWineD3DDeviceImpl_SetMaterial,
7547 IWineD3DDeviceImpl_GetMaterial,
7548 IWineD3DDeviceImpl_SetNPatchMode,
7549 IWineD3DDeviceImpl_GetNPatchMode,
7550 IWineD3DDeviceImpl_SetPaletteEntries,
7551 IWineD3DDeviceImpl_GetPaletteEntries,
7552 IWineD3DDeviceImpl_SetPixelShader,
7553 IWineD3DDeviceImpl_GetPixelShader,
7554 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7555 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7556 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7557 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7558 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7559 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7560 IWineD3DDeviceImpl_SetRenderState,
7561 IWineD3DDeviceImpl_GetRenderState,
7562 IWineD3DDeviceImpl_SetRenderTarget,
7563 IWineD3DDeviceImpl_GetRenderTarget,
7564 IWineD3DDeviceImpl_SetFrontBackBuffers,
7565 IWineD3DDeviceImpl_SetSamplerState,
7566 IWineD3DDeviceImpl_GetSamplerState,
7567 IWineD3DDeviceImpl_SetScissorRect,
7568 IWineD3DDeviceImpl_GetScissorRect,
7569 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7570 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7571 IWineD3DDeviceImpl_SetStreamSource,
7572 IWineD3DDeviceImpl_GetStreamSource,
7573 IWineD3DDeviceImpl_SetStreamSourceFreq,
7574 IWineD3DDeviceImpl_GetStreamSourceFreq,
7575 IWineD3DDeviceImpl_SetTexture,
7576 IWineD3DDeviceImpl_GetTexture,
7577 IWineD3DDeviceImpl_SetTextureStageState,
7578 IWineD3DDeviceImpl_GetTextureStageState,
7579 IWineD3DDeviceImpl_SetTransform,
7580 IWineD3DDeviceImpl_GetTransform,
7581 IWineD3DDeviceImpl_SetVertexDeclaration,
7582 IWineD3DDeviceImpl_GetVertexDeclaration,
7583 IWineD3DDeviceImpl_SetVertexShader,
7584 IWineD3DDeviceImpl_GetVertexShader,
7585 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7586 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7587 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7588 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7589 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7590 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7591 IWineD3DDeviceImpl_SetViewport,
7592 IWineD3DDeviceImpl_GetViewport,
7593 IWineD3DDeviceImpl_MultiplyTransform,
7594 IWineD3DDeviceImpl_ValidateDevice,
7595 IWineD3DDeviceImpl_ProcessVertices,
7596 /*** State block ***/
7597 IWineD3DDeviceImpl_BeginStateBlock,
7598 IWineD3DDeviceImpl_EndStateBlock,
7599 /*** Scene management ***/
7600 IWineD3DDeviceImpl_BeginScene,
7601 IWineD3DDeviceImpl_EndScene,
7602 IWineD3DDeviceImpl_Present,
7603 IWineD3DDeviceImpl_Clear,
7604 /*** Drawing ***/
7605 IWineD3DDeviceImpl_DrawPrimitive,
7606 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7607 IWineD3DDeviceImpl_DrawPrimitiveUP,
7608 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7609 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7610 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7611 IWineD3DDeviceImpl_DrawRectPatch,
7612 IWineD3DDeviceImpl_DrawTriPatch,
7613 IWineD3DDeviceImpl_DeletePatch,
7614 IWineD3DDeviceImpl_ColorFill,
7615 IWineD3DDeviceImpl_UpdateTexture,
7616 IWineD3DDeviceImpl_UpdateSurface,
7617 IWineD3DDeviceImpl_GetFrontBufferData,
7618 /*** object tracking ***/
7619 IWineD3DDeviceImpl_ResourceReleased,
7620 IWineD3DDeviceImpl_EnumResources
7623 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7625 /*** IUnknown methods ***/
7626 IWineD3DDeviceImpl_QueryInterface,
7627 IWineD3DDeviceImpl_AddRef,
7628 IWineD3DDeviceImpl_Release,
7629 /*** IWineD3DDevice methods ***/
7630 IWineD3DDeviceImpl_GetParent,
7631 /*** Creation methods**/
7632 IWineD3DDeviceImpl_CreateVertexBuffer,
7633 IWineD3DDeviceImpl_CreateIndexBuffer,
7634 IWineD3DDeviceImpl_CreateStateBlock,
7635 IWineD3DDeviceImpl_CreateSurface,
7636 IWineD3DDeviceImpl_CreateTexture,
7637 IWineD3DDeviceImpl_CreateVolumeTexture,
7638 IWineD3DDeviceImpl_CreateVolume,
7639 IWineD3DDeviceImpl_CreateCubeTexture,
7640 IWineD3DDeviceImpl_CreateQuery,
7641 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7642 IWineD3DDeviceImpl_CreateVertexDeclaration,
7643 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7644 IWineD3DDeviceImpl_CreateVertexShader,
7645 IWineD3DDeviceImpl_CreatePixelShader,
7646 IWineD3DDeviceImpl_CreatePalette,
7647 /*** Odd functions **/
7648 IWineD3DDeviceImpl_Init3D,
7649 IWineD3DDeviceImpl_Uninit3D,
7650 IWineD3DDeviceImpl_SetFullscreen,
7651 IWineD3DDeviceImpl_SetMultithreaded,
7652 IWineD3DDeviceImpl_EvictManagedResources,
7653 IWineD3DDeviceImpl_GetAvailableTextureMem,
7654 IWineD3DDeviceImpl_GetBackBuffer,
7655 IWineD3DDeviceImpl_GetCreationParameters,
7656 IWineD3DDeviceImpl_GetDeviceCaps,
7657 IWineD3DDeviceImpl_GetDirect3D,
7658 IWineD3DDeviceImpl_GetDisplayMode,
7659 IWineD3DDeviceImpl_SetDisplayMode,
7660 IWineD3DDeviceImpl_GetHWND,
7661 IWineD3DDeviceImpl_SetHWND,
7662 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7663 IWineD3DDeviceImpl_GetRasterStatus,
7664 IWineD3DDeviceImpl_GetSwapChain,
7665 IWineD3DDeviceImpl_Reset,
7666 IWineD3DDeviceImpl_SetDialogBoxMode,
7667 IWineD3DDeviceImpl_SetCursorProperties,
7668 IWineD3DDeviceImpl_SetCursorPosition,
7669 IWineD3DDeviceImpl_ShowCursor,
7670 IWineD3DDeviceImpl_TestCooperativeLevel,
7671 /*** Getters and setters **/
7672 IWineD3DDeviceImpl_SetClipPlane,
7673 IWineD3DDeviceImpl_GetClipPlane,
7674 IWineD3DDeviceImpl_SetClipStatus,
7675 IWineD3DDeviceImpl_GetClipStatus,
7676 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7677 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7678 IWineD3DDeviceImpl_SetDepthStencilSurface,
7679 IWineD3DDeviceImpl_GetDepthStencilSurface,
7680 IWineD3DDeviceImpl_SetFVF,
7681 IWineD3DDeviceImpl_GetFVF,
7682 IWineD3DDeviceImpl_SetGammaRamp,
7683 IWineD3DDeviceImpl_GetGammaRamp,
7684 IWineD3DDeviceImpl_SetIndices,
7685 IWineD3DDeviceImpl_GetIndices,
7686 IWineD3DDeviceImpl_SetBaseVertexIndex,
7687 IWineD3DDeviceImpl_GetBaseVertexIndex,
7688 IWineD3DDeviceImpl_SetLight,
7689 IWineD3DDeviceImpl_GetLight,
7690 IWineD3DDeviceImpl_SetLightEnable,
7691 IWineD3DDeviceImpl_GetLightEnable,
7692 IWineD3DDeviceImpl_SetMaterial,
7693 IWineD3DDeviceImpl_GetMaterial,
7694 IWineD3DDeviceImpl_SetNPatchMode,
7695 IWineD3DDeviceImpl_GetNPatchMode,
7696 IWineD3DDeviceImpl_SetPaletteEntries,
7697 IWineD3DDeviceImpl_GetPaletteEntries,
7698 IWineD3DDeviceImpl_SetPixelShader,
7699 IWineD3DDeviceImpl_GetPixelShader,
7700 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7701 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7702 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7703 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7704 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7705 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7706 IWineD3DDeviceImpl_SetRenderState,
7707 IWineD3DDeviceImpl_GetRenderState,
7708 IWineD3DDeviceImpl_SetRenderTarget,
7709 IWineD3DDeviceImpl_GetRenderTarget,
7710 IWineD3DDeviceImpl_SetFrontBackBuffers,
7711 IWineD3DDeviceImpl_SetSamplerState,
7712 IWineD3DDeviceImpl_GetSamplerState,
7713 IWineD3DDeviceImpl_SetScissorRect,
7714 IWineD3DDeviceImpl_GetScissorRect,
7715 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7716 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7717 IWineD3DDeviceImpl_SetStreamSource,
7718 IWineD3DDeviceImpl_GetStreamSource,
7719 IWineD3DDeviceImpl_SetStreamSourceFreq,
7720 IWineD3DDeviceImpl_GetStreamSourceFreq,
7721 IWineD3DDeviceImpl_SetTexture,
7722 IWineD3DDeviceImpl_GetTexture,
7723 IWineD3DDeviceImpl_SetTextureStageState,
7724 IWineD3DDeviceImpl_GetTextureStageState,
7725 IWineD3DDeviceImpl_SetTransform,
7726 IWineD3DDeviceImpl_GetTransform,
7727 IWineD3DDeviceImpl_SetVertexDeclaration,
7728 IWineD3DDeviceImpl_GetVertexDeclaration,
7729 IWineD3DDeviceImpl_SetVertexShader,
7730 IWineD3DDeviceImpl_GetVertexShader,
7731 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7732 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7733 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7734 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7735 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7736 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7737 IWineD3DDeviceImpl_SetViewport,
7738 IWineD3DDeviceImpl_GetViewport,
7739 IWineD3DDeviceImpl_MultiplyTransform,
7740 IWineD3DDeviceImpl_ValidateDevice,
7741 IWineD3DDeviceImpl_ProcessVertices,
7742 /*** State block ***/
7743 IWineD3DDeviceImpl_BeginStateBlock,
7744 IWineD3DDeviceImpl_EndStateBlock,
7745 /*** Scene management ***/
7746 IWineD3DDeviceImpl_BeginScene,
7747 IWineD3DDeviceImpl_EndScene,
7748 IWineD3DDeviceImpl_Present,
7749 IWineD3DDeviceImpl_Clear,
7750 /*** Drawing ***/
7751 IWineD3DDeviceImpl_DrawPrimitive,
7752 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7753 IWineD3DDeviceImpl_DrawPrimitiveUP,
7754 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7755 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7756 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7757 IWineD3DDeviceImpl_DrawRectPatch,
7758 IWineD3DDeviceImpl_DrawTriPatch,
7759 IWineD3DDeviceImpl_DeletePatch,
7760 IWineD3DDeviceImpl_ColorFill,
7761 IWineD3DDeviceImpl_UpdateTexture,
7762 IWineD3DDeviceImpl_UpdateSurface,
7763 IWineD3DDeviceImpl_GetFrontBufferData,
7764 /*** object tracking ***/
7765 IWineD3DDeviceImpl_ResourceReleased,
7766 IWineD3DDeviceImpl_EnumResources
7769 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7770 WINED3DRS_ALPHABLENDENABLE ,
7771 WINED3DRS_ALPHAFUNC ,
7772 WINED3DRS_ALPHAREF ,
7773 WINED3DRS_ALPHATESTENABLE ,
7774 WINED3DRS_BLENDOP ,
7775 WINED3DRS_COLORWRITEENABLE ,
7776 WINED3DRS_DESTBLEND ,
7777 WINED3DRS_DITHERENABLE ,
7778 WINED3DRS_FILLMODE ,
7779 WINED3DRS_FOGDENSITY ,
7780 WINED3DRS_FOGEND ,
7781 WINED3DRS_FOGSTART ,
7782 WINED3DRS_LASTPIXEL ,
7783 WINED3DRS_SHADEMODE ,
7784 WINED3DRS_SRCBLEND ,
7785 WINED3DRS_STENCILENABLE ,
7786 WINED3DRS_STENCILFAIL ,
7787 WINED3DRS_STENCILFUNC ,
7788 WINED3DRS_STENCILMASK ,
7789 WINED3DRS_STENCILPASS ,
7790 WINED3DRS_STENCILREF ,
7791 WINED3DRS_STENCILWRITEMASK ,
7792 WINED3DRS_STENCILZFAIL ,
7793 WINED3DRS_TEXTUREFACTOR ,
7794 WINED3DRS_WRAP0 ,
7795 WINED3DRS_WRAP1 ,
7796 WINED3DRS_WRAP2 ,
7797 WINED3DRS_WRAP3 ,
7798 WINED3DRS_WRAP4 ,
7799 WINED3DRS_WRAP5 ,
7800 WINED3DRS_WRAP6 ,
7801 WINED3DRS_WRAP7 ,
7802 WINED3DRS_ZENABLE ,
7803 WINED3DRS_ZFUNC ,
7804 WINED3DRS_ZWRITEENABLE
7807 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7808 WINED3DTSS_ADDRESSW ,
7809 WINED3DTSS_ALPHAARG0 ,
7810 WINED3DTSS_ALPHAARG1 ,
7811 WINED3DTSS_ALPHAARG2 ,
7812 WINED3DTSS_ALPHAOP ,
7813 WINED3DTSS_BUMPENVLOFFSET ,
7814 WINED3DTSS_BUMPENVLSCALE ,
7815 WINED3DTSS_BUMPENVMAT00 ,
7816 WINED3DTSS_BUMPENVMAT01 ,
7817 WINED3DTSS_BUMPENVMAT10 ,
7818 WINED3DTSS_BUMPENVMAT11 ,
7819 WINED3DTSS_COLORARG0 ,
7820 WINED3DTSS_COLORARG1 ,
7821 WINED3DTSS_COLORARG2 ,
7822 WINED3DTSS_COLOROP ,
7823 WINED3DTSS_RESULTARG ,
7824 WINED3DTSS_TEXCOORDINDEX ,
7825 WINED3DTSS_TEXTURETRANSFORMFLAGS
7828 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7829 WINED3DSAMP_ADDRESSU ,
7830 WINED3DSAMP_ADDRESSV ,
7831 WINED3DSAMP_ADDRESSW ,
7832 WINED3DSAMP_BORDERCOLOR ,
7833 WINED3DSAMP_MAGFILTER ,
7834 WINED3DSAMP_MINFILTER ,
7835 WINED3DSAMP_MIPFILTER ,
7836 WINED3DSAMP_MIPMAPLODBIAS ,
7837 WINED3DSAMP_MAXMIPLEVEL ,
7838 WINED3DSAMP_MAXANISOTROPY ,
7839 WINED3DSAMP_SRGBTEXTURE ,
7840 WINED3DSAMP_ELEMENTINDEX
7843 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7844 WINED3DRS_AMBIENT ,
7845 WINED3DRS_AMBIENTMATERIALSOURCE ,
7846 WINED3DRS_CLIPPING ,
7847 WINED3DRS_CLIPPLANEENABLE ,
7848 WINED3DRS_COLORVERTEX ,
7849 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7850 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7851 WINED3DRS_FOGDENSITY ,
7852 WINED3DRS_FOGEND ,
7853 WINED3DRS_FOGSTART ,
7854 WINED3DRS_FOGTABLEMODE ,
7855 WINED3DRS_FOGVERTEXMODE ,
7856 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7857 WINED3DRS_LIGHTING ,
7858 WINED3DRS_LOCALVIEWER ,
7859 WINED3DRS_MULTISAMPLEANTIALIAS ,
7860 WINED3DRS_MULTISAMPLEMASK ,
7861 WINED3DRS_NORMALIZENORMALS ,
7862 WINED3DRS_PATCHEDGESTYLE ,
7863 WINED3DRS_POINTSCALE_A ,
7864 WINED3DRS_POINTSCALE_B ,
7865 WINED3DRS_POINTSCALE_C ,
7866 WINED3DRS_POINTSCALEENABLE ,
7867 WINED3DRS_POINTSIZE ,
7868 WINED3DRS_POINTSIZE_MAX ,
7869 WINED3DRS_POINTSIZE_MIN ,
7870 WINED3DRS_POINTSPRITEENABLE ,
7871 WINED3DRS_RANGEFOGENABLE ,
7872 WINED3DRS_SPECULARMATERIALSOURCE ,
7873 WINED3DRS_TWEENFACTOR ,
7874 WINED3DRS_VERTEXBLEND ,
7875 WINED3DRS_CULLMODE ,
7876 WINED3DRS_FOGCOLOR
7879 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7880 WINED3DTSS_TEXCOORDINDEX ,
7881 WINED3DTSS_TEXTURETRANSFORMFLAGS
7884 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7885 WINED3DSAMP_DMAPOFFSET
7888 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7889 DWORD rep = This->shader_backend->StateTable[state].representative;
7890 DWORD idx;
7891 BYTE shift;
7892 UINT i;
7893 WineD3DContext *context;
7895 if(!rep) return;
7896 for(i = 0; i < This->numContexts; i++) {
7897 context = This->contexts[i];
7898 if(isStateDirty(context, rep)) continue;
7900 context->dirtyArray[context->numDirtyEntries++] = rep;
7901 idx = rep >> 5;
7902 shift = rep & 0x1f;
7903 context->isStateDirty[idx] |= (1 << shift);
7907 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7908 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7909 /* The drawable size of a pbuffer render target is the current pbuffer size
7911 *width = dev->pbufferWidth;
7912 *height = dev->pbufferHeight;
7915 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7916 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7918 *width = This->pow2Width;
7919 *height = This->pow2Height;
7922 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7923 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7924 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7925 * current context's drawable, which is the size of the back buffer of the swapchain
7926 * the active context belongs to. The back buffer of the swapchain is stored as the
7927 * surface the context belongs to.
7929 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7930 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;