push 50b650a476c6f0df362ce67f063848f086de44d9
[wine/hacks.git] / dlls / wined3d / device.c
blob6358c80913e0828f22eafca9dcefbce07da63aa5
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2007 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /* helper macros */
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
66 object->ref = 1; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->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.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
105 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
108 *pp##type = NULL; \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 *pp##type = (IWineD3D##type *) object; \
112 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
113 TRACE("(%p) : Created resource %p\n", This, object); \
116 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
117 _basetexture.levels = Levels; \
118 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
119 _basetexture.LOD = 0; \
120 _basetexture.dirty = TRUE; \
121 _basetexture.is_srgb = FALSE; \
122 _basetexture.srgb_mode_change_count = 0; \
125 /**********************************************************
126 * Global variable / Constants follow
127 **********************************************************/
128 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
130 /**********************************************************
131 * IUnknown parts follows
132 **********************************************************/
134 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
138 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
139 if (IsEqualGUID(riid, &IID_IUnknown)
140 || IsEqualGUID(riid, &IID_IWineD3DBase)
141 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
142 IUnknown_AddRef(iface);
143 *ppobj = This;
144 return S_OK;
146 *ppobj = NULL;
147 return E_NOINTERFACE;
150 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
152 ULONG refCount = InterlockedIncrement(&This->ref);
154 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
155 return refCount;
158 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
160 ULONG refCount = InterlockedDecrement(&This->ref);
162 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
164 if (!refCount) {
165 if (This->fbo) {
166 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
168 if (This->src_fbo) {
169 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
171 if (This->dst_fbo) {
172 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
175 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
177 /* TODO: Clean up all the surfaces and textures! */
178 /* NOTE: You must release the parent if the object was created via a callback
179 ** ***************************/
181 if (This->resources != NULL ) {
182 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
183 dumpResources(This->resources);
186 if(This->contexts) ERR("Context array not freed!\n");
187 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
188 This->haveHardwareCursor = FALSE;
190 IWineD3D_Release(This->wineD3D);
191 This->wineD3D = NULL;
192 HeapFree(GetProcessHeap(), 0, This);
193 TRACE("Freed device %p\n", This);
194 This = NULL;
196 return refCount;
199 /**********************************************************
200 * IWineD3DDevice implementation follows
201 **********************************************************/
202 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
204 *pParent = This->parent;
205 IUnknown_AddRef(This->parent);
206 return WINED3D_OK;
209 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
210 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
211 GLenum error, glUsage;
212 DWORD vboUsage = object->resource.usage;
213 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
214 WARN("Creating a vbo failed once, not trying again\n");
215 return;
218 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
220 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
221 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
222 ENTER_GL();
224 /* Make sure that the gl error is cleared. Do not use checkGLcall
225 * here because checkGLcall just prints a fixme and continues. However,
226 * if an error during VBO creation occurs we can fall back to non-vbo operation
227 * with full functionality(but performance loss)
229 while(glGetError() != GL_NO_ERROR);
231 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
232 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
233 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
234 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
235 * to check if the rhw and color values are in the correct format.
238 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
239 error = glGetError();
240 if(object->vbo == 0 || error != GL_NO_ERROR) {
241 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
242 goto error;
245 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
246 error = glGetError();
247 if(error != GL_NO_ERROR) {
248 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
249 goto error;
252 /* Don't use static, because dx apps tend to update the buffer
253 * quite often even if they specify 0 usage. Because we always keep the local copy
254 * we never read from the vbo and can create a write only opengl buffer.
256 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
257 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
258 case WINED3DUSAGE_DYNAMIC:
259 TRACE("Gl usage = GL_STREAM_DRAW\n");
260 glUsage = GL_STREAM_DRAW_ARB;
261 break;
262 case WINED3DUSAGE_WRITEONLY:
263 default:
264 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
265 glUsage = GL_DYNAMIC_DRAW_ARB;
266 break;
269 /* Reserve memory for the buffer. The amount of data won't change
270 * so we are safe with calling glBufferData once with a NULL ptr and
271 * calling glBufferSubData on updates
273 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
274 error = glGetError();
275 if(error != GL_NO_ERROR) {
276 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
277 goto error;
280 LEAVE_GL();
282 return;
283 error:
284 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
285 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
286 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
287 object->vbo = 0;
288 object->Flags |= VBFLAG_VBOCREATEFAIL;
289 LEAVE_GL();
290 return;
293 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
294 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
295 IUnknown *parent) {
296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
297 IWineD3DVertexBufferImpl *object;
298 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
299 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
300 BOOL conv;
302 if(Size == 0) {
303 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
304 *ppVertexBuffer = NULL;
305 return WINED3DERR_INVALIDCALL;
308 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
310 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
311 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
313 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
314 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
316 object->fvf = FVF;
318 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
319 * drawStridedFast (half-life 2).
321 * Basically converting the vertices in the buffer is quite expensive, and observations
322 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
323 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
325 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
326 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
327 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
328 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
329 * dx7 apps.
330 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
331 * more. In this call we can convert dx7 buffers too.
333 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
334 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
335 (dxVersion > 7 || !conv) ) {
336 CreateVBO(object);
338 return WINED3D_OK;
341 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
342 GLenum error, glUsage;
343 TRACE("Creating VBO for Index Buffer %p\n", object);
345 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
346 * restored on the next draw
348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
350 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
351 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
352 ENTER_GL();
354 while(glGetError());
356 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
357 error = glGetError();
358 if(error != GL_NO_ERROR || object->vbo == 0) {
359 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
360 goto out;
363 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
364 error = glGetError();
365 if(error != GL_NO_ERROR) {
366 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
367 goto out;
370 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
371 * copy no readback will be needed
373 glUsage = GL_STATIC_DRAW_ARB;
374 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
375 error = glGetError();
376 if(error != GL_NO_ERROR) {
377 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
378 goto out;
380 LEAVE_GL();
381 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
382 return;
384 out:
385 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
386 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
387 LEAVE_GL();
388 object->vbo = 0;
391 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
392 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
393 HANDLE *sharedHandle, IUnknown *parent) {
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
395 IWineD3DIndexBufferImpl *object;
396 TRACE("(%p) Creating index buffer\n", This);
398 /* Allocate the storage for the device */
399 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
401 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
402 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
405 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
406 CreateIndexBufferVBO(This, object);
409 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
410 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
411 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
413 return WINED3D_OK;
416 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
419 IWineD3DStateBlockImpl *object;
420 int i, j;
421 HRESULT temp_result;
423 D3DCREATEOBJECTINSTANCE(object, StateBlock)
424 object->blockType = Type;
426 for(i = 0; i < LIGHTMAP_SIZE; i++) {
427 list_init(&object->lightMap[i]);
430 /* Special case - Used during initialization to produce a placeholder stateblock
431 so other functions called can update a state block */
432 if (Type == WINED3DSBT_INIT) {
433 /* Don't bother increasing the reference count otherwise a device will never
434 be freed due to circular dependencies */
435 return WINED3D_OK;
438 temp_result = allocate_shader_constants(object);
439 if (WINED3D_OK != temp_result)
440 return temp_result;
442 /* Otherwise, might as well set the whole state block to the appropriate values */
443 if (This->stateBlock != NULL)
444 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
445 else
446 memset(object->streamFreq, 1, sizeof(object->streamFreq));
448 /* Reset the ref and type after kludging it */
449 object->wineD3DDevice = This;
450 object->ref = 1;
451 object->blockType = Type;
453 TRACE("Updating changed flags appropriate for type %d\n", Type);
455 if (Type == WINED3DSBT_ALL) {
457 TRACE("ALL => Pretend everything has changed\n");
458 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
460 /* Lights are not part of the changed / set structure */
461 for(j = 0; j < LIGHTMAP_SIZE; j++) {
462 struct list *e;
463 LIST_FOR_EACH(e, &object->lightMap[j]) {
464 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
465 light->changed = TRUE;
466 light->enabledChanged = TRUE;
469 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
470 object->contained_render_states[j - 1] = j;
472 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
473 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
474 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
475 object->contained_transform_states[j - 1] = j;
477 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
478 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
479 object->contained_vs_consts_f[j] = j;
481 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
482 for(j = 0; j < MAX_CONST_I; j++) {
483 object->contained_vs_consts_i[j] = j;
485 object->num_contained_vs_consts_i = MAX_CONST_I;
486 for(j = 0; j < MAX_CONST_B; j++) {
487 object->contained_vs_consts_b[j] = j;
489 object->num_contained_vs_consts_b = MAX_CONST_B;
490 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
491 object->contained_ps_consts_f[j] = j;
493 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
494 for(j = 0; j < MAX_CONST_I; j++) {
495 object->contained_ps_consts_i[j] = j;
497 object->num_contained_ps_consts_i = MAX_CONST_I;
498 for(j = 0; j < MAX_CONST_B; j++) {
499 object->contained_ps_consts_b[j] = j;
501 object->num_contained_ps_consts_b = MAX_CONST_B;
502 for(i = 0; i < MAX_TEXTURES; i++) {
503 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
504 object->contained_tss_states[object->num_contained_tss_states].stage = i;
505 object->contained_tss_states[object->num_contained_tss_states].state = j;
506 object->num_contained_tss_states++;
509 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
510 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
511 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
512 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
513 object->num_contained_sampler_states++;
517 for(i = 0; i < MAX_STREAMS; i++) {
518 if(object->streamSource[i]) {
519 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
522 if(object->pIndexData) {
523 IWineD3DIndexBuffer_AddRef(object->pIndexData);
525 if(object->vertexShader) {
526 IWineD3DVertexShader_AddRef(object->vertexShader);
528 if(object->pixelShader) {
529 IWineD3DPixelShader_AddRef(object->pixelShader);
532 } else if (Type == WINED3DSBT_PIXELSTATE) {
534 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
535 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
537 object->changed.pixelShader = TRUE;
539 /* Pixel Shader Constants */
540 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
541 object->contained_ps_consts_f[i] = i;
542 object->changed.pixelShaderConstantsF[i] = TRUE;
544 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
545 for (i = 0; i < MAX_CONST_B; ++i) {
546 object->contained_ps_consts_b[i] = i;
547 object->changed.pixelShaderConstantsB[i] = TRUE;
549 object->num_contained_ps_consts_b = MAX_CONST_B;
550 for (i = 0; i < MAX_CONST_I; ++i) {
551 object->contained_ps_consts_i[i] = i;
552 object->changed.pixelShaderConstantsI[i] = TRUE;
554 object->num_contained_ps_consts_i = MAX_CONST_I;
556 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
557 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
558 object->contained_render_states[i] = SavedPixelStates_R[i];
560 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
561 for (j = 0; j < MAX_TEXTURES; j++) {
562 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
563 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
564 object->contained_tss_states[object->num_contained_tss_states].stage = j;
565 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
566 object->num_contained_tss_states++;
569 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
570 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
571 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
572 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
573 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
574 object->num_contained_sampler_states++;
577 if(object->pixelShader) {
578 IWineD3DPixelShader_AddRef(object->pixelShader);
581 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
582 * on them. This makes releasing the buffer easier
584 for(i = 0; i < MAX_STREAMS; i++) {
585 object->streamSource[i] = NULL;
587 object->pIndexData = NULL;
588 object->vertexShader = NULL;
590 } else if (Type == WINED3DSBT_VERTEXSTATE) {
592 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
593 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
595 object->changed.vertexShader = TRUE;
597 /* Vertex Shader Constants */
598 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
599 object->changed.vertexShaderConstantsF[i] = TRUE;
600 object->contained_vs_consts_f[i] = i;
602 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
603 for (i = 0; i < MAX_CONST_B; ++i) {
604 object->changed.vertexShaderConstantsB[i] = TRUE;
605 object->contained_vs_consts_b[i] = i;
607 object->num_contained_vs_consts_b = MAX_CONST_B;
608 for (i = 0; i < MAX_CONST_I; ++i) {
609 object->changed.vertexShaderConstantsI[i] = TRUE;
610 object->contained_vs_consts_i[i] = i;
612 object->num_contained_vs_consts_i = MAX_CONST_I;
613 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
614 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
615 object->contained_render_states[i] = SavedVertexStates_R[i];
617 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
618 for (j = 0; j < MAX_TEXTURES; j++) {
619 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
620 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
621 object->contained_tss_states[object->num_contained_tss_states].stage = j;
622 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
623 object->num_contained_tss_states++;
626 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
627 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
628 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
629 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
630 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
631 object->num_contained_sampler_states++;
635 for(j = 0; j < LIGHTMAP_SIZE; j++) {
636 struct list *e;
637 LIST_FOR_EACH(e, &object->lightMap[j]) {
638 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
639 light->changed = TRUE;
640 light->enabledChanged = TRUE;
644 for(i = 0; i < MAX_STREAMS; i++) {
645 if(object->streamSource[i]) {
646 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
649 if(object->vertexShader) {
650 IWineD3DVertexShader_AddRef(object->vertexShader);
652 object->pIndexData = NULL;
653 object->pixelShader = NULL;
654 } else {
655 FIXME("Unrecognized state block type %d\n", Type);
658 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
659 return WINED3D_OK;
662 /* ************************************
663 MSDN:
664 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
666 Discard
667 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
669 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.
671 ******************************** */
673 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) {
674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
675 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
676 unsigned int Size = 1;
677 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
678 TRACE("(%p) Create surface\n",This);
680 /** FIXME: Check ranges on the inputs are valid
681 * MSDN
682 * MultisampleQuality
683 * [in] Quality level. The valid range is between zero and one less than the level
684 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
685 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
686 * values of paired render targets, depth stencil surfaces, and the MultiSample type
687 * must all match.
688 *******************************/
692 * TODO: Discard MSDN
693 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
695 * If this flag is set, the contents of the depth stencil buffer will be
696 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
697 * with a different depth surface.
699 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
700 ***************************/
702 if(MultisampleQuality < 0) {
703 FIXME("Invalid multisample level %d\n", MultisampleQuality);
704 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
707 if(MultisampleQuality > 0) {
708 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
709 MultisampleQuality=0;
712 /** FIXME: Check that the format is supported
713 * by the device.
714 *******************************/
716 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
717 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
718 * space!
719 *********************************/
720 if (WINED3DFMT_UNKNOWN == Format) {
721 Size = 0;
722 } else if (Format == WINED3DFMT_DXT1) {
723 /* DXT1 is half byte per pixel */
724 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
726 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
727 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
728 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
729 } else {
730 /* The pitch is a multiple of 4 bytes */
731 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
732 Size *= Height;
735 /** Create and initialise the surface resource **/
736 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
737 /* "Standalone" surface */
738 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
740 object->currentDesc.Width = Width;
741 object->currentDesc.Height = Height;
742 object->currentDesc.MultiSampleType = MultiSample;
743 object->currentDesc.MultiSampleQuality = MultisampleQuality;
744 object->glDescription.level = Level;
746 /* Flags */
747 object->Flags = 0;
748 object->Flags |= Discard ? SFLAG_DISCARD : 0;
749 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
750 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
753 if (WINED3DFMT_UNKNOWN != Format) {
754 object->bytesPerPixel = tableEntry->bpp;
755 } else {
756 object->bytesPerPixel = 0;
759 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
761 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
763 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
764 * this function is too deep to need to care about things like this.
765 * Levels need to be checked too, and possibly Type since they all affect what can be done.
766 * ****************************************/
767 switch(Pool) {
768 case WINED3DPOOL_SCRATCH:
769 if(!Lockable)
770 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
771 "which are mutually exclusive, setting lockable to TRUE\n");
772 Lockable = TRUE;
773 break;
774 case WINED3DPOOL_SYSTEMMEM:
775 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
776 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
777 case WINED3DPOOL_MANAGED:
778 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
779 "Usage of DYNAMIC which are mutually exclusive, not doing "
780 "anything just telling you.\n");
781 break;
782 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
783 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
784 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
785 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
786 break;
787 default:
788 FIXME("(%p) Unknown pool %d\n", This, Pool);
789 break;
792 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
793 FIXME("Trying to create a render target that isn't in the default pool\n");
796 /* mark the texture as dirty so that it gets loaded first time around*/
797 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
798 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
799 This, Width, Height, Format, debug_d3dformat(Format),
800 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
802 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
803 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
804 This->ddraw_primary = (IWineD3DSurface *) object;
806 /* Look at the implementation and set the correct Vtable */
807 switch(Impl) {
808 case SURFACE_OPENGL:
809 /* Check if a 3D adapter is available when creating gl surfaces */
810 if(!This->adapter) {
811 ERR("OpenGL surfaces are not available without opengl\n");
812 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
813 HeapFree(GetProcessHeap(), 0, object);
814 return WINED3DERR_NOTAVAILABLE;
816 break;
818 case SURFACE_GDI:
819 object->lpVtbl = &IWineGDISurface_Vtbl;
820 break;
822 default:
823 /* To be sure to catch this */
824 ERR("Unknown requested surface implementation %d!\n", Impl);
825 IWineD3DSurface_Release((IWineD3DSurface *) object);
826 return WINED3DERR_INVALIDCALL;
829 list_init(&object->renderbuffers);
831 /* Call the private setup routine */
832 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
836 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
837 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
838 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
839 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
842 IWineD3DTextureImpl *object;
843 unsigned int i;
844 UINT tmpW;
845 UINT tmpH;
846 HRESULT hr;
847 unsigned int pow2Width;
848 unsigned int pow2Height;
849 const GlPixelFormatDesc *glDesc;
850 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
853 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
854 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
855 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
857 /* TODO: It should only be possible to create textures for formats
858 that are reported as supported */
859 if (WINED3DFMT_UNKNOWN >= Format) {
860 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
861 return WINED3DERR_INVALIDCALL;
864 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
865 D3DINITIALIZEBASETEXTURE(object->baseTexture);
866 object->width = Width;
867 object->height = Height;
869 /** Non-power2 support **/
870 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
871 pow2Width = Width;
872 pow2Height = Height;
873 } else {
874 /* Find the nearest pow2 match */
875 pow2Width = pow2Height = 1;
876 while (pow2Width < Width) pow2Width <<= 1;
877 while (pow2Height < Height) pow2Height <<= 1;
880 /** FIXME: add support for real non-power-two if it's provided by the video card **/
881 /* Precalculated scaling for 'faked' non power of two texture coords */
882 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
883 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
884 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
886 /* Calculate levels for mip mapping */
887 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
888 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
889 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
890 return WINED3DERR_INVALIDCALL;
892 if(Levels > 1) {
893 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
894 return WINED3DERR_INVALIDCALL;
896 object->baseTexture.levels = 1;
897 } else if (Levels == 0) {
898 TRACE("calculating levels %d\n", object->baseTexture.levels);
899 object->baseTexture.levels++;
900 tmpW = Width;
901 tmpH = Height;
902 while (tmpW > 1 || tmpH > 1) {
903 tmpW = max(1, tmpW >> 1);
904 tmpH = max(1, tmpH >> 1);
905 object->baseTexture.levels++;
907 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
910 /* Generate all the surfaces */
911 tmpW = Width;
912 tmpH = Height;
913 for (i = 0; i < object->baseTexture.levels; i++)
915 /* use the callback to create the texture surface */
916 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
917 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
918 FIXME("Failed to create surface %p\n", object);
919 /* clean up */
920 object->surfaces[i] = NULL;
921 IWineD3DTexture_Release((IWineD3DTexture *)object);
923 *ppTexture = NULL;
924 return hr;
927 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
928 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
929 /* calculate the next mipmap level */
930 tmpW = max(1, tmpW >> 1);
931 tmpH = max(1, tmpH >> 1);
933 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
935 TRACE("(%p) : Created texture %p\n", This, object);
936 return WINED3D_OK;
939 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
940 UINT Width, UINT Height, UINT Depth,
941 UINT Levels, DWORD Usage,
942 WINED3DFORMAT Format, WINED3DPOOL Pool,
943 IWineD3DVolumeTexture **ppVolumeTexture,
944 HANDLE *pSharedHandle, IUnknown *parent,
945 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
948 IWineD3DVolumeTextureImpl *object;
949 unsigned int i;
950 UINT tmpW;
951 UINT tmpH;
952 UINT tmpD;
953 const GlPixelFormatDesc *glDesc;
954 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
956 /* TODO: It should only be possible to create textures for formats
957 that are reported as supported */
958 if (WINED3DFMT_UNKNOWN >= Format) {
959 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
960 return WINED3DERR_INVALIDCALL;
963 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
964 D3DINITIALIZEBASETEXTURE(object->baseTexture);
966 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
967 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
969 object->width = Width;
970 object->height = Height;
971 object->depth = Depth;
973 /* Calculate levels for mip mapping */
974 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
975 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
976 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
977 return WINED3DERR_INVALIDCALL;
979 if(Levels > 1) {
980 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
981 return WINED3DERR_INVALIDCALL;
983 Levels = 1;
984 } else if (Levels == 0) {
985 object->baseTexture.levels++;
986 tmpW = Width;
987 tmpH = Height;
988 tmpD = Depth;
989 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
990 tmpW = max(1, tmpW >> 1);
991 tmpH = max(1, tmpH >> 1);
992 tmpD = max(1, tmpD >> 1);
993 object->baseTexture.levels++;
995 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
998 /* Generate all the surfaces */
999 tmpW = Width;
1000 tmpH = Height;
1001 tmpD = Depth;
1003 for (i = 0; i < object->baseTexture.levels; i++)
1005 HRESULT hr;
1006 /* Create the volume */
1007 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
1008 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1010 if(FAILED(hr)) {
1011 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1012 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1013 *ppVolumeTexture = NULL;
1014 return hr;
1017 /* Set its container to this object */
1018 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1020 /* calcualte the next mipmap level */
1021 tmpW = max(1, tmpW >> 1);
1022 tmpH = max(1, tmpH >> 1);
1023 tmpD = max(1, tmpD >> 1);
1025 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1027 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1028 TRACE("(%p) : Created volume texture %p\n", This, object);
1029 return WINED3D_OK;
1032 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1033 UINT Width, UINT Height, UINT Depth,
1034 DWORD Usage,
1035 WINED3DFORMAT Format, WINED3DPOOL Pool,
1036 IWineD3DVolume** ppVolume,
1037 HANDLE* pSharedHandle, IUnknown *parent) {
1039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1040 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1041 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1043 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1045 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1046 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1048 object->currentDesc.Width = Width;
1049 object->currentDesc.Height = Height;
1050 object->currentDesc.Depth = Depth;
1051 object->bytesPerPixel = formatDesc->bpp;
1053 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1054 object->lockable = TRUE;
1055 object->locked = FALSE;
1056 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1057 object->dirty = TRUE;
1059 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1062 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1063 UINT Levels, DWORD Usage,
1064 WINED3DFORMAT Format, WINED3DPOOL Pool,
1065 IWineD3DCubeTexture **ppCubeTexture,
1066 HANDLE *pSharedHandle, IUnknown *parent,
1067 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1070 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1071 unsigned int i, j;
1072 UINT tmpW;
1073 HRESULT hr;
1074 unsigned int pow2EdgeLength = EdgeLength;
1075 const GlPixelFormatDesc *glDesc;
1076 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1078 /* TODO: It should only be possible to create textures for formats
1079 that are reported as supported */
1080 if (WINED3DFMT_UNKNOWN >= Format) {
1081 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1082 return WINED3DERR_INVALIDCALL;
1085 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1086 WARN("(%p) : Tried to create not supported cube texture\n", This);
1087 return WINED3DERR_INVALIDCALL;
1090 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1091 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1093 TRACE("(%p) Create Cube Texture\n", This);
1095 /** Non-power2 support **/
1097 /* Find the nearest pow2 match */
1098 pow2EdgeLength = 1;
1099 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1101 object->edgeLength = EdgeLength;
1102 /* TODO: support for native non-power 2 */
1103 /* Precalculated scaling for 'faked' non power of two texture coords */
1104 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1106 /* Calculate levels for mip mapping */
1107 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1108 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1109 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1110 HeapFree(GetProcessHeap(), 0, object);
1111 *ppCubeTexture = NULL;
1113 return WINED3DERR_INVALIDCALL;
1115 if(Levels > 1) {
1116 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1117 HeapFree(GetProcessHeap(), 0, object);
1118 *ppCubeTexture = NULL;
1120 return WINED3DERR_INVALIDCALL;
1122 Levels = 1;
1123 } else if (Levels == 0) {
1124 object->baseTexture.levels++;
1125 tmpW = EdgeLength;
1126 while (tmpW > 1) {
1127 tmpW = max(1, tmpW >> 1);
1128 object->baseTexture.levels++;
1130 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1133 /* Generate all the surfaces */
1134 tmpW = EdgeLength;
1135 for (i = 0; i < object->baseTexture.levels; i++) {
1137 /* Create the 6 faces */
1138 for (j = 0; j < 6; j++) {
1140 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1141 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1143 if(hr!= WINED3D_OK) {
1144 /* clean up */
1145 int k;
1146 int l;
1147 for (l = 0; l < j; l++) {
1148 IWineD3DSurface_Release(object->surfaces[l][i]);
1150 for (k = 0; k < i; k++) {
1151 for (l = 0; l < 6; l++) {
1152 IWineD3DSurface_Release(object->surfaces[l][k]);
1156 FIXME("(%p) Failed to create surface\n",object);
1157 HeapFree(GetProcessHeap(),0,object);
1158 *ppCubeTexture = NULL;
1159 return hr;
1161 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1162 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1164 tmpW = max(1, tmpW >> 1);
1166 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1168 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1169 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1170 return WINED3D_OK;
1173 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1175 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1176 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1178 /* Just a check to see if we support this type of query */
1179 switch(Type) {
1180 case WINED3DQUERYTYPE_OCCLUSION:
1181 TRACE("(%p) occlusion query\n", This);
1182 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1183 hr = WINED3D_OK;
1184 else
1185 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1186 break;
1188 case WINED3DQUERYTYPE_EVENT:
1189 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1190 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1191 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1193 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1195 hr = WINED3D_OK;
1196 break;
1198 case WINED3DQUERYTYPE_VCACHE:
1199 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1200 case WINED3DQUERYTYPE_VERTEXSTATS:
1201 case WINED3DQUERYTYPE_TIMESTAMP:
1202 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1203 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1204 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1205 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1206 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1207 case WINED3DQUERYTYPE_PIXELTIMINGS:
1208 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1209 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1210 default:
1211 FIXME("(%p) Unhandled query type %d\n", This, Type);
1213 if(NULL == ppQuery || hr != WINED3D_OK) {
1214 return hr;
1217 D3DCREATEOBJECTINSTANCE(object, Query)
1218 object->type = Type;
1219 /* allocated the 'extended' data based on the type of query requested */
1220 switch(Type){
1221 case WINED3DQUERYTYPE_OCCLUSION:
1222 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1223 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1225 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1226 TRACE("(%p) Allocating data for an occlusion query\n", This);
1227 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1228 break;
1230 case WINED3DQUERYTYPE_EVENT:
1231 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1232 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1234 if(GL_SUPPORT(APPLE_FENCE)) {
1235 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1236 checkGLcall("glGenFencesAPPLE");
1237 } else if(GL_SUPPORT(NV_FENCE)) {
1238 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1239 checkGLcall("glGenFencesNV");
1241 break;
1243 case WINED3DQUERYTYPE_VCACHE:
1244 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1245 case WINED3DQUERYTYPE_VERTEXSTATS:
1246 case WINED3DQUERYTYPE_TIMESTAMP:
1247 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1248 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1249 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1250 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1251 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1252 case WINED3DQUERYTYPE_PIXELTIMINGS:
1253 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1254 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1255 default:
1256 object->extendedData = 0;
1257 FIXME("(%p) Unhandled query type %d\n",This , Type);
1259 TRACE("(%p) : Created Query %p\n", This, object);
1260 return WINED3D_OK;
1263 /*****************************************************************************
1264 * IWineD3DDeviceImpl_SetupFullscreenWindow
1266 * Helper function that modifies a HWND's Style and ExStyle for proper
1267 * fullscreen use.
1269 * Params:
1270 * iface: Pointer to the IWineD3DDevice interface
1271 * window: Window to setup
1273 *****************************************************************************/
1274 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1277 LONG style, exStyle;
1278 /* Don't do anything if an original style is stored.
1279 * That shouldn't happen
1281 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1282 if (This->style || This->exStyle) {
1283 ERR("(%p): Want to change the window parameters of HWND %p, but "
1284 "another style is stored for restoration afterwards\n", This, window);
1287 /* Get the parameters and save them */
1288 style = GetWindowLongW(window, GWL_STYLE);
1289 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1290 This->style = style;
1291 This->exStyle = exStyle;
1293 /* Filter out window decorations */
1294 style &= ~WS_CAPTION;
1295 style &= ~WS_THICKFRAME;
1296 exStyle &= ~WS_EX_WINDOWEDGE;
1297 exStyle &= ~WS_EX_CLIENTEDGE;
1299 /* Make sure the window is managed, otherwise we won't get keyboard input */
1300 style |= WS_POPUP | WS_SYSMENU;
1302 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1303 This->style, This->exStyle, style, exStyle);
1305 SetWindowLongW(window, GWL_STYLE, style);
1306 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1308 /* Inform the window about the update. */
1309 SetWindowPos(window, HWND_TOP, 0, 0,
1310 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1311 ShowWindow(window, SW_NORMAL);
1314 /*****************************************************************************
1315 * IWineD3DDeviceImpl_RestoreWindow
1317 * Helper function that restores a windows' properties when taking it out
1318 * of fullscreen mode
1320 * Params:
1321 * iface: Pointer to the IWineD3DDevice interface
1322 * window: Window to setup
1324 *****************************************************************************/
1325 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1328 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1329 * switch, do nothing
1331 if (!This->style && !This->exStyle) return;
1333 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1334 This, window, This->style, This->exStyle);
1336 SetWindowLongW(window, GWL_STYLE, This->style);
1337 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1339 /* Delete the old values */
1340 This->style = 0;
1341 This->exStyle = 0;
1343 /* Inform the window about the update */
1344 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1345 0, 0, 0, 0, /* Pos, Size, ignored */
1346 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1349 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1350 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1351 IUnknown* parent,
1352 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1353 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1356 HDC hDc;
1357 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1358 HRESULT hr = WINED3D_OK;
1359 IUnknown *bufferParent;
1361 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1363 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1364 * does a device hold a reference to a swap chain giving them a lifetime of the device
1365 * or does the swap chain notify the device of its destruction.
1366 *******************************/
1368 /* Check the params */
1369 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1370 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1371 return WINED3DERR_INVALIDCALL;
1372 } else if (pPresentationParameters->BackBufferCount > 1) {
1373 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");
1376 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1378 /*********************
1379 * Lookup the window Handle and the relating X window handle
1380 ********************/
1382 /* Setup hwnd we are using, plus which display this equates to */
1383 object->win_handle = pPresentationParameters->hDeviceWindow;
1384 if (!object->win_handle) {
1385 object->win_handle = This->createParms.hFocusWindow;
1388 hDc = GetDC(object->win_handle);
1389 TRACE("Using hDc %p\n", hDc);
1391 if (NULL == hDc) {
1392 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1393 return WINED3DERR_NOTAVAILABLE;
1396 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1397 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1398 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1399 ReleaseDC(object->win_handle, hDc);
1401 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1402 * then the corresponding dimension of the client area of the hDeviceWindow
1403 * (or the focus window, if hDeviceWindow is NULL) is taken.
1404 **********************/
1406 if (pPresentationParameters->Windowed &&
1407 ((pPresentationParameters->BackBufferWidth == 0) ||
1408 (pPresentationParameters->BackBufferHeight == 0) ||
1409 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1411 RECT Rect;
1412 GetClientRect(object->win_handle, &Rect);
1414 if (pPresentationParameters->BackBufferWidth == 0) {
1415 pPresentationParameters->BackBufferWidth = Rect.right;
1416 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1418 if (pPresentationParameters->BackBufferHeight == 0) {
1419 pPresentationParameters->BackBufferHeight = Rect.bottom;
1420 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1422 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1423 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1424 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1428 /* Put the correct figures in the presentation parameters */
1429 TRACE("Copying across presentation parameters\n");
1430 object->presentParms = *pPresentationParameters;
1432 TRACE("calling rendertarget CB\n");
1433 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1434 parent,
1435 object->presentParms.BackBufferWidth,
1436 object->presentParms.BackBufferHeight,
1437 object->presentParms.BackBufferFormat,
1438 object->presentParms.MultiSampleType,
1439 object->presentParms.MultiSampleQuality,
1440 TRUE /* Lockable */,
1441 &object->frontBuffer,
1442 NULL /* pShared (always null)*/);
1443 if (object->frontBuffer != NULL) {
1444 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1445 } else {
1446 ERR("Failed to create the front buffer\n");
1447 goto error;
1451 * Create an opengl context for the display visual
1452 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1453 * use different properties after that point in time. FIXME: How to handle when requested format
1454 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1455 * it chooses is identical to the one already being used!
1456 **********************************/
1457 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1459 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1460 if(!object->context)
1461 return E_OUTOFMEMORY;
1462 object->num_contexts = 1;
1464 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1465 if (!object->context[0]) {
1466 ERR("Failed to create a new context\n");
1467 hr = WINED3DERR_NOTAVAILABLE;
1468 goto error;
1469 } else {
1470 TRACE("Context created (HWND=%p, glContext=%p)\n",
1471 object->win_handle, object->context[0]->glCtx);
1474 /*********************
1475 * Windowed / Fullscreen
1476 *******************/
1479 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1480 * so we should really check to see if there is a fullscreen swapchain already
1481 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1482 **************************************/
1484 if (!pPresentationParameters->Windowed) {
1486 DEVMODEW devmode;
1487 HDC hdc;
1488 int bpp = 0;
1489 RECT clip_rc;
1491 /* Get info on the current display setup */
1492 hdc = GetDC(0);
1493 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1494 ReleaseDC(0, hdc);
1496 /* Change the display settings */
1497 memset(&devmode, 0, sizeof(devmode));
1498 devmode.dmSize = sizeof(devmode);
1499 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1500 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1501 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1502 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1503 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1505 /* For GetDisplayMode */
1506 This->ddraw_width = devmode.dmPelsWidth;
1507 This->ddraw_height = devmode.dmPelsHeight;
1508 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1510 IWineD3DDevice_SetFullscreen(iface, TRUE);
1512 /* And finally clip mouse to our screen */
1513 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1514 ClipCursor(&clip_rc);
1517 /*********************
1518 * Create the back, front and stencil buffers
1519 *******************/
1520 if(object->presentParms.BackBufferCount > 0) {
1521 int i;
1523 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1524 if(!object->backBuffer) {
1525 ERR("Out of memory\n");
1526 hr = E_OUTOFMEMORY;
1527 goto error;
1530 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1531 TRACE("calling rendertarget CB\n");
1532 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1533 parent,
1534 object->presentParms.BackBufferWidth,
1535 object->presentParms.BackBufferHeight,
1536 object->presentParms.BackBufferFormat,
1537 object->presentParms.MultiSampleType,
1538 object->presentParms.MultiSampleQuality,
1539 TRUE /* Lockable */,
1540 &object->backBuffer[i],
1541 NULL /* pShared (always null)*/);
1542 if(hr == WINED3D_OK && object->backBuffer[i]) {
1543 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1544 } else {
1545 ERR("Cannot create new back buffer\n");
1546 goto error;
1548 ENTER_GL();
1549 glDrawBuffer(GL_BACK);
1550 checkGLcall("glDrawBuffer(GL_BACK)");
1551 LEAVE_GL();
1553 } else {
1554 object->backBuffer = NULL;
1556 /* Single buffering - draw to front buffer */
1557 ENTER_GL();
1558 glDrawBuffer(GL_FRONT);
1559 checkGLcall("glDrawBuffer(GL_FRONT)");
1560 LEAVE_GL();
1563 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1564 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1565 TRACE("Creating depth stencil buffer\n");
1566 if (This->depthStencilBuffer == NULL ) {
1567 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1568 parent,
1569 object->presentParms.BackBufferWidth,
1570 object->presentParms.BackBufferHeight,
1571 object->presentParms.AutoDepthStencilFormat,
1572 object->presentParms.MultiSampleType,
1573 object->presentParms.MultiSampleQuality,
1574 FALSE /* FIXME: Discard */,
1575 &This->depthStencilBuffer,
1576 NULL /* pShared (always null)*/ );
1577 if (This->depthStencilBuffer != NULL)
1578 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1581 /** TODO: A check on width, height and multisample types
1582 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1583 ****************************/
1584 object->wantsDepthStencilBuffer = TRUE;
1585 } else {
1586 object->wantsDepthStencilBuffer = FALSE;
1589 TRACE("Created swapchain %p\n", object);
1590 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1591 return WINED3D_OK;
1593 error:
1594 if (object->backBuffer) {
1595 int i;
1596 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1597 if(object->backBuffer[i]) {
1598 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1599 IUnknown_Release(bufferParent); /* once for the get parent */
1600 if (IUnknown_Release(bufferParent) > 0) {
1601 FIXME("(%p) Something's still holding the back buffer\n",This);
1605 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1606 object->backBuffer = NULL;
1608 if(object->context[0])
1609 DestroyContext(This, object->context[0]);
1610 if(object->frontBuffer) {
1611 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1612 IUnknown_Release(bufferParent); /* once for the get parent */
1613 if (IUnknown_Release(bufferParent) > 0) {
1614 FIXME("(%p) Something's still holding the front buffer\n",This);
1617 HeapFree(GetProcessHeap(), 0, object);
1618 return hr;
1621 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1622 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1624 TRACE("(%p)\n", This);
1626 return This->NumberOfSwapChains;
1629 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1631 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1633 if(iSwapChain < This->NumberOfSwapChains) {
1634 *pSwapChain = This->swapchains[iSwapChain];
1635 IWineD3DSwapChain_AddRef(*pSwapChain);
1636 TRACE("(%p) returning %p\n", This, *pSwapChain);
1637 return WINED3D_OK;
1638 } else {
1639 TRACE("Swapchain out of range\n");
1640 *pSwapChain = NULL;
1641 return WINED3DERR_INVALIDCALL;
1645 /*****
1646 * Vertex Declaration
1647 *****/
1648 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1649 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1651 IWineD3DVertexDeclarationImpl *object = NULL;
1652 HRESULT hr = WINED3D_OK;
1654 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1655 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1657 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1659 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1661 return hr;
1664 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1666 unsigned int idx, idx2;
1667 unsigned int offset;
1668 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1669 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1670 BOOL has_blend_idx = has_blend &&
1671 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1672 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1673 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1674 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1675 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1676 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1677 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1679 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1680 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1682 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1683 WINED3DVERTEXELEMENT *elements = NULL;
1685 unsigned int size;
1686 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1687 if (has_blend_idx) num_blends--;
1689 /* Compute declaration size */
1690 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1691 has_psize + has_diffuse + has_specular + num_textures + 1;
1693 /* convert the declaration */
1694 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1695 if (!elements)
1696 return 0;
1698 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1699 idx = 0;
1700 if (has_pos) {
1701 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1702 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1703 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1705 else {
1706 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1707 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1709 elements[idx].UsageIndex = 0;
1710 idx++;
1712 if (has_blend && (num_blends > 0)) {
1713 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1714 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1715 else
1716 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1717 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1718 elements[idx].UsageIndex = 0;
1719 idx++;
1721 if (has_blend_idx) {
1722 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1723 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1724 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1725 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1726 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1727 else
1728 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1729 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1730 elements[idx].UsageIndex = 0;
1731 idx++;
1733 if (has_normal) {
1734 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1735 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1736 elements[idx].UsageIndex = 0;
1737 idx++;
1739 if (has_psize) {
1740 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1741 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1742 elements[idx].UsageIndex = 0;
1743 idx++;
1745 if (has_diffuse) {
1746 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1747 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1748 elements[idx].UsageIndex = 0;
1749 idx++;
1751 if (has_specular) {
1752 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1753 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1754 elements[idx].UsageIndex = 1;
1755 idx++;
1757 for (idx2 = 0; idx2 < num_textures; idx2++) {
1758 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1759 switch (numcoords) {
1760 case WINED3DFVF_TEXTUREFORMAT1:
1761 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1762 break;
1763 case WINED3DFVF_TEXTUREFORMAT2:
1764 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1765 break;
1766 case WINED3DFVF_TEXTUREFORMAT3:
1767 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1768 break;
1769 case WINED3DFVF_TEXTUREFORMAT4:
1770 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1771 break;
1773 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1774 elements[idx].UsageIndex = idx2;
1775 idx++;
1778 /* Now compute offsets, and initialize the rest of the fields */
1779 for (idx = 0, offset = 0; idx < size-1; idx++) {
1780 elements[idx].Stream = 0;
1781 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1782 elements[idx].Offset = offset;
1783 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1786 *ppVertexElements = elements;
1787 return size;
1790 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1791 WINED3DVERTEXELEMENT* elements = NULL;
1792 size_t size;
1793 DWORD hr;
1795 size = ConvertFvfToDeclaration(Fvf, &elements);
1796 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1798 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1799 HeapFree(GetProcessHeap(), 0, elements);
1800 if (hr != S_OK) return hr;
1802 return WINED3D_OK;
1805 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1806 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1808 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1809 HRESULT hr = WINED3D_OK;
1810 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1811 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1813 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1815 if (vertex_declaration) {
1816 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1819 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1821 if (WINED3D_OK != hr) {
1822 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1823 IWineD3DVertexShader_Release(*ppVertexShader);
1824 return WINED3DERR_INVALIDCALL;
1827 return WINED3D_OK;
1830 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1832 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1833 HRESULT hr = WINED3D_OK;
1835 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1836 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1837 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1838 if (WINED3D_OK == hr) {
1839 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1840 } else {
1841 WARN("(%p) : Failed to create pixel shader\n", This);
1844 return hr;
1847 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1849 IWineD3DPaletteImpl *object;
1850 HRESULT hr;
1851 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1853 /* Create the new object */
1854 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1855 if(!object) {
1856 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1857 return E_OUTOFMEMORY;
1860 object->lpVtbl = &IWineD3DPalette_Vtbl;
1861 object->ref = 1;
1862 object->Flags = Flags;
1863 object->parent = Parent;
1864 object->wineD3DDevice = This;
1865 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1867 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1869 if(!object->hpal) {
1870 HeapFree( GetProcessHeap(), 0, object);
1871 return E_OUTOFMEMORY;
1874 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1875 if(FAILED(hr)) {
1876 IWineD3DPalette_Release((IWineD3DPalette *) object);
1877 return hr;
1880 *Palette = (IWineD3DPalette *) object;
1882 return WINED3D_OK;
1885 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1886 HBITMAP hbm;
1887 BITMAP bm;
1888 HRESULT hr;
1889 HDC dcb = NULL, dcs = NULL;
1890 WINEDDCOLORKEY colorkey;
1892 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1893 if(hbm)
1895 GetObjectA(hbm, sizeof(BITMAP), &bm);
1896 dcb = CreateCompatibleDC(NULL);
1897 if(!dcb) goto out;
1898 SelectObject(dcb, hbm);
1900 else
1902 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1903 * couldn't be loaded
1905 memset(&bm, 0, sizeof(bm));
1906 bm.bmWidth = 32;
1907 bm.bmHeight = 32;
1910 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1911 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1912 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1913 if(FAILED(hr)) {
1914 ERR("Wine logo requested, but failed to create surface\n");
1915 goto out;
1918 if(dcb) {
1919 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1920 if(FAILED(hr)) goto out;
1921 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1922 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1924 colorkey.dwColorSpaceLowValue = 0;
1925 colorkey.dwColorSpaceHighValue = 0;
1926 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1927 } else {
1928 /* Fill the surface with a white color to show that wined3d is there */
1929 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1932 out:
1933 if(dcb) {
1934 DeleteDC(dcb);
1936 if(hbm) {
1937 DeleteObject(hbm);
1939 return;
1942 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1944 IWineD3DSwapChainImpl *swapchain;
1945 HRESULT hr;
1946 DWORD state;
1948 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1949 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1951 /* TODO: Test if OpenGL is compiled in and loaded */
1953 TRACE("(%p) : Creating stateblock\n", This);
1954 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1955 hr = IWineD3DDevice_CreateStateBlock(iface,
1956 WINED3DSBT_INIT,
1957 (IWineD3DStateBlock **)&This->stateBlock,
1958 NULL);
1959 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1960 WARN("Failed to create stateblock\n");
1961 goto err_out;
1963 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1964 This->updateStateBlock = This->stateBlock;
1965 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1967 hr = allocate_shader_constants(This->updateStateBlock);
1968 if (WINED3D_OK != hr) {
1969 goto err_out;
1972 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1973 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1974 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1976 /* Initialize the texture unit mapping to a 1:1 mapping */
1977 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1978 if (state < GL_LIMITS(fragment_samplers)) {
1979 This->texUnitMap[state] = state;
1980 This->rev_tex_unit_map[state] = state;
1981 } else {
1982 This->texUnitMap[state] = -1;
1983 This->rev_tex_unit_map[state] = -1;
1987 /* Setup the implicit swapchain */
1988 TRACE("Creating implicit swapchain\n");
1989 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1990 if (FAILED(hr) || !swapchain) {
1991 WARN("Failed to create implicit swapchain\n");
1992 goto err_out;
1995 This->NumberOfSwapChains = 1;
1996 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1997 if(!This->swapchains) {
1998 ERR("Out of memory!\n");
1999 goto err_out;
2001 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2003 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
2005 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2006 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2007 This->render_targets[0] = swapchain->backBuffer[0];
2008 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2010 else {
2011 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2012 This->render_targets[0] = swapchain->frontBuffer;
2013 This->lastActiveRenderTarget = swapchain->frontBuffer;
2015 IWineD3DSurface_AddRef(This->render_targets[0]);
2016 This->activeContext = swapchain->context[0];
2017 This->lastThread = GetCurrentThreadId();
2019 /* Depth Stencil support */
2020 This->stencilBufferTarget = This->depthStencilBuffer;
2021 if (NULL != This->stencilBufferTarget) {
2022 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2025 /* Set up some starting GL setup */
2026 ENTER_GL();
2028 /* Setup all the devices defaults */
2029 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2030 #if 0
2031 IWineD3DImpl_CheckGraphicsMemory();
2032 #endif
2034 { /* Set a default viewport */
2035 WINED3DVIEWPORT vp;
2036 vp.X = 0;
2037 vp.Y = 0;
2038 vp.Width = pPresentationParameters->BackBufferWidth;
2039 vp.Height = pPresentationParameters->BackBufferHeight;
2040 vp.MinZ = 0.0f;
2041 vp.MaxZ = 1.0f;
2042 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2045 /* Initialize the current view state */
2046 This->view_ident = 1;
2047 This->contexts[0]->last_was_rhw = 0;
2048 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2049 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2051 switch(wined3d_settings.offscreen_rendering_mode) {
2052 case ORM_FBO:
2053 case ORM_PBUFFER:
2054 This->offscreenBuffer = GL_BACK;
2055 break;
2057 case ORM_BACKBUFFER:
2059 if(GL_LIMITS(aux_buffers) > 0) {
2060 TRACE("Using auxilliary buffer for offscreen rendering\n");
2061 This->offscreenBuffer = GL_AUX0;
2062 } else {
2063 TRACE("Using back buffer for offscreen rendering\n");
2064 This->offscreenBuffer = GL_BACK;
2069 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2070 LEAVE_GL();
2072 /* Clear the screen */
2073 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2074 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2075 0x00, 1.0, 0);
2077 This->d3d_initialized = TRUE;
2079 if(wined3d_settings.logo) {
2080 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2082 return WINED3D_OK;
2084 err_out:
2085 HeapFree(GetProcessHeap(), 0, This->render_targets);
2086 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2087 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2088 HeapFree(GetProcessHeap(), 0, This->swapchains);
2089 This->NumberOfSwapChains = 0;
2090 if(swapchain) {
2091 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2093 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2094 if(This->stateBlock) {
2095 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2096 This->stateBlock = NULL;
2098 return hr;
2101 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2103 int sampler;
2104 UINT i;
2105 TRACE("(%p)\n", This);
2107 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2109 /* I don't think that the interface guarants that the device is destroyed from the same thread
2110 * it was created. Thus make sure a context is active for the glDelete* calls
2112 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2114 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2116 TRACE("Deleting high order patches\n");
2117 for(i = 0; i < PATCHMAP_SIZE; i++) {
2118 struct list *e1, *e2;
2119 struct WineD3DRectPatch *patch;
2120 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2121 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2122 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2126 /* Delete the palette conversion shader if it is around */
2127 if(This->paletteConversionShader) {
2128 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2131 /* Delete the pbuffer context if there is any */
2132 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2134 /* Delete the mouse cursor texture */
2135 if(This->cursorTexture) {
2136 ENTER_GL();
2137 glDeleteTextures(1, &This->cursorTexture);
2138 LEAVE_GL();
2139 This->cursorTexture = 0;
2142 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2143 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2145 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2146 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2149 /* Release the update stateblock */
2150 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2151 if(This->updateStateBlock != This->stateBlock)
2152 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2154 This->updateStateBlock = NULL;
2156 { /* because were not doing proper internal refcounts releasing the primary state block
2157 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2158 to set this->stateBlock = NULL; first */
2159 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2160 This->stateBlock = NULL;
2162 /* Release the stateblock */
2163 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2164 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2168 /* Release the buffers (with sanity checks)*/
2169 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2170 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2171 if(This->depthStencilBuffer != This->stencilBufferTarget)
2172 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2174 This->stencilBufferTarget = NULL;
2176 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2177 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2178 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2180 TRACE("Setting rendertarget to NULL\n");
2181 This->render_targets[0] = NULL;
2183 if (This->depthStencilBuffer) {
2184 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
2185 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2187 This->depthStencilBuffer = NULL;
2190 for(i=0; i < This->NumberOfSwapChains; i++) {
2191 TRACE("Releasing the implicit swapchain %d\n", i);
2192 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2193 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2197 HeapFree(GetProcessHeap(), 0, This->swapchains);
2198 This->swapchains = NULL;
2199 This->NumberOfSwapChains = 0;
2201 HeapFree(GetProcessHeap(), 0, This->render_targets);
2202 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2203 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2204 This->render_targets = NULL;
2205 This->fbo_color_attachments = NULL;
2206 This->draw_buffers = NULL;
2209 This->d3d_initialized = FALSE;
2210 return WINED3D_OK;
2213 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2214 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2215 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2217 /* Setup the window for fullscreen mode */
2218 if(fullscreen && !This->ddraw_fullscreen) {
2219 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2220 } else if(!fullscreen && This->ddraw_fullscreen) {
2221 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2224 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2225 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2226 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2227 * separately.
2229 This->ddraw_fullscreen = fullscreen;
2232 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2233 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2234 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2236 * There is no way to deactivate thread safety once it is enabled.
2238 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2241 /*For now just store the flag(needed in case of ddraw) */
2242 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2244 return;
2247 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2248 DEVMODEW devmode;
2249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2250 LONG ret;
2251 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2252 RECT clip_rc;
2254 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2256 /* Resize the screen even without a window:
2257 * The app could have unset it with SetCooperativeLevel, but not called
2258 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2259 * but we don't have any hwnd
2262 memset(&devmode, 0, sizeof(devmode));
2263 devmode.dmSize = sizeof(devmode);
2264 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2265 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2266 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2267 devmode.dmPelsWidth = pMode->Width;
2268 devmode.dmPelsHeight = pMode->Height;
2270 devmode.dmDisplayFrequency = pMode->RefreshRate;
2271 if (pMode->RefreshRate != 0) {
2272 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2275 /* Only change the mode if necessary */
2276 if( (This->ddraw_width == pMode->Width) &&
2277 (This->ddraw_height == pMode->Height) &&
2278 (This->ddraw_format == pMode->Format) &&
2279 (pMode->RefreshRate == 0) ) {
2280 return WINED3D_OK;
2283 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2284 if (ret != DISP_CHANGE_SUCCESSFUL) {
2285 if(devmode.dmDisplayFrequency != 0) {
2286 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2287 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2288 devmode.dmDisplayFrequency = 0;
2289 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2291 if(ret != DISP_CHANGE_SUCCESSFUL) {
2292 return WINED3DERR_NOTAVAILABLE;
2296 /* Store the new values */
2297 This->ddraw_width = pMode->Width;
2298 This->ddraw_height = pMode->Height;
2299 This->ddraw_format = pMode->Format;
2301 /* Only do this with a window of course */
2302 if(This->ddraw_window)
2303 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2305 /* And finally clip mouse to our screen */
2306 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2307 ClipCursor(&clip_rc);
2309 return WINED3D_OK;
2312 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2314 *ppD3D= This->wineD3D;
2315 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2316 IWineD3D_AddRef(*ppD3D);
2317 return WINED3D_OK;
2320 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2323 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2324 (This->adapter->TextureRam/(1024*1024)),
2325 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2326 /* return simulated texture memory left */
2327 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2332 /*****
2333 * Get / Set FVF
2334 *****/
2335 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2338 /* Update the current state block */
2339 This->updateStateBlock->changed.fvf = TRUE;
2341 if(This->updateStateBlock->fvf == fvf) {
2342 TRACE("Application is setting the old fvf over, nothing to do\n");
2343 return WINED3D_OK;
2346 This->updateStateBlock->fvf = fvf;
2347 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2349 return WINED3D_OK;
2353 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2355 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2356 *pfvf = This->stateBlock->fvf;
2357 return WINED3D_OK;
2360 /*****
2361 * Get / Set Stream Source
2362 *****/
2363 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2365 IWineD3DVertexBuffer *oldSrc;
2367 if (StreamNumber >= MAX_STREAMS) {
2368 WARN("Stream out of range %d\n", StreamNumber);
2369 return WINED3DERR_INVALIDCALL;
2372 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2373 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2375 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2377 if(oldSrc == pStreamData &&
2378 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2379 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2380 TRACE("Application is setting the old values over, nothing to do\n");
2381 return WINED3D_OK;
2384 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2385 if (pStreamData) {
2386 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2387 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2390 /* Handle recording of state blocks */
2391 if (This->isRecordingState) {
2392 TRACE("Recording... not performing anything\n");
2393 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2394 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2395 return WINED3D_OK;
2398 /* Need to do a getParent and pass the reffs up */
2399 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2400 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2401 so for now, just count internally */
2402 if (pStreamData != NULL) {
2403 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2404 InterlockedIncrement(&vbImpl->bindCount);
2405 IWineD3DVertexBuffer_AddRef(pStreamData);
2407 if (oldSrc != NULL) {
2408 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2409 IWineD3DVertexBuffer_Release(oldSrc);
2412 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2414 return WINED3D_OK;
2417 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2420 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2421 This->stateBlock->streamSource[StreamNumber],
2422 This->stateBlock->streamOffset[StreamNumber],
2423 This->stateBlock->streamStride[StreamNumber]);
2425 if (StreamNumber >= MAX_STREAMS) {
2426 WARN("Stream out of range %d\n", StreamNumber);
2427 return WINED3DERR_INVALIDCALL;
2429 *pStream = This->stateBlock->streamSource[StreamNumber];
2430 *pStride = This->stateBlock->streamStride[StreamNumber];
2431 if (pOffset) {
2432 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2435 if (*pStream != NULL) {
2436 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2438 return WINED3D_OK;
2441 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2443 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2444 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2446 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2447 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2449 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2450 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2452 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2453 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2454 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2457 return WINED3D_OK;
2460 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2461 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2463 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2464 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2466 TRACE("(%p) : returning %d\n", This, *Divider);
2468 return WINED3D_OK;
2471 /*****
2472 * Get / Set & Multiply Transform
2473 *****/
2474 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2477 /* Most of this routine, comments included copied from ddraw tree initially: */
2478 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2480 /* Handle recording of state blocks */
2481 if (This->isRecordingState) {
2482 TRACE("Recording... not performing anything\n");
2483 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2484 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2485 return WINED3D_OK;
2489 * If the new matrix is the same as the current one,
2490 * we cut off any further processing. this seems to be a reasonable
2491 * optimization because as was noticed, some apps (warcraft3 for example)
2492 * tend towards setting the same matrix repeatedly for some reason.
2494 * From here on we assume that the new matrix is different, wherever it matters.
2496 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2497 TRACE("The app is setting the same matrix over again\n");
2498 return WINED3D_OK;
2499 } else {
2500 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2504 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2505 where ViewMat = Camera space, WorldMat = world space.
2507 In OpenGL, camera and world space is combined into GL_MODELVIEW
2508 matrix. The Projection matrix stay projection matrix.
2511 /* Capture the times we can just ignore the change for now */
2512 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2513 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2514 /* Handled by the state manager */
2517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2518 return WINED3D_OK;
2521 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2523 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2524 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2525 return WINED3D_OK;
2528 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2529 WINED3DMATRIX *mat = NULL;
2530 WINED3DMATRIX temp;
2532 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2533 * below means it will be recorded in a state block change, but it
2534 * works regardless where it is recorded.
2535 * If this is found to be wrong, change to StateBlock.
2537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2538 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2540 if (State < HIGHEST_TRANSFORMSTATE)
2542 mat = &This->updateStateBlock->transforms[State];
2543 } else {
2544 FIXME("Unhandled transform state!!\n");
2547 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2549 /* Apply change via set transform - will reapply to eg. lights this way */
2550 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2553 /*****
2554 * Get / Set Light
2555 *****/
2556 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2557 you can reference any indexes you want as long as that number max are enabled at any
2558 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2559 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2560 but when recording, just build a chain pretty much of commands to be replayed. */
2562 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2563 float rho;
2564 PLIGHTINFOEL *object = NULL;
2565 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2566 struct list *e;
2568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2569 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2571 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2572 * the gl driver.
2574 if(!pLight) {
2575 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2576 return WINED3DERR_INVALIDCALL;
2579 switch(pLight->Type) {
2580 case WINED3DLIGHT_POINT:
2581 case WINED3DLIGHT_SPOT:
2582 case WINED3DLIGHT_PARALLELPOINT:
2583 case WINED3DLIGHT_GLSPOT:
2584 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2585 * most wanted
2587 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2588 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2589 return WINED3DERR_INVALIDCALL;
2591 break;
2593 case WINED3DLIGHT_DIRECTIONAL:
2594 /* Ignores attenuation */
2595 break;
2597 default:
2598 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2599 return WINED3DERR_INVALIDCALL;
2602 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2603 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2604 if(object->OriginalIndex == Index) break;
2605 object = NULL;
2608 if(!object) {
2609 TRACE("Adding new light\n");
2610 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2611 if(!object) {
2612 ERR("Out of memory error when allocating a light\n");
2613 return E_OUTOFMEMORY;
2615 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2616 object->glIndex = -1;
2617 object->OriginalIndex = Index;
2618 object->changed = TRUE;
2621 /* Initialize the object */
2622 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,
2623 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2624 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2625 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2626 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2627 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2628 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2630 /* Save away the information */
2631 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2633 switch (pLight->Type) {
2634 case WINED3DLIGHT_POINT:
2635 /* Position */
2636 object->lightPosn[0] = pLight->Position.x;
2637 object->lightPosn[1] = pLight->Position.y;
2638 object->lightPosn[2] = pLight->Position.z;
2639 object->lightPosn[3] = 1.0f;
2640 object->cutoff = 180.0f;
2641 /* FIXME: Range */
2642 break;
2644 case WINED3DLIGHT_DIRECTIONAL:
2645 /* Direction */
2646 object->lightPosn[0] = -pLight->Direction.x;
2647 object->lightPosn[1] = -pLight->Direction.y;
2648 object->lightPosn[2] = -pLight->Direction.z;
2649 object->lightPosn[3] = 0.0;
2650 object->exponent = 0.0f;
2651 object->cutoff = 180.0f;
2652 break;
2654 case WINED3DLIGHT_SPOT:
2655 /* Position */
2656 object->lightPosn[0] = pLight->Position.x;
2657 object->lightPosn[1] = pLight->Position.y;
2658 object->lightPosn[2] = pLight->Position.z;
2659 object->lightPosn[3] = 1.0;
2661 /* Direction */
2662 object->lightDirn[0] = pLight->Direction.x;
2663 object->lightDirn[1] = pLight->Direction.y;
2664 object->lightDirn[2] = pLight->Direction.z;
2665 object->lightDirn[3] = 1.0;
2668 * opengl-ish and d3d-ish spot lights use too different models for the
2669 * light "intensity" as a function of the angle towards the main light direction,
2670 * so we only can approximate very roughly.
2671 * however spot lights are rather rarely used in games (if ever used at all).
2672 * furthermore if still used, probably nobody pays attention to such details.
2674 if (pLight->Falloff == 0) {
2675 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2676 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2677 * will always be 1.0 for both of them, and we don't have to care for the
2678 * rest of the rather complex calculation
2680 object->exponent = 0;
2681 } else {
2682 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2683 if (rho < 0.0001) rho = 0.0001f;
2684 object->exponent = -0.3/log(cos(rho/2));
2686 if (object->exponent > 128.0) {
2687 object->exponent = 128.0;
2689 object->cutoff = pLight->Phi*90/M_PI;
2691 /* FIXME: Range */
2692 break;
2694 default:
2695 FIXME("Unrecognized light type %d\n", pLight->Type);
2698 /* Update the live definitions if the light is currently assigned a glIndex */
2699 if (object->glIndex != -1 && !This->isRecordingState) {
2700 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2702 return WINED3D_OK;
2705 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2706 PLIGHTINFOEL *lightInfo = NULL;
2707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2708 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2709 struct list *e;
2710 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2712 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2713 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2714 if(lightInfo->OriginalIndex == Index) break;
2715 lightInfo = NULL;
2718 if (lightInfo == NULL) {
2719 TRACE("Light information requested but light not defined\n");
2720 return WINED3DERR_INVALIDCALL;
2723 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2724 return WINED3D_OK;
2727 /*****
2728 * Get / Set Light Enable
2729 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2730 *****/
2731 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2732 PLIGHTINFOEL *lightInfo = NULL;
2733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2734 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2735 struct list *e;
2736 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2738 /* Tests show true = 128...not clear why */
2739 Enable = Enable? 128: 0;
2741 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2742 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2743 if(lightInfo->OriginalIndex == Index) break;
2744 lightInfo = NULL;
2746 TRACE("Found light: %p\n", lightInfo);
2748 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2749 if (lightInfo == NULL) {
2751 TRACE("Light enabled requested but light not defined, so defining one!\n");
2752 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2754 /* Search for it again! Should be fairly quick as near head of list */
2755 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2756 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2757 if(lightInfo->OriginalIndex == Index) break;
2758 lightInfo = NULL;
2760 if (lightInfo == NULL) {
2761 FIXME("Adding default lights has failed dismally\n");
2762 return WINED3DERR_INVALIDCALL;
2766 lightInfo->enabledChanged = TRUE;
2767 if(!Enable) {
2768 if(lightInfo->glIndex != -1) {
2769 if(!This->isRecordingState) {
2770 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2773 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2774 lightInfo->glIndex = -1;
2775 } else {
2776 TRACE("Light already disabled, nothing to do\n");
2778 } else {
2779 if (lightInfo->glIndex != -1) {
2780 /* nop */
2781 TRACE("Nothing to do as light was enabled\n");
2782 } else {
2783 int i;
2784 /* Find a free gl light */
2785 for(i = 0; i < This->maxConcurrentLights; i++) {
2786 if(This->stateBlock->activeLights[i] == NULL) {
2787 This->stateBlock->activeLights[i] = lightInfo;
2788 lightInfo->glIndex = i;
2789 break;
2792 if(lightInfo->glIndex == -1) {
2793 ERR("Too many concurrently active lights\n");
2794 return WINED3DERR_INVALIDCALL;
2797 /* i == lightInfo->glIndex */
2798 if(!This->isRecordingState) {
2799 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2804 return WINED3D_OK;
2807 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2809 PLIGHTINFOEL *lightInfo = NULL;
2810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2811 struct list *e;
2812 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2813 TRACE("(%p) : for idx(%d)\n", This, Index);
2815 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2816 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2817 if(lightInfo->OriginalIndex == Index) break;
2818 lightInfo = NULL;
2821 if (lightInfo == NULL) {
2822 TRACE("Light enabled state requested but light not defined\n");
2823 return WINED3DERR_INVALIDCALL;
2825 /* true is 128 according to SetLightEnable */
2826 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2827 return WINED3D_OK;
2830 /*****
2831 * Get / Set Clip Planes
2832 *****/
2833 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2835 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2837 /* Validate Index */
2838 if (Index >= GL_LIMITS(clipplanes)) {
2839 TRACE("Application has requested clipplane this device doesn't support\n");
2840 return WINED3DERR_INVALIDCALL;
2843 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2845 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2846 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2847 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2848 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2849 TRACE("Application is setting old values over, nothing to do\n");
2850 return WINED3D_OK;
2853 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2854 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2855 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2856 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2858 /* Handle recording of state blocks */
2859 if (This->isRecordingState) {
2860 TRACE("Recording... not performing anything\n");
2861 return WINED3D_OK;
2864 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2866 return WINED3D_OK;
2869 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2871 TRACE("(%p) : for idx %d\n", This, Index);
2873 /* Validate Index */
2874 if (Index >= GL_LIMITS(clipplanes)) {
2875 TRACE("Application has requested clipplane this device doesn't support\n");
2876 return WINED3DERR_INVALIDCALL;
2879 pPlane[0] = This->stateBlock->clipplane[Index][0];
2880 pPlane[1] = This->stateBlock->clipplane[Index][1];
2881 pPlane[2] = This->stateBlock->clipplane[Index][2];
2882 pPlane[3] = This->stateBlock->clipplane[Index][3];
2883 return WINED3D_OK;
2886 /*****
2887 * Get / Set Clip Plane Status
2888 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2889 *****/
2890 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2892 FIXME("(%p) : stub\n", This);
2893 if (NULL == pClipStatus) {
2894 return WINED3DERR_INVALIDCALL;
2896 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2897 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2898 return WINED3D_OK;
2901 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2903 FIXME("(%p) : stub\n", This);
2904 if (NULL == pClipStatus) {
2905 return WINED3DERR_INVALIDCALL;
2907 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2908 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2909 return WINED3D_OK;
2912 /*****
2913 * Get / Set Material
2914 *****/
2915 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2918 This->updateStateBlock->changed.material = TRUE;
2919 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2921 /* Handle recording of state blocks */
2922 if (This->isRecordingState) {
2923 TRACE("Recording... not performing anything\n");
2924 return WINED3D_OK;
2927 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2928 return WINED3D_OK;
2931 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2933 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2934 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2935 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2936 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2937 pMaterial->Ambient.b, pMaterial->Ambient.a);
2938 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2939 pMaterial->Specular.b, pMaterial->Specular.a);
2940 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2941 pMaterial->Emissive.b, pMaterial->Emissive.a);
2942 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2944 return WINED3D_OK;
2947 /*****
2948 * Get / Set Indices
2949 *****/
2950 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2952 IWineD3DIndexBuffer *oldIdxs;
2954 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2955 oldIdxs = This->updateStateBlock->pIndexData;
2957 This->updateStateBlock->changed.indices = TRUE;
2958 This->updateStateBlock->pIndexData = pIndexData;
2960 /* Handle recording of state blocks */
2961 if (This->isRecordingState) {
2962 TRACE("Recording... not performing anything\n");
2963 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2964 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2965 return WINED3D_OK;
2968 if(oldIdxs != pIndexData) {
2969 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2970 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2971 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2973 return WINED3D_OK;
2976 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2979 *ppIndexData = This->stateBlock->pIndexData;
2981 /* up ref count on ppindexdata */
2982 if (*ppIndexData) {
2983 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2984 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2985 }else{
2986 TRACE("(%p) No index data set\n", This);
2988 TRACE("Returning %p\n", *ppIndexData);
2990 return WINED3D_OK;
2993 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2994 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2996 TRACE("(%p)->(%d)\n", This, BaseIndex);
2998 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2999 TRACE("Application is setting the old value over, nothing to do\n");
3000 return WINED3D_OK;
3003 This->updateStateBlock->baseVertexIndex = BaseIndex;
3005 if (This->isRecordingState) {
3006 TRACE("Recording... not performing anything\n");
3007 return WINED3D_OK;
3009 /* The base vertex index affects the stream sources */
3010 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3011 return WINED3D_OK;
3014 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3016 TRACE("(%p) : base_index %p\n", This, base_index);
3018 *base_index = This->stateBlock->baseVertexIndex;
3020 TRACE("Returning %u\n", *base_index);
3022 return WINED3D_OK;
3025 /*****
3026 * Get / Set Viewports
3027 *****/
3028 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3031 TRACE("(%p)\n", This);
3032 This->updateStateBlock->changed.viewport = TRUE;
3033 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3035 /* Handle recording of state blocks */
3036 if (This->isRecordingState) {
3037 TRACE("Recording... not performing anything\n");
3038 return WINED3D_OK;
3041 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3042 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3044 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3045 return WINED3D_OK;
3049 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3051 TRACE("(%p)\n", This);
3052 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3053 return WINED3D_OK;
3056 /*****
3057 * Get / Set Render States
3058 * TODO: Verify against dx9 definitions
3059 *****/
3060 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3063 DWORD oldValue = This->stateBlock->renderState[State];
3065 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3067 This->updateStateBlock->changed.renderState[State] = TRUE;
3068 This->updateStateBlock->renderState[State] = Value;
3070 /* Handle recording of state blocks */
3071 if (This->isRecordingState) {
3072 TRACE("Recording... not performing anything\n");
3073 return WINED3D_OK;
3076 /* Compared here and not before the assignment to allow proper stateblock recording */
3077 if(Value == oldValue) {
3078 TRACE("Application is setting the old value over, nothing to do\n");
3079 } else {
3080 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3083 return WINED3D_OK;
3086 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3088 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3089 *pValue = This->stateBlock->renderState[State];
3090 return WINED3D_OK;
3093 /*****
3094 * Get / Set Sampler States
3095 * TODO: Verify against dx9 definitions
3096 *****/
3098 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3100 DWORD oldValue;
3102 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3103 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3105 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3106 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3110 * SetSampler is designed to allow for more than the standard up to 8 textures
3111 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3112 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3114 * http://developer.nvidia.com/object/General_FAQ.html#t6
3116 * There are two new settings for GForce
3117 * the sampler one:
3118 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3119 * and the texture one:
3120 * GL_MAX_TEXTURE_COORDS_ARB.
3121 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3122 ******************/
3124 oldValue = This->stateBlock->samplerState[Sampler][Type];
3125 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3126 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3128 /* Handle recording of state blocks */
3129 if (This->isRecordingState) {
3130 TRACE("Recording... not performing anything\n");
3131 return WINED3D_OK;
3134 if(oldValue == Value) {
3135 TRACE("Application is setting the old value over, nothing to do\n");
3136 return WINED3D_OK;
3139 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3141 return WINED3D_OK;
3144 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3147 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3148 This, Sampler, debug_d3dsamplerstate(Type), Type);
3150 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3151 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3154 *Value = This->stateBlock->samplerState[Sampler][Type];
3155 TRACE("(%p) : Returning %#x\n", This, *Value);
3157 return WINED3D_OK;
3160 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3163 This->updateStateBlock->changed.scissorRect = TRUE;
3164 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3165 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3166 return WINED3D_OK;
3168 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3170 if(This->isRecordingState) {
3171 TRACE("Recording... not performing anything\n");
3172 return WINED3D_OK;
3175 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3177 return WINED3D_OK;
3180 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3183 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3184 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3185 return WINED3D_OK;
3188 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3190 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3192 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3194 This->updateStateBlock->vertexDecl = pDecl;
3195 This->updateStateBlock->changed.vertexDecl = TRUE;
3197 if (This->isRecordingState) {
3198 TRACE("Recording... not performing anything\n");
3199 return WINED3D_OK;
3200 } else if(pDecl == oldDecl) {
3201 /* Checked after the assignment to allow proper stateblock recording */
3202 TRACE("Application is setting the old declaration over, nothing to do\n");
3203 return WINED3D_OK;
3206 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3207 return WINED3D_OK;
3210 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3213 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3215 *ppDecl = This->stateBlock->vertexDecl;
3216 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3217 return WINED3D_OK;
3220 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3222 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3224 This->updateStateBlock->vertexShader = pShader;
3225 This->updateStateBlock->changed.vertexShader = TRUE;
3227 if (This->isRecordingState) {
3228 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3229 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3230 TRACE("Recording... not performing anything\n");
3231 return WINED3D_OK;
3232 } else if(oldShader == pShader) {
3233 /* Checked here to allow proper stateblock recording */
3234 TRACE("App is setting the old shader over, nothing to do\n");
3235 return WINED3D_OK;
3238 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3239 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3240 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3242 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3244 return WINED3D_OK;
3247 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3250 if (NULL == ppShader) {
3251 return WINED3DERR_INVALIDCALL;
3253 *ppShader = This->stateBlock->vertexShader;
3254 if( NULL != *ppShader)
3255 IWineD3DVertexShader_AddRef(*ppShader);
3257 TRACE("(%p) : returning %p\n", This, *ppShader);
3258 return WINED3D_OK;
3261 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3262 IWineD3DDevice *iface,
3263 UINT start,
3264 CONST BOOL *srcData,
3265 UINT count) {
3267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3268 int i, cnt = min(count, MAX_CONST_B - start);
3270 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3271 iface, srcData, start, count);
3273 if (srcData == NULL || cnt < 0)
3274 return WINED3DERR_INVALIDCALL;
3276 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3277 for (i = 0; i < cnt; i++)
3278 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3280 for (i = start; i < cnt + start; ++i) {
3281 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3284 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3286 return WINED3D_OK;
3289 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3290 IWineD3DDevice *iface,
3291 UINT start,
3292 BOOL *dstData,
3293 UINT count) {
3295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3296 int cnt = min(count, MAX_CONST_B - start);
3298 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3299 iface, dstData, start, count);
3301 if (dstData == NULL || cnt < 0)
3302 return WINED3DERR_INVALIDCALL;
3304 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3305 return WINED3D_OK;
3308 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3309 IWineD3DDevice *iface,
3310 UINT start,
3311 CONST int *srcData,
3312 UINT count) {
3314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3315 int i, cnt = min(count, MAX_CONST_I - start);
3317 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3318 iface, srcData, start, count);
3320 if (srcData == NULL || cnt < 0)
3321 return WINED3DERR_INVALIDCALL;
3323 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3324 for (i = 0; i < cnt; i++)
3325 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3326 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3328 for (i = start; i < cnt + start; ++i) {
3329 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3332 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3334 return WINED3D_OK;
3337 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3338 IWineD3DDevice *iface,
3339 UINT start,
3340 int *dstData,
3341 UINT count) {
3343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3344 int cnt = min(count, MAX_CONST_I - start);
3346 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3347 iface, dstData, start, count);
3349 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3350 return WINED3DERR_INVALIDCALL;
3352 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3353 return WINED3D_OK;
3356 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3357 IWineD3DDevice *iface,
3358 UINT start,
3359 CONST float *srcData,
3360 UINT count) {
3362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3363 int i;
3365 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3366 iface, srcData, start, count);
3368 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3369 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3370 return WINED3DERR_INVALIDCALL;
3372 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3373 if(TRACE_ON(d3d)) {
3374 for (i = 0; i < count; i++)
3375 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3376 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3379 for (i = start; i < count + start; ++i) {
3380 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3381 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3382 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3383 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3384 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3386 ptr->idx[ptr->count++] = i;
3387 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3391 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3393 return WINED3D_OK;
3396 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3397 IWineD3DDevice *iface,
3398 UINT start,
3399 float *dstData,
3400 UINT count) {
3402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3403 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3405 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3406 iface, dstData, start, count);
3408 if (dstData == NULL || cnt < 0)
3409 return WINED3DERR_INVALIDCALL;
3411 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3412 return WINED3D_OK;
3415 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3416 DWORD i;
3417 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3418 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3422 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3423 int i = This->rev_tex_unit_map[unit];
3424 int j = This->texUnitMap[stage];
3426 This->texUnitMap[stage] = unit;
3427 if (i != -1 && i != stage) {
3428 This->texUnitMap[i] = -1;
3431 This->rev_tex_unit_map[unit] = stage;
3432 if (j != -1 && j != unit) {
3433 This->rev_tex_unit_map[j] = -1;
3437 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3438 int i;
3440 for (i = 0; i < MAX_TEXTURES; ++i) {
3441 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3442 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3443 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3444 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3445 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3446 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3447 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3448 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3450 if (color_op == WINED3DTOP_DISABLE) {
3451 /* Not used, and disable higher stages */
3452 while (i < MAX_TEXTURES) {
3453 This->fixed_function_usage_map[i] = FALSE;
3454 ++i;
3456 break;
3459 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3460 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3461 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3462 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3463 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3464 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3465 This->fixed_function_usage_map[i] = TRUE;
3466 } else {
3467 This->fixed_function_usage_map[i] = FALSE;
3470 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3471 This->fixed_function_usage_map[i+1] = TRUE;
3476 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3477 int i, tex;
3479 device_update_fixed_function_usage_map(This);
3481 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3482 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3483 if (!This->fixed_function_usage_map[i]) continue;
3485 if (This->texUnitMap[i] != i) {
3486 device_map_stage(This, i, i);
3487 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3488 markTextureStagesDirty(This, i);
3491 return;
3494 /* Now work out the mapping */
3495 tex = 0;
3496 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3497 if (!This->fixed_function_usage_map[i]) continue;
3499 if (This->texUnitMap[i] != tex) {
3500 device_map_stage(This, i, tex);
3501 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3502 markTextureStagesDirty(This, i);
3505 ++tex;
3509 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3510 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3511 int i;
3513 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3514 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3515 device_map_stage(This, i, i);
3516 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3517 if (i < MAX_TEXTURES) {
3518 markTextureStagesDirty(This, i);
3524 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3525 int current_mapping = This->rev_tex_unit_map[unit];
3527 if (current_mapping == -1) {
3528 /* Not currently used */
3529 return TRUE;
3532 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3533 /* Used by a fragment sampler */
3535 if (!pshader_sampler_tokens) {
3536 /* No pixel shader, check fixed function */
3537 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3540 /* Pixel shader, check the shader's sampler map */
3541 return !pshader_sampler_tokens[current_mapping];
3544 /* Used by a vertex sampler */
3545 return !vshader_sampler_tokens[current_mapping];
3548 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3549 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3550 DWORD *pshader_sampler_tokens = NULL;
3551 int start = GL_LIMITS(combined_samplers) - 1;
3552 int i;
3554 if (ps) {
3555 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3557 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3558 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3559 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3562 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3563 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3564 if (vshader_sampler_tokens[i]) {
3565 if (This->texUnitMap[vsampler_idx] != -1) {
3566 /* Already mapped somewhere */
3567 continue;
3570 while (start >= 0) {
3571 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3572 device_map_stage(This, vsampler_idx, start);
3573 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3575 --start;
3576 break;
3579 --start;
3585 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3586 BOOL vs = use_vs(This);
3587 BOOL ps = use_ps(This);
3589 * Rules are:
3590 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3591 * that would be really messy and require shader recompilation
3592 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3593 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3595 if (ps) {
3596 device_map_psamplers(This);
3597 } else {
3598 device_map_fixed_function_samplers(This);
3601 if (vs) {
3602 device_map_vsamplers(This, ps);
3606 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3608 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3609 This->updateStateBlock->pixelShader = pShader;
3610 This->updateStateBlock->changed.pixelShader = TRUE;
3612 /* Handle recording of state blocks */
3613 if (This->isRecordingState) {
3614 TRACE("Recording... not performing anything\n");
3617 if (This->isRecordingState) {
3618 TRACE("Recording... not performing anything\n");
3619 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3620 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3621 return WINED3D_OK;
3624 if(pShader == oldShader) {
3625 TRACE("App is setting the old pixel shader over, nothing to do\n");
3626 return WINED3D_OK;
3629 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3630 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3632 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3633 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3635 return WINED3D_OK;
3638 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3641 if (NULL == ppShader) {
3642 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3643 return WINED3DERR_INVALIDCALL;
3646 *ppShader = This->stateBlock->pixelShader;
3647 if (NULL != *ppShader) {
3648 IWineD3DPixelShader_AddRef(*ppShader);
3650 TRACE("(%p) : returning %p\n", This, *ppShader);
3651 return WINED3D_OK;
3654 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3655 IWineD3DDevice *iface,
3656 UINT start,
3657 CONST BOOL *srcData,
3658 UINT count) {
3660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3661 int i, cnt = min(count, MAX_CONST_B - start);
3663 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3664 iface, srcData, start, count);
3666 if (srcData == NULL || cnt < 0)
3667 return WINED3DERR_INVALIDCALL;
3669 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3670 for (i = 0; i < cnt; i++)
3671 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3673 for (i = start; i < cnt + start; ++i) {
3674 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3677 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3679 return WINED3D_OK;
3682 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3683 IWineD3DDevice *iface,
3684 UINT start,
3685 BOOL *dstData,
3686 UINT count) {
3688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3689 int cnt = min(count, MAX_CONST_B - start);
3691 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3692 iface, dstData, start, count);
3694 if (dstData == NULL || cnt < 0)
3695 return WINED3DERR_INVALIDCALL;
3697 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3698 return WINED3D_OK;
3701 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3702 IWineD3DDevice *iface,
3703 UINT start,
3704 CONST int *srcData,
3705 UINT count) {
3707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3708 int i, cnt = min(count, MAX_CONST_I - start);
3710 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3711 iface, srcData, start, count);
3713 if (srcData == NULL || cnt < 0)
3714 return WINED3DERR_INVALIDCALL;
3716 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3717 for (i = 0; i < cnt; i++)
3718 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3719 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3721 for (i = start; i < cnt + start; ++i) {
3722 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3725 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3727 return WINED3D_OK;
3730 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3731 IWineD3DDevice *iface,
3732 UINT start,
3733 int *dstData,
3734 UINT count) {
3736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3737 int cnt = min(count, MAX_CONST_I - start);
3739 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3740 iface, dstData, start, count);
3742 if (dstData == NULL || cnt < 0)
3743 return WINED3DERR_INVALIDCALL;
3745 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3746 return WINED3D_OK;
3749 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3750 IWineD3DDevice *iface,
3751 UINT start,
3752 CONST float *srcData,
3753 UINT count) {
3755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3756 int i;
3758 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3759 iface, srcData, start, count);
3761 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3762 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3763 return WINED3DERR_INVALIDCALL;
3765 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3766 if(TRACE_ON(d3d)) {
3767 for (i = 0; i < count; i++)
3768 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3769 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3772 for (i = start; i < count + start; ++i) {
3773 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3774 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3775 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3776 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3777 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3779 ptr->idx[ptr->count++] = i;
3780 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3784 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3786 return WINED3D_OK;
3789 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3790 IWineD3DDevice *iface,
3791 UINT start,
3792 float *dstData,
3793 UINT count) {
3795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3796 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3798 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3799 iface, dstData, start, count);
3801 if (dstData == NULL || cnt < 0)
3802 return WINED3DERR_INVALIDCALL;
3804 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3805 return WINED3D_OK;
3808 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3809 static HRESULT
3810 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3811 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3812 unsigned int i;
3813 DWORD DestFVF = dest->fvf;
3814 WINED3DVIEWPORT vp;
3815 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3816 BOOL doClip;
3817 int numTextures;
3819 if (lpStrideData->u.s.normal.lpData) {
3820 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3823 if (lpStrideData->u.s.position.lpData == NULL) {
3824 ERR("Source has no position mask\n");
3825 return WINED3DERR_INVALIDCALL;
3828 /* We might access VBOs from this code, so hold the lock */
3829 ENTER_GL();
3831 if (dest->resource.allocatedMemory == NULL) {
3832 /* This may happen if we do direct locking into a vbo. Unlikely,
3833 * but theoretically possible(ddraw processvertices test)
3835 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3836 if(!dest->resource.allocatedMemory) {
3837 LEAVE_GL();
3838 ERR("Out of memory\n");
3839 return E_OUTOFMEMORY;
3841 if(dest->vbo) {
3842 void *src;
3843 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3844 checkGLcall("glBindBufferARB");
3845 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3846 if(src) {
3847 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3849 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3850 checkGLcall("glUnmapBufferARB");
3854 /* Get a pointer into the destination vbo(create one if none exists) and
3855 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3857 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3858 CreateVBO(dest);
3861 if(dest->vbo) {
3862 unsigned char extrabytes = 0;
3863 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3864 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3865 * this may write 4 extra bytes beyond the area that should be written
3867 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3868 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3869 if(!dest_conv_addr) {
3870 ERR("Out of memory\n");
3871 /* Continue without storing converted vertices */
3873 dest_conv = dest_conv_addr;
3876 /* Should I clip?
3877 * a) WINED3DRS_CLIPPING is enabled
3878 * b) WINED3DVOP_CLIP is passed
3880 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3881 static BOOL warned = FALSE;
3883 * The clipping code is not quite correct. Some things need
3884 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3885 * so disable clipping for now.
3886 * (The graphics in Half-Life are broken, and my processvertices
3887 * test crashes with IDirect3DDevice3)
3888 doClip = TRUE;
3890 doClip = FALSE;
3891 if(!warned) {
3892 warned = TRUE;
3893 FIXME("Clipping is broken and disabled for now\n");
3895 } else doClip = FALSE;
3896 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3898 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3899 WINED3DTS_VIEW,
3900 &view_mat);
3901 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3902 WINED3DTS_PROJECTION,
3903 &proj_mat);
3904 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3905 WINED3DTS_WORLDMATRIX(0),
3906 &world_mat);
3908 TRACE("View mat:\n");
3909 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);
3910 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);
3911 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);
3912 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);
3914 TRACE("Proj mat:\n");
3915 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);
3916 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);
3917 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);
3918 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);
3920 TRACE("World mat:\n");
3921 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);
3922 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);
3923 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);
3924 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);
3926 /* Get the viewport */
3927 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3928 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3929 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3931 multiply_matrix(&mat,&view_mat,&world_mat);
3932 multiply_matrix(&mat,&proj_mat,&mat);
3934 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3936 for (i = 0; i < dwCount; i+= 1) {
3937 unsigned int tex_index;
3939 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3940 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3941 /* The position first */
3942 float *p =
3943 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3944 float x, y, z, rhw;
3945 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3947 /* Multiplication with world, view and projection matrix */
3948 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);
3949 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);
3950 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);
3951 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);
3953 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3955 /* WARNING: The following things are taken from d3d7 and were not yet checked
3956 * against d3d8 or d3d9!
3959 /* Clipping conditions: From
3960 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3962 * A vertex is clipped if it does not match the following requirements
3963 * -rhw < x <= rhw
3964 * -rhw < y <= rhw
3965 * 0 < z <= rhw
3966 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3968 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3969 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3973 if( !doClip ||
3974 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3975 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3976 ( rhw > eps ) ) ) {
3978 /* "Normal" viewport transformation (not clipped)
3979 * 1) The values are divided by rhw
3980 * 2) The y axis is negative, so multiply it with -1
3981 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3982 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3983 * 4) Multiply x with Width/2 and add Width/2
3984 * 5) The same for the height
3985 * 6) Add the viewpoint X and Y to the 2D coordinates and
3986 * The minimum Z value to z
3987 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3989 * Well, basically it's simply a linear transformation into viewport
3990 * coordinates
3993 x /= rhw;
3994 y /= rhw;
3995 z /= rhw;
3997 y *= -1;
3999 x *= vp.Width / 2;
4000 y *= vp.Height / 2;
4001 z *= vp.MaxZ - vp.MinZ;
4003 x += vp.Width / 2 + vp.X;
4004 y += vp.Height / 2 + vp.Y;
4005 z += vp.MinZ;
4007 rhw = 1 / rhw;
4008 } else {
4009 /* That vertex got clipped
4010 * Contrary to OpenGL it is not dropped completely, it just
4011 * undergoes a different calculation.
4013 TRACE("Vertex got clipped\n");
4014 x += rhw;
4015 y += rhw;
4017 x /= 2;
4018 y /= 2;
4020 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4021 * outside of the main vertex buffer memory. That needs some more
4022 * investigation...
4026 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4029 ( (float *) dest_ptr)[0] = x;
4030 ( (float *) dest_ptr)[1] = y;
4031 ( (float *) dest_ptr)[2] = z;
4032 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4034 dest_ptr += 3 * sizeof(float);
4036 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4037 dest_ptr += sizeof(float);
4040 if(dest_conv) {
4041 float w = 1 / rhw;
4042 ( (float *) dest_conv)[0] = x * w;
4043 ( (float *) dest_conv)[1] = y * w;
4044 ( (float *) dest_conv)[2] = z * w;
4045 ( (float *) dest_conv)[3] = w;
4047 dest_conv += 3 * sizeof(float);
4049 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4050 dest_conv += sizeof(float);
4054 if (DestFVF & WINED3DFVF_PSIZE) {
4055 dest_ptr += sizeof(DWORD);
4056 if(dest_conv) dest_conv += sizeof(DWORD);
4058 if (DestFVF & WINED3DFVF_NORMAL) {
4059 float *normal =
4060 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4061 /* AFAIK this should go into the lighting information */
4062 FIXME("Didn't expect the destination to have a normal\n");
4063 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4064 if(dest_conv) {
4065 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4069 if (DestFVF & WINED3DFVF_DIFFUSE) {
4070 DWORD *color_d =
4071 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4072 if(!color_d) {
4073 static BOOL warned = FALSE;
4075 if(!warned) {
4076 ERR("No diffuse color in source, but destination has one\n");
4077 warned = TRUE;
4080 *( (DWORD *) dest_ptr) = 0xffffffff;
4081 dest_ptr += sizeof(DWORD);
4083 if(dest_conv) {
4084 *( (DWORD *) dest_conv) = 0xffffffff;
4085 dest_conv += sizeof(DWORD);
4088 else {
4089 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4090 if(dest_conv) {
4091 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4092 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4093 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4094 dest_conv += sizeof(DWORD);
4099 if (DestFVF & WINED3DFVF_SPECULAR) {
4100 /* What's the color value in the feedback buffer? */
4101 DWORD *color_s =
4102 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4103 if(!color_s) {
4104 static BOOL warned = FALSE;
4106 if(!warned) {
4107 ERR("No specular color in source, but destination has one\n");
4108 warned = TRUE;
4111 *( (DWORD *) dest_ptr) = 0xFF000000;
4112 dest_ptr += sizeof(DWORD);
4114 if(dest_conv) {
4115 *( (DWORD *) dest_conv) = 0xFF000000;
4116 dest_conv += sizeof(DWORD);
4119 else {
4120 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4121 if(dest_conv) {
4122 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4123 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4124 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4125 dest_conv += sizeof(DWORD);
4130 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4131 float *tex_coord =
4132 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4133 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4134 if(!tex_coord) {
4135 ERR("No source texture, but destination requests one\n");
4136 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4137 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4139 else {
4140 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4141 if(dest_conv) {
4142 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4148 if(dest_conv) {
4149 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4150 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4151 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4152 dwCount * get_flexible_vertex_size(DestFVF),
4153 dest_conv_addr));
4154 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4155 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4158 LEAVE_GL();
4160 return WINED3D_OK;
4162 #undef copy_and_next
4164 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4166 WineDirect3DVertexStridedData strided;
4167 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4168 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4170 if(pVertexDecl) {
4171 ERR("Output vertex declaration not implemented yet\n");
4174 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
4175 * and this call is quite performance critical, so don't call needlessly
4177 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4178 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4181 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4182 * control the streamIsUP flag, thus restore it afterwards.
4184 This->stateBlock->streamIsUP = FALSE;
4185 memset(&strided, 0, sizeof(strided));
4186 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4187 This->stateBlock->streamIsUP = streamWasUP;
4189 if(vbo || SrcStartIndex) {
4190 unsigned int i;
4191 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4192 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4194 * Also get the start index in, but only loop over all elements if there's something to add at all.
4196 #define FIXSRC(type) \
4197 if(strided.u.s.type.VBO) { \
4198 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4199 strided.u.s.type.VBO = 0; \
4200 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4201 ENTER_GL(); \
4202 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4203 vb->vbo = 0; \
4204 LEAVE_GL(); \
4206 if(strided.u.s.type.lpData) { \
4207 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4209 FIXSRC(position);
4210 FIXSRC(blendWeights);
4211 FIXSRC(blendMatrixIndices);
4212 FIXSRC(normal);
4213 FIXSRC(pSize);
4214 FIXSRC(diffuse);
4215 FIXSRC(specular);
4216 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4217 FIXSRC(texCoords[i]);
4219 FIXSRC(position2);
4220 FIXSRC(normal2);
4221 FIXSRC(tangent);
4222 FIXSRC(binormal);
4223 FIXSRC(tessFactor);
4224 FIXSRC(fog);
4225 FIXSRC(depth);
4226 FIXSRC(sample);
4227 #undef FIXSRC
4230 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4233 /*****
4234 * Get / Set Texture Stage States
4235 * TODO: Verify against dx9 definitions
4236 *****/
4237 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4238 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4239 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4241 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4243 if (Stage >= MAX_TEXTURES) {
4244 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4245 return WINED3D_OK;
4248 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4249 This->updateStateBlock->textureState[Stage][Type] = Value;
4251 if (This->isRecordingState) {
4252 TRACE("Recording... not performing anything\n");
4253 return WINED3D_OK;
4256 /* Checked after the assignments to allow proper stateblock recording */
4257 if(oldValue == Value) {
4258 TRACE("App is setting the old value over, nothing to do\n");
4259 return WINED3D_OK;
4262 if(Stage > This->stateBlock->lowest_disabled_stage &&
4263 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4264 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4265 * Changes in other states are important on disabled stages too
4267 return WINED3D_OK;
4270 if(Type == WINED3DTSS_COLOROP) {
4271 int i;
4273 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4274 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4275 * they have to be disabled
4277 * The current stage is dirtified below.
4279 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4280 TRACE("Additionally dirtifying stage %d\n", i);
4281 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4283 This->stateBlock->lowest_disabled_stage = Stage;
4284 TRACE("New lowest disabled: %d\n", Stage);
4285 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4286 /* Previously disabled stage enabled. Stages above it may need enabling
4287 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4288 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4290 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4293 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4294 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4295 break;
4297 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4298 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4300 This->stateBlock->lowest_disabled_stage = i;
4301 TRACE("New lowest disabled: %d\n", i);
4303 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4304 /* TODO: Built a stage -> texture unit mapping for register combiners */
4308 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4310 return WINED3D_OK;
4313 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4315 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4316 *pValue = This->updateStateBlock->textureState[Stage][Type];
4317 return WINED3D_OK;
4320 /*****
4321 * Get / Set Texture
4322 *****/
4323 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4325 IWineD3DBaseTexture *oldTexture;
4327 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4329 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4330 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4333 oldTexture = This->updateStateBlock->textures[Stage];
4335 if(pTexture != NULL) {
4336 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4338 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4339 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4340 return WINED3DERR_INVALIDCALL;
4342 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4345 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4346 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4348 This->updateStateBlock->changed.textures[Stage] = TRUE;
4349 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4350 This->updateStateBlock->textures[Stage] = pTexture;
4352 /* Handle recording of state blocks */
4353 if (This->isRecordingState) {
4354 TRACE("Recording... not performing anything\n");
4355 return WINED3D_OK;
4358 if(oldTexture == pTexture) {
4359 TRACE("App is setting the same texture again, nothing to do\n");
4360 return WINED3D_OK;
4363 /** NOTE: MSDN says that setTexture increases the reference count,
4364 * and that the application must set the texture back to null (or have a leaky application),
4365 * This means we should pass the refcount up to the parent
4366 *******************************/
4367 if (NULL != This->updateStateBlock->textures[Stage]) {
4368 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4369 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4371 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4372 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4373 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4374 * so the COLOROP and ALPHAOP have to be dirtified.
4376 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4377 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4379 if(bindCount == 1) {
4380 new->baseTexture.sampler = Stage;
4382 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4386 if (NULL != oldTexture) {
4387 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4388 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4390 IWineD3DBaseTexture_Release(oldTexture);
4391 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4392 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4393 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4396 if(bindCount && old->baseTexture.sampler == Stage) {
4397 int i;
4398 /* Have to do a search for the other sampler(s) where the texture is bound to
4399 * Shouldn't happen as long as apps bind a texture only to one stage
4401 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4402 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4403 if(This->updateStateBlock->textures[i] == oldTexture) {
4404 old->baseTexture.sampler = i;
4405 break;
4411 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4413 return WINED3D_OK;
4416 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4419 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4421 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4422 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4425 *ppTexture=This->stateBlock->textures[Stage];
4426 if (*ppTexture)
4427 IWineD3DBaseTexture_AddRef(*ppTexture);
4429 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4431 return WINED3D_OK;
4434 /*****
4435 * Get Back Buffer
4436 *****/
4437 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4438 IWineD3DSurface **ppBackBuffer) {
4439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4440 IWineD3DSwapChain *swapChain;
4441 HRESULT hr;
4443 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4445 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4446 if (hr == WINED3D_OK) {
4447 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4448 IWineD3DSwapChain_Release(swapChain);
4449 } else {
4450 *ppBackBuffer = NULL;
4452 return hr;
4455 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4457 WARN("(%p) : stub, calling idirect3d for now\n", This);
4458 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4461 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4463 IWineD3DSwapChain *swapChain;
4464 HRESULT hr;
4466 if(iSwapChain > 0) {
4467 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4468 if (hr == WINED3D_OK) {
4469 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4470 IWineD3DSwapChain_Release(swapChain);
4471 } else {
4472 FIXME("(%p) Error getting display mode\n", This);
4474 } else {
4475 /* Don't read the real display mode,
4476 but return the stored mode instead. X11 can't change the color
4477 depth, and some apps are pretty angry if they SetDisplayMode from
4478 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4480 Also don't relay to the swapchain because with ddraw it's possible
4481 that there isn't a swapchain at all */
4482 pMode->Width = This->ddraw_width;
4483 pMode->Height = This->ddraw_height;
4484 pMode->Format = This->ddraw_format;
4485 pMode->RefreshRate = 0;
4486 hr = WINED3D_OK;
4489 return hr;
4492 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4494 TRACE("(%p)->(%p)\n", This, hWnd);
4496 if(This->ddraw_fullscreen) {
4497 if(This->ddraw_window && This->ddraw_window != hWnd) {
4498 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4500 if(hWnd && This->ddraw_window != hWnd) {
4501 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4505 This->ddraw_window = hWnd;
4506 return WINED3D_OK;
4509 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4511 TRACE("(%p)->(%p)\n", This, hWnd);
4513 *hWnd = This->ddraw_window;
4514 return WINED3D_OK;
4517 /*****
4518 * Stateblock related functions
4519 *****/
4521 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4523 IWineD3DStateBlockImpl *object;
4524 HRESULT temp_result;
4525 int i;
4527 TRACE("(%p)\n", This);
4529 if (This->isRecordingState) {
4530 return WINED3DERR_INVALIDCALL;
4533 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4534 if (NULL == object ) {
4535 FIXME("(%p)Error allocating memory for stateblock\n", This);
4536 return E_OUTOFMEMORY;
4538 TRACE("(%p) created object %p\n", This, object);
4539 object->wineD3DDevice= This;
4540 /** FIXME: object->parent = parent; **/
4541 object->parent = NULL;
4542 object->blockType = WINED3DSBT_RECORDED;
4543 object->ref = 1;
4544 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4546 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4547 list_init(&object->lightMap[i]);
4550 temp_result = allocate_shader_constants(object);
4551 if (WINED3D_OK != temp_result)
4552 return temp_result;
4554 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4555 This->updateStateBlock = object;
4556 This->isRecordingState = TRUE;
4558 TRACE("(%p) recording stateblock %p\n",This , object);
4559 return WINED3D_OK;
4562 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4564 unsigned int i, j;
4565 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4567 if (!This->isRecordingState) {
4568 FIXME("(%p) not recording! returning error\n", This);
4569 *ppStateBlock = NULL;
4570 return WINED3DERR_INVALIDCALL;
4573 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4574 if(object->changed.renderState[i]) {
4575 object->contained_render_states[object->num_contained_render_states] = i;
4576 object->num_contained_render_states++;
4579 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4580 if(object->changed.transform[i]) {
4581 object->contained_transform_states[object->num_contained_transform_states] = i;
4582 object->num_contained_transform_states++;
4585 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4586 if(object->changed.vertexShaderConstantsF[i]) {
4587 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4588 object->num_contained_vs_consts_f++;
4591 for(i = 0; i < MAX_CONST_I; i++) {
4592 if(object->changed.vertexShaderConstantsI[i]) {
4593 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4594 object->num_contained_vs_consts_i++;
4597 for(i = 0; i < MAX_CONST_B; i++) {
4598 if(object->changed.vertexShaderConstantsB[i]) {
4599 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4600 object->num_contained_vs_consts_b++;
4603 for(i = 0; i < MAX_CONST_I; i++) {
4604 if(object->changed.pixelShaderConstantsI[i]) {
4605 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4606 object->num_contained_ps_consts_i++;
4609 for(i = 0; i < MAX_CONST_B; i++) {
4610 if(object->changed.pixelShaderConstantsB[i]) {
4611 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4612 object->num_contained_ps_consts_b++;
4615 for(i = 0; i < MAX_TEXTURES; i++) {
4616 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4617 if(object->changed.textureState[i][j]) {
4618 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4619 object->contained_tss_states[object->num_contained_tss_states].state = j;
4620 object->num_contained_tss_states++;
4624 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4625 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4626 if(object->changed.samplerState[i][j]) {
4627 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4628 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4629 object->num_contained_sampler_states++;
4634 *ppStateBlock = (IWineD3DStateBlock*) object;
4635 This->isRecordingState = FALSE;
4636 This->updateStateBlock = This->stateBlock;
4637 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4638 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4639 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4640 return WINED3D_OK;
4643 /*****
4644 * Scene related functions
4645 *****/
4646 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4647 /* At the moment we have no need for any functionality at the beginning
4648 of a scene */
4649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4650 TRACE("(%p)\n", This);
4652 if(This->inScene) {
4653 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4654 return WINED3DERR_INVALIDCALL;
4656 This->inScene = TRUE;
4657 return WINED3D_OK;
4660 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4662 TRACE("(%p)\n", This);
4664 if(!This->inScene) {
4665 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4666 return WINED3DERR_INVALIDCALL;
4669 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4670 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4672 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4673 ENTER_GL();
4674 glFlush();
4675 checkGLcall("glFlush");
4676 LEAVE_GL();
4678 This->inScene = FALSE;
4679 return WINED3D_OK;
4682 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4683 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4684 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4686 IWineD3DSwapChain *swapChain = NULL;
4687 int i;
4688 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4690 TRACE("(%p) Presenting the frame\n", This);
4692 for(i = 0 ; i < swapchains ; i ++) {
4694 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4695 TRACE("presentinng chain %d, %p\n", i, swapChain);
4696 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4697 IWineD3DSwapChain_Release(swapChain);
4700 return WINED3D_OK;
4703 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4704 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4706 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4708 GLbitfield glMask = 0;
4709 unsigned int i;
4710 CONST WINED3DRECT* curRect;
4712 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4713 Count, pRects, Flags, Color, Z, Stencil);
4715 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4716 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4717 /* TODO: What about depth stencil buffers without stencil bits? */
4718 return WINED3DERR_INVALIDCALL;
4721 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4722 * and not the last active one.
4724 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4725 ENTER_GL();
4727 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4728 apply_fbo_state(iface);
4731 if (Count > 0 && pRects) {
4732 curRect = pRects;
4733 } else {
4734 curRect = NULL;
4737 /* Only set the values up once, as they are not changing */
4738 if (Flags & WINED3DCLEAR_STENCIL) {
4739 glClearStencil(Stencil);
4740 checkGLcall("glClearStencil");
4741 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4742 glStencilMask(0xFFFFFFFF);
4745 if (Flags & WINED3DCLEAR_ZBUFFER) {
4746 glDepthMask(GL_TRUE);
4747 glClearDepth(Z);
4748 checkGLcall("glClearDepth");
4749 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4750 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4753 if (Flags & WINED3DCLEAR_TARGET) {
4754 TRACE("Clearing screen with glClear to color %x\n", Color);
4755 glClearColor(D3DCOLOR_R(Color),
4756 D3DCOLOR_G(Color),
4757 D3DCOLOR_B(Color),
4758 D3DCOLOR_A(Color));
4759 checkGLcall("glClearColor");
4761 /* Clear ALL colors! */
4762 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4763 glMask = glMask | GL_COLOR_BUFFER_BIT;
4766 if (!curRect) {
4767 /* In drawable flag is set below */
4769 if (This->render_offscreen) {
4770 glScissor(This->stateBlock->viewport.X,
4771 This->stateBlock->viewport.Y,
4772 This->stateBlock->viewport.Width,
4773 This->stateBlock->viewport.Height);
4774 } else {
4775 glScissor(This->stateBlock->viewport.X,
4776 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4777 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4778 This->stateBlock->viewport.Width,
4779 This->stateBlock->viewport.Height);
4781 checkGLcall("glScissor");
4782 glClear(glMask);
4783 checkGLcall("glClear");
4784 } else {
4785 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4786 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4788 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4789 curRect[0].x2 < target->currentDesc.Width ||
4790 curRect[0].y2 < target->currentDesc.Height) {
4791 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4792 blt_to_drawable(This, target);
4796 /* Now process each rect in turn */
4797 for (i = 0; i < Count; i++) {
4798 /* Note gl uses lower left, width/height */
4799 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4800 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4801 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4802 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4804 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4805 * The rectangle is not cleared, no error is returned, but further rectanlges are
4806 * still cleared if they are valid
4808 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4809 TRACE("Rectangle with negative dimensions, ignoring\n");
4810 continue;
4813 if(This->render_offscreen) {
4814 glScissor(curRect[i].x1, curRect[i].y1,
4815 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4816 } else {
4817 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4818 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4820 checkGLcall("glScissor");
4822 glClear(glMask);
4823 checkGLcall("glClear");
4827 /* Restore the old values (why..?) */
4828 if (Flags & WINED3DCLEAR_STENCIL) {
4829 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4831 if (Flags & WINED3DCLEAR_TARGET) {
4832 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4833 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4834 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4835 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4836 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4839 LEAVE_GL();
4841 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4842 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4844 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4845 target->Flags |= SFLAG_INTEXTURE;
4846 target->Flags &= ~SFLAG_INSYSMEM;
4847 } else {
4848 target->Flags |= SFLAG_INDRAWABLE;
4849 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4851 return WINED3D_OK;
4854 /*****
4855 * Drawing functions
4856 *****/
4857 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4858 UINT PrimitiveCount) {
4860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4862 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4863 debug_d3dprimitivetype(PrimitiveType),
4864 StartVertex, PrimitiveCount);
4866 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4867 if(This->stateBlock->streamIsUP) {
4868 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4869 This->stateBlock->streamIsUP = FALSE;
4872 if(This->stateBlock->loadBaseVertexIndex != 0) {
4873 This->stateBlock->loadBaseVertexIndex = 0;
4874 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4876 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4877 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4878 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4879 return WINED3D_OK;
4882 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4883 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4884 WINED3DPRIMITIVETYPE PrimitiveType,
4885 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4888 UINT idxStride = 2;
4889 IWineD3DIndexBuffer *pIB;
4890 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4891 GLuint vbo;
4893 pIB = This->stateBlock->pIndexData;
4894 if (!pIB) {
4895 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4896 * without an index buffer set. (The first time at least...)
4897 * D3D8 simply dies, but I doubt it can do much harm to return
4898 * D3DERR_INVALIDCALL there as well. */
4899 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4900 return WINED3DERR_INVALIDCALL;
4903 if(This->stateBlock->streamIsUP) {
4904 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4905 This->stateBlock->streamIsUP = FALSE;
4907 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4909 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4910 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4911 minIndex, NumVertices, startIndex, primCount);
4913 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4914 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4915 idxStride = 2;
4916 } else {
4917 idxStride = 4;
4920 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4921 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4922 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4925 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4926 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4928 return WINED3D_OK;
4931 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4932 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4933 UINT VertexStreamZeroStride) {
4934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4935 IWineD3DVertexBuffer *vb;
4937 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4938 debug_d3dprimitivetype(PrimitiveType),
4939 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4941 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4942 vb = This->stateBlock->streamSource[0];
4943 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4944 if(vb) IWineD3DVertexBuffer_Release(vb);
4945 This->stateBlock->streamOffset[0] = 0;
4946 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4947 This->stateBlock->streamIsUP = TRUE;
4948 This->stateBlock->loadBaseVertexIndex = 0;
4950 /* TODO: Only mark dirty if drawing from a different UP address */
4951 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4953 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4954 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4956 /* MSDN specifies stream zero settings must be set to NULL */
4957 This->stateBlock->streamStride[0] = 0;
4958 This->stateBlock->streamSource[0] = NULL;
4960 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4961 * the new stream sources or use UP drawing again
4963 return WINED3D_OK;
4966 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4967 UINT MinVertexIndex, UINT NumVertices,
4968 UINT PrimitiveCount, CONST void* pIndexData,
4969 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4970 UINT VertexStreamZeroStride) {
4971 int idxStride;
4972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4973 IWineD3DVertexBuffer *vb;
4974 IWineD3DIndexBuffer *ib;
4976 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4977 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4978 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4979 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4981 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4982 idxStride = 2;
4983 } else {
4984 idxStride = 4;
4987 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4988 vb = This->stateBlock->streamSource[0];
4989 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4990 if(vb) IWineD3DVertexBuffer_Release(vb);
4991 This->stateBlock->streamIsUP = TRUE;
4992 This->stateBlock->streamOffset[0] = 0;
4993 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4995 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4996 This->stateBlock->baseVertexIndex = 0;
4997 This->stateBlock->loadBaseVertexIndex = 0;
4998 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4999 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5000 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5002 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5004 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5005 This->stateBlock->streamSource[0] = NULL;
5006 This->stateBlock->streamStride[0] = 0;
5007 ib = This->stateBlock->pIndexData;
5008 if(ib) {
5009 IWineD3DIndexBuffer_Release(ib);
5010 This->stateBlock->pIndexData = NULL;
5012 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5013 * SetStreamSource to specify a vertex buffer
5016 return WINED3D_OK;
5019 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5022 /* Mark the state dirty until we have nicer tracking
5023 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5024 * that value.
5026 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5027 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5028 This->stateBlock->baseVertexIndex = 0;
5029 This->up_strided = DrawPrimStrideData;
5030 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5031 This->up_strided = NULL;
5032 return WINED3D_OK;
5035 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5037 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5039 /* Mark the state dirty until we have nicer tracking
5040 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5041 * that value.
5043 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5044 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5045 This->stateBlock->streamIsUP = TRUE;
5046 This->stateBlock->baseVertexIndex = 0;
5047 This->up_strided = DrawPrimStrideData;
5048 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5049 This->up_strided = NULL;
5050 return WINED3D_OK;
5053 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5054 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5055 * not callable by the app directly no parameter validation checks are needed here.
5057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5058 WINED3DLOCKED_BOX src;
5059 WINED3DLOCKED_BOX dst;
5060 HRESULT hr;
5061 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5063 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5064 * dirtification to improve loading performance.
5066 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5067 if(FAILED(hr)) return hr;
5068 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5069 if(FAILED(hr)) {
5070 IWineD3DVolume_UnlockBox(pSourceVolume);
5071 return hr;
5074 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5076 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5077 if(FAILED(hr)) {
5078 IWineD3DVolume_UnlockBox(pSourceVolume);
5079 } else {
5080 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5082 return hr;
5085 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5086 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5088 HRESULT hr = WINED3D_OK;
5089 WINED3DRESOURCETYPE sourceType;
5090 WINED3DRESOURCETYPE destinationType;
5091 int i ,levels;
5093 /* TODO: think about moving the code into IWineD3DBaseTexture */
5095 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5097 /* verify that the source and destination textures aren't NULL */
5098 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5099 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5100 This, pSourceTexture, pDestinationTexture);
5101 hr = WINED3DERR_INVALIDCALL;
5104 if (pSourceTexture == pDestinationTexture) {
5105 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5106 This, pSourceTexture, pDestinationTexture);
5107 hr = WINED3DERR_INVALIDCALL;
5109 /* Verify that the source and destination textures are the same type */
5110 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5111 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5113 if (sourceType != destinationType) {
5114 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5115 This);
5116 hr = WINED3DERR_INVALIDCALL;
5119 /* check that both textures have the identical numbers of levels */
5120 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5121 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5122 hr = WINED3DERR_INVALIDCALL;
5125 if (WINED3D_OK == hr) {
5127 /* Make sure that the destination texture is loaded */
5128 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5130 /* Update every surface level of the texture */
5131 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5133 switch (sourceType) {
5134 case WINED3DRTYPE_TEXTURE:
5136 IWineD3DSurface *srcSurface;
5137 IWineD3DSurface *destSurface;
5139 for (i = 0 ; i < levels ; ++i) {
5140 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5141 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5142 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5143 IWineD3DSurface_Release(srcSurface);
5144 IWineD3DSurface_Release(destSurface);
5145 if (WINED3D_OK != hr) {
5146 WARN("(%p) : Call to update surface failed\n", This);
5147 return hr;
5151 break;
5152 case WINED3DRTYPE_CUBETEXTURE:
5154 IWineD3DSurface *srcSurface;
5155 IWineD3DSurface *destSurface;
5156 WINED3DCUBEMAP_FACES faceType;
5158 for (i = 0 ; i < levels ; ++i) {
5159 /* Update each cube face */
5160 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5161 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5162 if (WINED3D_OK != hr) {
5163 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5164 } else {
5165 TRACE("Got srcSurface %p\n", srcSurface);
5167 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5168 if (WINED3D_OK != hr) {
5169 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5170 } else {
5171 TRACE("Got desrSurface %p\n", destSurface);
5173 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5174 IWineD3DSurface_Release(srcSurface);
5175 IWineD3DSurface_Release(destSurface);
5176 if (WINED3D_OK != hr) {
5177 WARN("(%p) : Call to update surface failed\n", This);
5178 return hr;
5183 break;
5185 case WINED3DRTYPE_VOLUMETEXTURE:
5187 IWineD3DVolume *srcVolume = NULL;
5188 IWineD3DVolume *destVolume = NULL;
5190 for (i = 0 ; i < levels ; ++i) {
5191 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5192 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5193 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5194 IWineD3DVolume_Release(srcVolume);
5195 IWineD3DVolume_Release(destVolume);
5196 if (WINED3D_OK != hr) {
5197 WARN("(%p) : Call to update volume failed\n", This);
5198 return hr;
5202 break;
5204 default:
5205 FIXME("(%p) : Unsupported source and destination type\n", This);
5206 hr = WINED3DERR_INVALIDCALL;
5210 return hr;
5213 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5214 IWineD3DSwapChain *swapChain;
5215 HRESULT hr;
5216 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5217 if(hr == WINED3D_OK) {
5218 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5219 IWineD3DSwapChain_Release(swapChain);
5221 return hr;
5224 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5226 /* return a sensible default */
5227 *pNumPasses = 1;
5228 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5229 FIXME("(%p) : stub\n", This);
5230 return WINED3D_OK;
5233 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5235 int j;
5236 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5237 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5238 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5239 return WINED3DERR_INVALIDCALL;
5241 for (j = 0; j < 256; ++j) {
5242 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5243 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5244 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5245 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5247 TRACE("(%p) : returning\n", This);
5248 return WINED3D_OK;
5251 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5253 int j;
5254 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5255 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5256 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5257 return WINED3DERR_INVALIDCALL;
5259 for (j = 0; j < 256; ++j) {
5260 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5261 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5262 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5263 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5265 TRACE("(%p) : returning\n", This);
5266 return WINED3D_OK;
5269 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5271 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5272 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5273 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5274 return WINED3DERR_INVALIDCALL;
5276 /*TODO: stateblocks */
5277 This->currentPalette = PaletteNumber;
5278 TRACE("(%p) : returning\n", This);
5279 return WINED3D_OK;
5282 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5284 if (PaletteNumber == NULL) {
5285 WARN("(%p) : returning Invalid Call\n", This);
5286 return WINED3DERR_INVALIDCALL;
5288 /*TODO: stateblocks */
5289 *PaletteNumber = This->currentPalette;
5290 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5291 return WINED3D_OK;
5294 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5296 static BOOL showFixmes = TRUE;
5297 if (showFixmes) {
5298 FIXME("(%p) : stub\n", This);
5299 showFixmes = FALSE;
5302 This->softwareVertexProcessing = bSoftware;
5303 return WINED3D_OK;
5307 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5309 static BOOL showFixmes = TRUE;
5310 if (showFixmes) {
5311 FIXME("(%p) : stub\n", This);
5312 showFixmes = FALSE;
5314 return This->softwareVertexProcessing;
5318 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5320 IWineD3DSwapChain *swapChain;
5321 HRESULT hr;
5323 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5325 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5326 if(hr == WINED3D_OK){
5327 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5328 IWineD3DSwapChain_Release(swapChain);
5329 }else{
5330 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5332 return hr;
5336 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5338 static BOOL showfixmes = TRUE;
5339 if(nSegments != 0.0f) {
5340 if( showfixmes) {
5341 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5342 showfixmes = FALSE;
5345 return WINED3D_OK;
5348 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5350 static BOOL showfixmes = TRUE;
5351 if( showfixmes) {
5352 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5353 showfixmes = FALSE;
5355 return 0.0f;
5358 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5360 /** TODO: remove casts to IWineD3DSurfaceImpl
5361 * NOTE: move code to surface to accomplish this
5362 ****************************************/
5363 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5364 int srcWidth, srcHeight;
5365 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5366 WINED3DFORMAT destFormat, srcFormat;
5367 UINT destSize;
5368 int srcLeft, destLeft, destTop;
5369 WINED3DPOOL srcPool, destPool;
5370 int offset = 0;
5371 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5372 glDescriptor *glDescription = NULL;
5373 GLenum dummy;
5374 int bpp;
5375 CONVERT_TYPES convert = NO_CONVERSION;
5377 WINED3DSURFACE_DESC winedesc;
5379 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5380 memset(&winedesc, 0, sizeof(winedesc));
5381 winedesc.Width = &srcSurfaceWidth;
5382 winedesc.Height = &srcSurfaceHeight;
5383 winedesc.Pool = &srcPool;
5384 winedesc.Format = &srcFormat;
5386 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5388 winedesc.Width = &destSurfaceWidth;
5389 winedesc.Height = &destSurfaceHeight;
5390 winedesc.Pool = &destPool;
5391 winedesc.Format = &destFormat;
5392 winedesc.Size = &destSize;
5394 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5396 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5397 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5398 return WINED3DERR_INVALIDCALL;
5401 /* This call loads the opengl surface directly, instead of copying the surface to the
5402 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5403 * copy in sysmem and use regular surface loading.
5405 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5406 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5407 if(convert != NO_CONVERSION) {
5408 return IWineD3DSurface_BltFast(pDestinationSurface,
5409 pDestPoint ? pDestPoint->x : 0,
5410 pDestPoint ? pDestPoint->y : 0,
5411 pSourceSurface, (RECT *) pSourceRect, 0);
5414 if (destFormat == WINED3DFMT_UNKNOWN) {
5415 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5416 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5418 /* Get the update surface description */
5419 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5422 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5424 ENTER_GL();
5426 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5427 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5428 checkGLcall("glActiveTextureARB");
5431 /* Make sure the surface is loaded and up to date */
5432 IWineD3DSurface_PreLoad(pDestinationSurface);
5434 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5436 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5437 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5438 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5439 srcLeft = pSourceRect ? pSourceRect->left : 0;
5440 destLeft = pDestPoint ? pDestPoint->x : 0;
5441 destTop = pDestPoint ? pDestPoint->y : 0;
5444 /* This function doesn't support compressed textures
5445 the pitch is just bytesPerPixel * width */
5446 if(srcWidth != srcSurfaceWidth || srcLeft ){
5447 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5448 offset += srcLeft * pSrcSurface->bytesPerPixel;
5449 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5451 /* TODO DXT formats */
5453 if(pSourceRect != NULL && pSourceRect->top != 0){
5454 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5456 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5457 ,This
5458 ,glDescription->level
5459 ,destLeft
5460 ,destTop
5461 ,srcWidth
5462 ,srcHeight
5463 ,glDescription->glFormat
5464 ,glDescription->glType
5465 ,IWineD3DSurface_GetData(pSourceSurface)
5468 /* Sanity check */
5469 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5471 /* need to lock the surface to get the data */
5472 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5475 /* TODO: Cube and volume support */
5476 if(rowoffset != 0){
5477 /* not a whole row so we have to do it a line at a time */
5478 int j;
5480 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5481 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5483 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5485 glTexSubImage2D(glDescription->target
5486 ,glDescription->level
5487 ,destLeft
5489 ,srcWidth
5491 ,glDescription->glFormat
5492 ,glDescription->glType
5493 ,data /* could be quicker using */
5495 data += rowoffset;
5498 } else { /* Full width, so just write out the whole texture */
5500 if (WINED3DFMT_DXT1 == destFormat ||
5501 WINED3DFMT_DXT2 == destFormat ||
5502 WINED3DFMT_DXT3 == destFormat ||
5503 WINED3DFMT_DXT4 == destFormat ||
5504 WINED3DFMT_DXT5 == destFormat) {
5505 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5506 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5507 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5508 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5509 } if (destFormat != srcFormat) {
5510 FIXME("Updating mixed format compressed texture is not curretly support\n");
5511 } else {
5512 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5513 glDescription->level,
5514 glDescription->glFormatInternal,
5515 srcWidth,
5516 srcHeight,
5518 destSize,
5519 IWineD3DSurface_GetData(pSourceSurface));
5521 } else {
5522 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5526 } else {
5527 glTexSubImage2D(glDescription->target
5528 ,glDescription->level
5529 ,destLeft
5530 ,destTop
5531 ,srcWidth
5532 ,srcHeight
5533 ,glDescription->glFormat
5534 ,glDescription->glType
5535 ,IWineD3DSurface_GetData(pSourceSurface)
5539 checkGLcall("glTexSubImage2D");
5541 LEAVE_GL();
5543 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5544 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5545 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5547 return WINED3D_OK;
5550 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5552 struct WineD3DRectPatch *patch;
5553 unsigned int i;
5554 struct list *e;
5555 BOOL found;
5556 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5558 if(!(Handle || pRectPatchInfo)) {
5559 /* TODO: Write a test for the return value, thus the FIXME */
5560 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5561 return WINED3DERR_INVALIDCALL;
5564 if(Handle) {
5565 i = PATCHMAP_HASHFUNC(Handle);
5566 found = FALSE;
5567 LIST_FOR_EACH(e, &This->patches[i]) {
5568 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5569 if(patch->Handle == Handle) {
5570 found = TRUE;
5571 break;
5575 if(!found) {
5576 TRACE("Patch does not exist. Creating a new one\n");
5577 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5578 patch->Handle = Handle;
5579 list_add_head(&This->patches[i], &patch->entry);
5580 } else {
5581 TRACE("Found existing patch %p\n", patch);
5583 } else {
5584 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5585 * attributes we have to tesselate, read back, and draw. This needs a patch
5586 * management structure instance. Create one.
5588 * A possible improvement is to check if a vertex shader is used, and if not directly
5589 * draw the patch.
5591 FIXME("Drawing an uncached patch. This is slow\n");
5592 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5595 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5596 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5597 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5598 HRESULT hr;
5599 TRACE("Tesselation density or patch info changed, retesselating\n");
5601 if(pRectPatchInfo) {
5602 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5604 patch->numSegs[0] = pNumSegs[0];
5605 patch->numSegs[1] = pNumSegs[1];
5606 patch->numSegs[2] = pNumSegs[2];
5607 patch->numSegs[3] = pNumSegs[3];
5609 hr = tesselate_rectpatch(This, patch);
5610 if(FAILED(hr)) {
5611 WARN("Patch tesselation failed\n");
5613 /* Do not release the handle to store the params of the patch */
5614 if(!Handle) {
5615 HeapFree(GetProcessHeap(), 0, patch);
5617 return hr;
5621 This->currentPatch = patch;
5622 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5623 This->currentPatch = NULL;
5625 /* Destroy uncached patches */
5626 if(!Handle) {
5627 HeapFree(GetProcessHeap(), 0, patch->mem);
5628 HeapFree(GetProcessHeap(), 0, patch);
5630 return WINED3D_OK;
5633 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5634 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5636 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5637 FIXME("(%p) : Stub\n", This);
5638 return WINED3D_OK;
5641 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5643 int i;
5644 struct WineD3DRectPatch *patch;
5645 struct list *e;
5646 TRACE("(%p) Handle(%d)\n", This, Handle);
5648 i = PATCHMAP_HASHFUNC(Handle);
5649 LIST_FOR_EACH(e, &This->patches[i]) {
5650 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5651 if(patch->Handle == Handle) {
5652 TRACE("Deleting patch %p\n", patch);
5653 list_remove(&patch->entry);
5654 HeapFree(GetProcessHeap(), 0, patch->mem);
5655 HeapFree(GetProcessHeap(), 0, patch);
5656 return WINED3D_OK;
5660 /* TODO: Write a test for the return value */
5661 FIXME("Attempt to destroy nonexistant patch\n");
5662 return WINED3DERR_INVALIDCALL;
5665 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5666 HRESULT hr;
5667 IWineD3DSwapChain *swapchain;
5669 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5670 if (SUCCEEDED(hr)) {
5671 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5672 return swapchain;
5675 return NULL;
5678 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5681 if (!*fbo) {
5682 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5683 checkGLcall("glGenFramebuffersEXT()");
5685 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5686 checkGLcall("glBindFramebuffer()");
5689 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5690 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5691 IWineD3DBaseTextureImpl *texture_impl;
5692 GLenum texttarget, target;
5693 GLint old_binding;
5695 texttarget = surface_impl->glDescription.target;
5696 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5697 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5699 IWineD3DSurface_PreLoad(surface);
5701 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5702 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5703 glBindTexture(target, old_binding);
5705 /* Update base texture states array */
5706 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5707 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5708 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5709 if (texture_impl->baseTexture.bindCount) {
5710 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5713 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5716 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5717 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5719 checkGLcall("attach_surface_fbo");
5722 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5724 IWineD3DSwapChain *swapchain;
5726 swapchain = get_swapchain(surface);
5727 if (swapchain) {
5728 GLenum buffer;
5730 TRACE("Surface %p is onscreen\n", surface);
5732 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5733 buffer = surface_get_gl_buffer(surface, swapchain);
5734 glDrawBuffer(buffer);
5735 checkGLcall("glDrawBuffer()");
5736 } else {
5737 TRACE("Surface %p is offscreen\n", surface);
5738 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5739 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5742 if (rect) {
5743 glEnable(GL_SCISSOR_TEST);
5744 if(!swapchain) {
5745 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5746 } else {
5747 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5748 rect->x2 - rect->x1, rect->y2 - rect->y1);
5750 checkGLcall("glScissor");
5751 } else {
5752 glDisable(GL_SCISSOR_TEST);
5754 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5756 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5757 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5759 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5760 glClear(GL_COLOR_BUFFER_BIT);
5761 checkGLcall("glClear");
5763 if (This->render_offscreen) {
5764 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5765 } else {
5766 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5767 checkGLcall("glBindFramebuffer()");
5770 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5771 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5772 glDrawBuffer(GL_BACK);
5773 checkGLcall("glDrawBuffer()");
5777 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5778 unsigned int r, g, b, a;
5779 DWORD ret;
5781 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
5782 destfmt == WINED3DFMT_R8G8B8)
5783 return color;
5785 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5787 a = (color & 0xff000000) >> 24;
5788 r = (color & 0x00ff0000) >> 16;
5789 g = (color & 0x0000ff00) >> 8;
5790 b = (color & 0x000000ff) >> 0;
5792 switch(destfmt)
5794 case WINED3DFMT_R5G6B5:
5795 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5796 r = (r * 32) / 256;
5797 g = (g * 64) / 256;
5798 b = (b * 32) / 256;
5799 ret = r << 11;
5800 ret |= g << 5;
5801 ret |= b;
5802 TRACE("Returning %08x\n", ret);
5803 return ret;
5805 case WINED3DFMT_X1R5G5B5:
5806 case WINED3DFMT_A1R5G5B5:
5807 a = (a * 2) / 256;
5808 r = (r * 32) / 256;
5809 g = (g * 32) / 256;
5810 b = (b * 32) / 256;
5811 ret = a << 15;
5812 ret |= r << 10;
5813 ret |= g << 5;
5814 ret |= b << 0;
5815 TRACE("Returning %08x\n", ret);
5816 return ret;
5818 case WINED3DFMT_A8:
5819 TRACE("Returning %08x\n", a);
5820 return a;
5822 case WINED3DFMT_X4R4G4B4:
5823 case WINED3DFMT_A4R4G4B4:
5824 a = (a * 16) / 256;
5825 r = (r * 16) / 256;
5826 g = (g * 16) / 256;
5827 b = (b * 16) / 256;
5828 ret = a << 12;
5829 ret |= r << 8;
5830 ret |= g << 4;
5831 ret |= b << 0;
5832 TRACE("Returning %08x\n", ret);
5833 return ret;
5835 case WINED3DFMT_R3G3B2:
5836 r = (r * 8) / 256;
5837 g = (g * 8) / 256;
5838 b = (b * 4) / 256;
5839 ret = r << 5;
5840 ret |= g << 2;
5841 ret |= b << 0;
5842 TRACE("Returning %08x\n", ret);
5843 return ret;
5845 case WINED3DFMT_X8B8G8R8:
5846 case WINED3DFMT_A8B8G8R8:
5847 ret = a << 24;
5848 ret |= b << 16;
5849 ret |= g << 8;
5850 ret |= r << 0;
5851 TRACE("Returning %08x\n", ret);
5852 return ret;
5854 case WINED3DFMT_A2R10G10B10:
5855 a = (a * 4) / 256;
5856 r = (r * 1024) / 256;
5857 g = (g * 1024) / 256;
5858 b = (b * 1024) / 256;
5859 ret = a << 30;
5860 ret |= r << 20;
5861 ret |= g << 10;
5862 ret |= b << 0;
5863 TRACE("Returning %08x\n", ret);
5864 return ret;
5866 case WINED3DFMT_A2B10G10R10:
5867 a = (a * 4) / 256;
5868 r = (r * 1024) / 256;
5869 g = (g * 1024) / 256;
5870 b = (b * 1024) / 256;
5871 ret = a << 30;
5872 ret |= b << 20;
5873 ret |= g << 10;
5874 ret |= r << 0;
5875 TRACE("Returning %08x\n", ret);
5876 return ret;
5878 default:
5879 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5880 return 0;
5884 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5886 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5887 WINEDDBLTFX BltFx;
5888 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5890 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5891 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5892 return WINED3DERR_INVALIDCALL;
5895 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5896 color_fill_fbo(iface, pSurface, pRect, color);
5897 return WINED3D_OK;
5898 } else {
5899 /* Just forward this to the DirectDraw blitting engine */
5900 memset(&BltFx, 0, sizeof(BltFx));
5901 BltFx.dwSize = sizeof(BltFx);
5902 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
5903 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5907 /* rendertarget and deptth stencil functions */
5908 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5911 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5912 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5913 return WINED3DERR_INVALIDCALL;
5916 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5917 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5918 /* Note inc ref on returned surface */
5919 if(*ppRenderTarget != NULL)
5920 IWineD3DSurface_AddRef(*ppRenderTarget);
5921 return WINED3D_OK;
5924 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5926 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5927 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5928 IWineD3DSwapChainImpl *Swapchain;
5929 HRESULT hr;
5931 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5933 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5934 if(hr != WINED3D_OK) {
5935 ERR("Can't get the swapchain\n");
5936 return hr;
5939 /* Make sure to release the swapchain */
5940 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5942 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5943 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5944 return WINED3DERR_INVALIDCALL;
5946 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5947 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5948 return WINED3DERR_INVALIDCALL;
5951 if(Swapchain->frontBuffer != Front) {
5952 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5954 if(Swapchain->frontBuffer)
5955 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5956 Swapchain->frontBuffer = Front;
5958 if(Swapchain->frontBuffer) {
5959 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5963 if(Back && !Swapchain->backBuffer) {
5964 /* We need memory for the back buffer array - only one back buffer this way */
5965 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5966 if(!Swapchain->backBuffer) {
5967 ERR("Out of memory\n");
5968 return E_OUTOFMEMORY;
5972 if(Swapchain->backBuffer[0] != Back) {
5973 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5975 /* What to do about the context here in the case of multithreading? Not sure.
5976 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5978 ENTER_GL();
5979 if(!Swapchain->backBuffer[0]) {
5980 /* GL was told to draw to the front buffer at creation,
5981 * undo that
5983 glDrawBuffer(GL_BACK);
5984 checkGLcall("glDrawBuffer(GL_BACK)");
5985 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5986 Swapchain->presentParms.BackBufferCount = 1;
5987 } else if (!Back) {
5988 /* That makes problems - disable for now */
5989 /* glDrawBuffer(GL_FRONT); */
5990 checkGLcall("glDrawBuffer(GL_FRONT)");
5991 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5992 Swapchain->presentParms.BackBufferCount = 0;
5994 LEAVE_GL();
5996 if(Swapchain->backBuffer[0])
5997 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5998 Swapchain->backBuffer[0] = Back;
6000 if(Swapchain->backBuffer[0]) {
6001 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6002 } else {
6003 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6008 return WINED3D_OK;
6011 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6013 *ppZStencilSurface = This->depthStencilBuffer;
6014 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6016 if(*ppZStencilSurface != NULL) {
6017 /* Note inc ref on returned surface */
6018 IWineD3DSurface_AddRef(*ppZStencilSurface);
6019 return WINED3D_OK;
6020 } else {
6021 return WINED3DERR_NOTFOUND;
6025 /* TODO: Handle stencil attachments */
6026 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6028 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6030 TRACE("Set depth stencil to %p\n", depth_stencil);
6032 if (depth_stencil_impl) {
6033 if (depth_stencil_impl->current_renderbuffer) {
6034 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6035 checkGLcall("glFramebufferRenderbufferEXT()");
6036 } else {
6037 IWineD3DBaseTextureImpl *texture_impl;
6038 GLenum texttarget, target;
6039 GLint old_binding = 0;
6041 texttarget = depth_stencil_impl->glDescription.target;
6042 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
6043 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6045 IWineD3DSurface_PreLoad(depth_stencil);
6047 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6048 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6049 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6050 glBindTexture(target, old_binding);
6052 /* Update base texture states array */
6053 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6054 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6055 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6056 if (texture_impl->baseTexture.bindCount) {
6057 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6060 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6063 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6064 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6065 checkGLcall("glFramebufferTexture2DEXT()");
6067 } else {
6068 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6069 checkGLcall("glFramebufferTexture2DEXT()");
6073 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6075 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6077 TRACE("Set render target %u to %p\n", idx, render_target);
6079 if (rtimpl) {
6080 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6081 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6082 } else {
6083 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6084 checkGLcall("glFramebufferTexture2DEXT()");
6086 This->draw_buffers[idx] = GL_NONE;
6090 static void check_fbo_status(IWineD3DDevice *iface) {
6091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6092 GLenum status;
6094 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6095 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6096 TRACE("FBO complete\n");
6097 } else {
6098 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6100 /* Dump the FBO attachments */
6101 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
6102 IWineD3DSurfaceImpl *attachment;
6103 int i;
6105 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6106 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6107 if (attachment) {
6108 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6109 attachment->pow2Width, attachment->pow2Height);
6112 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6113 if (attachment) {
6114 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6115 attachment->pow2Width, attachment->pow2Height);
6121 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6123 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6124 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6126 if (!ds_impl) return FALSE;
6128 if (ds_impl->current_renderbuffer) {
6129 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6130 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6133 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6134 rt_impl->pow2Height != ds_impl->pow2Height);
6137 void apply_fbo_state(IWineD3DDevice *iface) {
6138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6139 unsigned int i;
6141 if (This->render_offscreen) {
6142 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6144 /* Apply render targets */
6145 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6146 IWineD3DSurface *render_target = This->render_targets[i];
6147 if (This->fbo_color_attachments[i] != render_target) {
6148 set_render_target_fbo(iface, i, render_target);
6149 This->fbo_color_attachments[i] = render_target;
6153 /* Apply depth targets */
6154 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6155 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6156 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6158 if (This->stencilBufferTarget) {
6159 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6161 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6162 This->fbo_depth_attachment = This->stencilBufferTarget;
6165 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6166 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6167 checkGLcall("glDrawBuffers()");
6168 } else {
6169 glDrawBuffer(This->draw_buffers[0]);
6170 checkGLcall("glDrawBuffer()");
6172 } else {
6173 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6176 check_fbo_status(iface);
6179 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6180 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6182 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6183 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6184 GLenum gl_filter;
6186 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6187 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6188 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6189 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6191 switch (filter) {
6192 case WINED3DTEXF_LINEAR:
6193 gl_filter = GL_LINEAR;
6194 break;
6196 default:
6197 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6198 case WINED3DTEXF_NONE:
6199 case WINED3DTEXF_POINT:
6200 gl_filter = GL_NEAREST;
6201 break;
6204 /* Attach src surface to src fbo */
6205 src_swapchain = get_swapchain(src_surface);
6206 if (src_swapchain) {
6207 GLenum buffer;
6209 TRACE("Source surface %p is onscreen\n", src_surface);
6210 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6212 ENTER_GL();
6213 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6214 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6215 glReadBuffer(buffer);
6216 checkGLcall("glReadBuffer()");
6218 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6219 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6220 } else {
6221 TRACE("Source surface %p is offscreen\n", src_surface);
6222 ENTER_GL();
6223 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6224 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6225 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6226 checkGLcall("glReadBuffer()");
6228 LEAVE_GL();
6230 /* Attach dst surface to dst fbo */
6231 dst_swapchain = get_swapchain(dst_surface);
6232 if (dst_swapchain) {
6233 GLenum buffer;
6235 TRACE("Destination surface %p is onscreen\n", dst_surface);
6236 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6238 ENTER_GL();
6239 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6240 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6241 glDrawBuffer(buffer);
6242 checkGLcall("glDrawBuffer()");
6244 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6245 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6246 } else {
6247 TRACE("Destination surface %p is offscreen\n", dst_surface);
6249 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6250 if(!src_swapchain) {
6251 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6254 ENTER_GL();
6255 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6256 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6257 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6258 checkGLcall("glDrawBuffer()");
6260 glDisable(GL_SCISSOR_TEST);
6261 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6263 if (flip) {
6264 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6265 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6266 checkGLcall("glBlitFramebuffer()");
6267 } else {
6268 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6269 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6270 checkGLcall("glBlitFramebuffer()");
6273 if (This->render_offscreen) {
6274 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6275 } else {
6276 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6277 checkGLcall("glBindFramebuffer()");
6280 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6281 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6282 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6283 glDrawBuffer(GL_BACK);
6284 checkGLcall("glDrawBuffer()");
6286 LEAVE_GL();
6289 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6291 WINED3DVIEWPORT viewport;
6293 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6295 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6296 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6297 return WINED3DERR_INVALIDCALL;
6300 /* MSDN says that null disables the render target
6301 but a device must always be associated with a render target
6302 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6304 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6305 for more details
6307 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6308 FIXME("Trying to set render target 0 to NULL\n");
6309 return WINED3DERR_INVALIDCALL;
6311 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
6312 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);
6313 return WINED3DERR_INVALIDCALL;
6316 /* If we are trying to set what we already have, don't bother */
6317 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6318 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6319 return WINED3D_OK;
6321 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6322 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6323 This->render_targets[RenderTargetIndex] = pRenderTarget;
6325 /* Render target 0 is special */
6326 if(RenderTargetIndex == 0) {
6327 /* Finally, reset the viewport as the MSDN states. */
6328 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6329 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6330 viewport.X = 0;
6331 viewport.Y = 0;
6332 viewport.MaxZ = 1.0f;
6333 viewport.MinZ = 0.0f;
6334 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6335 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6336 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6338 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6340 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6341 * ctx properly.
6342 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6343 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6345 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6347 return WINED3D_OK;
6350 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6352 HRESULT hr = WINED3D_OK;
6353 IWineD3DSurface *tmp;
6355 TRACE("(%p) Swapping z-buffer\n",This);
6357 if (pNewZStencil == This->stencilBufferTarget) {
6358 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6359 } else {
6360 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6361 * depending on the renter target implementation being used.
6362 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6363 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6364 * stencil buffer and incure an extra memory overhead
6365 ******************************************************/
6367 tmp = This->stencilBufferTarget;
6368 This->stencilBufferTarget = pNewZStencil;
6369 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6370 /* should we be calling the parent or the wined3d surface? */
6371 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6372 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6373 hr = WINED3D_OK;
6375 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6376 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6377 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6379 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6383 return hr;
6386 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6387 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6389 /* TODO: the use of Impl is deprecated. */
6390 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6391 WINED3DLOCKED_RECT lockedRect;
6393 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6395 /* some basic validation checks */
6396 if(This->cursorTexture) {
6397 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6398 ENTER_GL();
6399 glDeleteTextures(1, &This->cursorTexture);
6400 LEAVE_GL();
6401 This->cursorTexture = 0;
6404 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6405 This->haveHardwareCursor = TRUE;
6406 else
6407 This->haveHardwareCursor = FALSE;
6409 if(pCursorBitmap) {
6410 WINED3DLOCKED_RECT rect;
6412 /* MSDN: Cursor must be A8R8G8B8 */
6413 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6414 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6415 return WINED3DERR_INVALIDCALL;
6418 /* MSDN: Cursor must be smaller than the display mode */
6419 if(pSur->currentDesc.Width > This->ddraw_width ||
6420 pSur->currentDesc.Height > This->ddraw_height) {
6421 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);
6422 return WINED3DERR_INVALIDCALL;
6425 if (!This->haveHardwareCursor) {
6426 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6428 /* Do not store the surface's pointer because the application may
6429 * release it after setting the cursor image. Windows doesn't
6430 * addref the set surface, so we can't do this either without
6431 * creating circular refcount dependencies. Copy out the gl texture
6432 * instead.
6434 This->cursorWidth = pSur->currentDesc.Width;
6435 This->cursorHeight = pSur->currentDesc.Height;
6436 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6438 const GlPixelFormatDesc *glDesc;
6439 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6440 char *mem, *bits = (char *)rect.pBits;
6441 GLint intfmt = glDesc->glInternal;
6442 GLint format = glDesc->glFormat;
6443 GLint type = glDesc->glType;
6444 INT height = This->cursorHeight;
6445 INT width = This->cursorWidth;
6446 INT bpp = tableEntry->bpp;
6447 INT i;
6449 /* Reformat the texture memory (pitch and width can be
6450 * different) */
6451 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6452 for(i = 0; i < height; i++)
6453 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6454 IWineD3DSurface_UnlockRect(pCursorBitmap);
6455 ENTER_GL();
6457 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6458 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6459 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6462 /* Make sure that a proper texture unit is selected */
6463 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6464 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6465 checkGLcall("glActiveTextureARB");
6467 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6468 /* Create a new cursor texture */
6469 glGenTextures(1, &This->cursorTexture);
6470 checkGLcall("glGenTextures");
6471 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6472 checkGLcall("glBindTexture");
6473 /* Copy the bitmap memory into the cursor texture */
6474 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6475 HeapFree(GetProcessHeap(), 0, mem);
6476 checkGLcall("glTexImage2D");
6478 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6479 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6480 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6483 LEAVE_GL();
6485 else
6487 FIXME("A cursor texture was not returned.\n");
6488 This->cursorTexture = 0;
6491 else
6493 /* Draw a hardware cursor */
6494 ICONINFO cursorInfo;
6495 HCURSOR cursor;
6496 /* Create and clear maskBits because it is not needed for
6497 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6498 * chunks. */
6499 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6500 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6501 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6502 WINED3DLOCK_NO_DIRTY_UPDATE |
6503 WINED3DLOCK_READONLY
6505 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6506 pSur->currentDesc.Height);
6508 cursorInfo.fIcon = FALSE;
6509 cursorInfo.xHotspot = XHotSpot;
6510 cursorInfo.yHotspot = YHotSpot;
6511 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6512 pSur->currentDesc.Height, 1,
6513 1, &maskBits);
6514 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6515 pSur->currentDesc.Height, 1,
6516 32, lockedRect.pBits);
6517 IWineD3DSurface_UnlockRect(pCursorBitmap);
6518 /* Create our cursor and clean up. */
6519 cursor = CreateIconIndirect(&cursorInfo);
6520 SetCursor(cursor);
6521 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6522 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6523 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6524 This->hardwareCursor = cursor;
6525 HeapFree(GetProcessHeap(), 0, maskBits);
6529 This->xHotSpot = XHotSpot;
6530 This->yHotSpot = YHotSpot;
6531 return WINED3D_OK;
6534 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6536 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6538 This->xScreenSpace = XScreenSpace;
6539 This->yScreenSpace = YScreenSpace;
6541 return;
6545 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6547 BOOL oldVisible = This->bCursorVisible;
6548 POINT pt;
6550 TRACE("(%p) : visible(%d)\n", This, bShow);
6553 * When ShowCursor is first called it should make the cursor appear at the OS's last
6554 * known cursor position. Because of this, some applications just repetitively call
6555 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6557 GetCursorPos(&pt);
6558 This->xScreenSpace = pt.x;
6559 This->yScreenSpace = pt.y;
6561 if (This->haveHardwareCursor) {
6562 This->bCursorVisible = bShow;
6563 if (bShow)
6564 SetCursor(This->hardwareCursor);
6565 else
6566 SetCursor(NULL);
6568 else
6570 if (This->cursorTexture)
6571 This->bCursorVisible = bShow;
6574 return oldVisible;
6577 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6579 TRACE("(%p) : state (%u)\n", This, This->state);
6580 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6581 switch (This->state) {
6582 case WINED3D_OK:
6583 return WINED3D_OK;
6584 case WINED3DERR_DEVICELOST:
6586 ResourceList *resourceList = This->resources;
6587 while (NULL != resourceList) {
6588 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6589 return WINED3DERR_DEVICENOTRESET;
6590 resourceList = resourceList->next;
6592 return WINED3DERR_DEVICELOST;
6594 case WINED3DERR_DRIVERINTERNALERROR:
6595 return WINED3DERR_DRIVERINTERNALERROR;
6598 /* Unknown state */
6599 return WINED3DERR_DRIVERINTERNALERROR;
6603 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6605 /** FIXME: Resource tracking needs to be done,
6606 * The closes we can do to this is set the priorities of all managed textures low
6607 * and then reset them.
6608 ***********************************************************/
6609 FIXME("(%p) : stub\n", This);
6610 return WINED3D_OK;
6613 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6614 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6616 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6617 if(surface->Flags & SFLAG_DIBSECTION) {
6618 /* Release the DC */
6619 SelectObject(surface->hDC, surface->dib.holdbitmap);
6620 DeleteDC(surface->hDC);
6621 /* Release the DIB section */
6622 DeleteObject(surface->dib.DIBsection);
6623 surface->dib.bitmap_data = NULL;
6624 surface->resource.allocatedMemory = NULL;
6625 surface->Flags &= ~SFLAG_DIBSECTION;
6627 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6628 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6629 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6630 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6631 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6632 } else {
6633 surface->pow2Width = surface->pow2Height = 1;
6634 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6635 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6637 if(surface->glDescription.textureName) {
6638 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6639 ENTER_GL();
6640 glDeleteTextures(1, &surface->glDescription.textureName);
6641 LEAVE_GL();
6642 surface->glDescription.textureName = 0;
6643 surface->Flags &= ~SFLAG_CLIENT;
6645 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6646 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6647 surface->Flags |= SFLAG_NONPOW2;
6648 } else {
6649 surface->Flags &= ~SFLAG_NONPOW2;
6651 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6652 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6655 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6657 IWineD3DSwapChainImpl *swapchain;
6658 HRESULT hr;
6659 BOOL DisplayModeChanged = FALSE;
6660 WINED3DDISPLAYMODE mode;
6661 TRACE("(%p)\n", This);
6663 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6664 if(FAILED(hr)) {
6665 ERR("Failed to get the first implicit swapchain\n");
6666 return hr;
6669 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6670 * on an existing gl context, so there's no real need for recreation.
6672 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6674 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6676 TRACE("New params:\n");
6677 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6678 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6679 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6680 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6681 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6682 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6683 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6684 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6685 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6686 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6687 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6688 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6689 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6691 /* No special treatment of these parameters. Just store them */
6692 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6693 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6694 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6695 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6697 /* What to do about these? */
6698 if(pPresentationParameters->BackBufferCount != 0 &&
6699 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6700 ERR("Cannot change the back buffer count yet\n");
6702 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6703 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6704 ERR("Cannot change the back buffer format yet\n");
6706 if(pPresentationParameters->hDeviceWindow != NULL &&
6707 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6708 ERR("Cannot change the device window yet\n");
6710 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6711 ERR("What do do about a changed auto depth stencil parameter?\n");
6714 if(pPresentationParameters->Windowed) {
6715 mode.Width = swapchain->orig_width;
6716 mode.Height = swapchain->orig_height;
6717 mode.RefreshRate = 0;
6718 mode.Format = swapchain->presentParms.BackBufferFormat;
6719 } else {
6720 mode.Width = pPresentationParameters->BackBufferWidth;
6721 mode.Height = pPresentationParameters->BackBufferHeight;
6722 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6723 mode.Format = swapchain->presentParms.BackBufferFormat;
6725 SetWindowLongA(swapchain->win_handle, GWL_STYLE, WS_POPUP);
6726 SetWindowPos(swapchain->win_handle, HWND_TOP, 0, 0,
6727 pPresentationParameters->BackBufferWidth,
6728 pPresentationParameters->BackBufferHeight, SWP_SHOWWINDOW | SWP_FRAMECHANGED);
6731 /* Should Width == 800 && Height == 0 set 800x600? */
6732 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6733 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6734 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6736 WINED3DVIEWPORT vp;
6737 int i;
6739 vp.X = 0;
6740 vp.Y = 0;
6741 vp.Width = pPresentationParameters->BackBufferWidth;
6742 vp.Height = pPresentationParameters->BackBufferHeight;
6743 vp.MinZ = 0;
6744 vp.MaxZ = 1;
6746 if(!pPresentationParameters->Windowed) {
6747 DisplayModeChanged = TRUE;
6749 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6750 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6752 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6753 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6754 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6757 /* Now set the new viewport */
6758 IWineD3DDevice_SetViewport(iface, &vp);
6761 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6762 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6763 DisplayModeChanged) {
6765 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6766 if(!pPresentationParameters->Windowed) {
6767 IWineD3DDevice_SetFullscreen(iface, TRUE);
6770 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6772 /* Switching out of fullscreen mode? First set the original res, then change the window */
6773 if(pPresentationParameters->Windowed) {
6774 IWineD3DDevice_SetFullscreen(iface, FALSE);
6776 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6779 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6780 return WINED3D_OK;
6783 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6785 /** FIXME: always true at the moment **/
6786 if(!bEnableDialogs) {
6787 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6789 return WINED3D_OK;
6793 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6795 TRACE("(%p) : pParameters %p\n", This, pParameters);
6797 *pParameters = This->createParms;
6798 return WINED3D_OK;
6801 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6802 IWineD3DSwapChain *swapchain;
6803 HRESULT hrc = WINED3D_OK;
6805 TRACE("Relaying to swapchain\n");
6807 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6808 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6809 IWineD3DSwapChain_Release(swapchain);
6811 return;
6814 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6815 IWineD3DSwapChain *swapchain;
6816 HRESULT hrc = WINED3D_OK;
6818 TRACE("Relaying to swapchain\n");
6820 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6821 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6822 IWineD3DSwapChain_Release(swapchain);
6824 return;
6828 /** ********************************************************
6829 * Notification functions
6830 ** ********************************************************/
6831 /** This function must be called in the release of a resource when ref == 0,
6832 * the contents of resource must still be correct,
6833 * any handels to other resource held by the caller must be closed
6834 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6835 *****************************************************/
6836 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6838 ResourceList* resourceList;
6840 TRACE("(%p) : resource %p\n", This, resource);
6841 /* add a new texture to the frot of the linked list */
6842 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6843 resourceList->resource = resource;
6845 /* Get the old head */
6846 resourceList->next = This->resources;
6848 This->resources = resourceList;
6849 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6851 return;
6854 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6856 ResourceList* resourceList = NULL;
6857 ResourceList* previousResourceList = NULL;
6859 TRACE("(%p) : resource %p\n", This, resource);
6861 resourceList = This->resources;
6863 while (resourceList != NULL) {
6864 if(resourceList->resource == resource) break;
6865 previousResourceList = resourceList;
6866 resourceList = resourceList->next;
6869 if (resourceList == NULL) {
6870 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6871 return;
6872 } else {
6873 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6875 /* make sure we don't leave a hole in the list */
6876 if (previousResourceList != NULL) {
6877 previousResourceList->next = resourceList->next;
6878 } else {
6879 This->resources = resourceList->next;
6882 return;
6886 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6888 int counter;
6890 TRACE("(%p) : resource %p\n", This, resource);
6891 switch(IWineD3DResource_GetType(resource)){
6892 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6893 case WINED3DRTYPE_SURFACE: {
6894 unsigned int i;
6896 /* Cleanup any FBO attachments if d3d is enabled */
6897 if(This->d3d_initialized) {
6898 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
6899 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
6901 TRACE("Last active render target destroyed\n");
6902 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
6903 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
6904 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
6905 * and the lastActiveRenderTarget member shouldn't matter
6907 if(swapchain) {
6908 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
6909 TRACE("Activating primary back buffer\n");
6910 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
6911 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
6912 /* Single buffering environment */
6913 TRACE("Activating primary front buffer\n");
6914 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
6915 } else {
6916 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
6917 /* Implicit render target destroyed, that means the device is being destroyed
6918 * whatever we set here, it shouldn't matter
6920 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
6922 } else {
6923 /* May happen during ddraw uninitialization */
6924 TRACE("Render target set, but swapchain does not exist!\n");
6925 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
6929 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6930 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6931 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6932 set_render_target_fbo(iface, i, NULL);
6933 This->fbo_color_attachments[i] = NULL;
6936 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6937 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6938 set_depth_stencil_fbo(iface, NULL);
6939 This->fbo_depth_attachment = NULL;
6943 break;
6945 case WINED3DRTYPE_TEXTURE:
6946 case WINED3DRTYPE_CUBETEXTURE:
6947 case WINED3DRTYPE_VOLUMETEXTURE:
6948 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6949 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6950 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6951 This->stateBlock->textures[counter] = NULL;
6953 if (This->updateStateBlock != This->stateBlock ){
6954 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6955 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6956 This->updateStateBlock->textures[counter] = NULL;
6960 break;
6961 case WINED3DRTYPE_VOLUME:
6962 /* TODO: nothing really? */
6963 break;
6964 case WINED3DRTYPE_VERTEXBUFFER:
6965 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6967 int streamNumber;
6968 TRACE("Cleaning up stream pointers\n");
6970 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6971 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6972 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6974 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6975 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6976 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6977 This->updateStateBlock->streamSource[streamNumber] = 0;
6978 /* Set changed flag? */
6981 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) */
6982 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6983 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6984 This->stateBlock->streamSource[streamNumber] = 0;
6987 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6988 else { /* This shouldn't happen */
6989 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6991 #endif
6995 break;
6996 case WINED3DRTYPE_INDEXBUFFER:
6997 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6998 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6999 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7000 This->updateStateBlock->pIndexData = NULL;
7003 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7004 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7005 This->stateBlock->pIndexData = NULL;
7009 break;
7010 default:
7011 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7012 break;
7016 /* Remove the resoruce from the resourceStore */
7017 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7019 TRACE("Resource released\n");
7023 /**********************************************************
7024 * IWineD3DDevice VTbl follows
7025 **********************************************************/
7027 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7029 /*** IUnknown methods ***/
7030 IWineD3DDeviceImpl_QueryInterface,
7031 IWineD3DDeviceImpl_AddRef,
7032 IWineD3DDeviceImpl_Release,
7033 /*** IWineD3DDevice methods ***/
7034 IWineD3DDeviceImpl_GetParent,
7035 /*** Creation methods**/
7036 IWineD3DDeviceImpl_CreateVertexBuffer,
7037 IWineD3DDeviceImpl_CreateIndexBuffer,
7038 IWineD3DDeviceImpl_CreateStateBlock,
7039 IWineD3DDeviceImpl_CreateSurface,
7040 IWineD3DDeviceImpl_CreateTexture,
7041 IWineD3DDeviceImpl_CreateVolumeTexture,
7042 IWineD3DDeviceImpl_CreateVolume,
7043 IWineD3DDeviceImpl_CreateCubeTexture,
7044 IWineD3DDeviceImpl_CreateQuery,
7045 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7046 IWineD3DDeviceImpl_CreateVertexDeclaration,
7047 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7048 IWineD3DDeviceImpl_CreateVertexShader,
7049 IWineD3DDeviceImpl_CreatePixelShader,
7050 IWineD3DDeviceImpl_CreatePalette,
7051 /*** Odd functions **/
7052 IWineD3DDeviceImpl_Init3D,
7053 IWineD3DDeviceImpl_Uninit3D,
7054 IWineD3DDeviceImpl_SetFullscreen,
7055 IWineD3DDeviceImpl_SetMultithreaded,
7056 IWineD3DDeviceImpl_EvictManagedResources,
7057 IWineD3DDeviceImpl_GetAvailableTextureMem,
7058 IWineD3DDeviceImpl_GetBackBuffer,
7059 IWineD3DDeviceImpl_GetCreationParameters,
7060 IWineD3DDeviceImpl_GetDeviceCaps,
7061 IWineD3DDeviceImpl_GetDirect3D,
7062 IWineD3DDeviceImpl_GetDisplayMode,
7063 IWineD3DDeviceImpl_SetDisplayMode,
7064 IWineD3DDeviceImpl_GetHWND,
7065 IWineD3DDeviceImpl_SetHWND,
7066 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7067 IWineD3DDeviceImpl_GetRasterStatus,
7068 IWineD3DDeviceImpl_GetSwapChain,
7069 IWineD3DDeviceImpl_Reset,
7070 IWineD3DDeviceImpl_SetDialogBoxMode,
7071 IWineD3DDeviceImpl_SetCursorProperties,
7072 IWineD3DDeviceImpl_SetCursorPosition,
7073 IWineD3DDeviceImpl_ShowCursor,
7074 IWineD3DDeviceImpl_TestCooperativeLevel,
7075 /*** Getters and setters **/
7076 IWineD3DDeviceImpl_SetClipPlane,
7077 IWineD3DDeviceImpl_GetClipPlane,
7078 IWineD3DDeviceImpl_SetClipStatus,
7079 IWineD3DDeviceImpl_GetClipStatus,
7080 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7081 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7082 IWineD3DDeviceImpl_SetDepthStencilSurface,
7083 IWineD3DDeviceImpl_GetDepthStencilSurface,
7084 IWineD3DDeviceImpl_SetFVF,
7085 IWineD3DDeviceImpl_GetFVF,
7086 IWineD3DDeviceImpl_SetGammaRamp,
7087 IWineD3DDeviceImpl_GetGammaRamp,
7088 IWineD3DDeviceImpl_SetIndices,
7089 IWineD3DDeviceImpl_GetIndices,
7090 IWineD3DDeviceImpl_SetBaseVertexIndex,
7091 IWineD3DDeviceImpl_GetBaseVertexIndex,
7092 IWineD3DDeviceImpl_SetLight,
7093 IWineD3DDeviceImpl_GetLight,
7094 IWineD3DDeviceImpl_SetLightEnable,
7095 IWineD3DDeviceImpl_GetLightEnable,
7096 IWineD3DDeviceImpl_SetMaterial,
7097 IWineD3DDeviceImpl_GetMaterial,
7098 IWineD3DDeviceImpl_SetNPatchMode,
7099 IWineD3DDeviceImpl_GetNPatchMode,
7100 IWineD3DDeviceImpl_SetPaletteEntries,
7101 IWineD3DDeviceImpl_GetPaletteEntries,
7102 IWineD3DDeviceImpl_SetPixelShader,
7103 IWineD3DDeviceImpl_GetPixelShader,
7104 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7105 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7106 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7107 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7108 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7109 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7110 IWineD3DDeviceImpl_SetRenderState,
7111 IWineD3DDeviceImpl_GetRenderState,
7112 IWineD3DDeviceImpl_SetRenderTarget,
7113 IWineD3DDeviceImpl_GetRenderTarget,
7114 IWineD3DDeviceImpl_SetFrontBackBuffers,
7115 IWineD3DDeviceImpl_SetSamplerState,
7116 IWineD3DDeviceImpl_GetSamplerState,
7117 IWineD3DDeviceImpl_SetScissorRect,
7118 IWineD3DDeviceImpl_GetScissorRect,
7119 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7120 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7121 IWineD3DDeviceImpl_SetStreamSource,
7122 IWineD3DDeviceImpl_GetStreamSource,
7123 IWineD3DDeviceImpl_SetStreamSourceFreq,
7124 IWineD3DDeviceImpl_GetStreamSourceFreq,
7125 IWineD3DDeviceImpl_SetTexture,
7126 IWineD3DDeviceImpl_GetTexture,
7127 IWineD3DDeviceImpl_SetTextureStageState,
7128 IWineD3DDeviceImpl_GetTextureStageState,
7129 IWineD3DDeviceImpl_SetTransform,
7130 IWineD3DDeviceImpl_GetTransform,
7131 IWineD3DDeviceImpl_SetVertexDeclaration,
7132 IWineD3DDeviceImpl_GetVertexDeclaration,
7133 IWineD3DDeviceImpl_SetVertexShader,
7134 IWineD3DDeviceImpl_GetVertexShader,
7135 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7136 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7137 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7138 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7139 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7140 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7141 IWineD3DDeviceImpl_SetViewport,
7142 IWineD3DDeviceImpl_GetViewport,
7143 IWineD3DDeviceImpl_MultiplyTransform,
7144 IWineD3DDeviceImpl_ValidateDevice,
7145 IWineD3DDeviceImpl_ProcessVertices,
7146 /*** State block ***/
7147 IWineD3DDeviceImpl_BeginStateBlock,
7148 IWineD3DDeviceImpl_EndStateBlock,
7149 /*** Scene management ***/
7150 IWineD3DDeviceImpl_BeginScene,
7151 IWineD3DDeviceImpl_EndScene,
7152 IWineD3DDeviceImpl_Present,
7153 IWineD3DDeviceImpl_Clear,
7154 /*** Drawing ***/
7155 IWineD3DDeviceImpl_DrawPrimitive,
7156 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7157 IWineD3DDeviceImpl_DrawPrimitiveUP,
7158 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7159 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7160 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7161 IWineD3DDeviceImpl_DrawRectPatch,
7162 IWineD3DDeviceImpl_DrawTriPatch,
7163 IWineD3DDeviceImpl_DeletePatch,
7164 IWineD3DDeviceImpl_ColorFill,
7165 IWineD3DDeviceImpl_UpdateTexture,
7166 IWineD3DDeviceImpl_UpdateSurface,
7167 IWineD3DDeviceImpl_GetFrontBufferData,
7168 /*** object tracking ***/
7169 IWineD3DDeviceImpl_ResourceReleased
7173 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7174 WINED3DRS_ALPHABLENDENABLE ,
7175 WINED3DRS_ALPHAFUNC ,
7176 WINED3DRS_ALPHAREF ,
7177 WINED3DRS_ALPHATESTENABLE ,
7178 WINED3DRS_BLENDOP ,
7179 WINED3DRS_COLORWRITEENABLE ,
7180 WINED3DRS_DESTBLEND ,
7181 WINED3DRS_DITHERENABLE ,
7182 WINED3DRS_FILLMODE ,
7183 WINED3DRS_FOGDENSITY ,
7184 WINED3DRS_FOGEND ,
7185 WINED3DRS_FOGSTART ,
7186 WINED3DRS_LASTPIXEL ,
7187 WINED3DRS_SHADEMODE ,
7188 WINED3DRS_SRCBLEND ,
7189 WINED3DRS_STENCILENABLE ,
7190 WINED3DRS_STENCILFAIL ,
7191 WINED3DRS_STENCILFUNC ,
7192 WINED3DRS_STENCILMASK ,
7193 WINED3DRS_STENCILPASS ,
7194 WINED3DRS_STENCILREF ,
7195 WINED3DRS_STENCILWRITEMASK ,
7196 WINED3DRS_STENCILZFAIL ,
7197 WINED3DRS_TEXTUREFACTOR ,
7198 WINED3DRS_WRAP0 ,
7199 WINED3DRS_WRAP1 ,
7200 WINED3DRS_WRAP2 ,
7201 WINED3DRS_WRAP3 ,
7202 WINED3DRS_WRAP4 ,
7203 WINED3DRS_WRAP5 ,
7204 WINED3DRS_WRAP6 ,
7205 WINED3DRS_WRAP7 ,
7206 WINED3DRS_ZENABLE ,
7207 WINED3DRS_ZFUNC ,
7208 WINED3DRS_ZWRITEENABLE
7211 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7212 WINED3DTSS_ADDRESSW ,
7213 WINED3DTSS_ALPHAARG0 ,
7214 WINED3DTSS_ALPHAARG1 ,
7215 WINED3DTSS_ALPHAARG2 ,
7216 WINED3DTSS_ALPHAOP ,
7217 WINED3DTSS_BUMPENVLOFFSET ,
7218 WINED3DTSS_BUMPENVLSCALE ,
7219 WINED3DTSS_BUMPENVMAT00 ,
7220 WINED3DTSS_BUMPENVMAT01 ,
7221 WINED3DTSS_BUMPENVMAT10 ,
7222 WINED3DTSS_BUMPENVMAT11 ,
7223 WINED3DTSS_COLORARG0 ,
7224 WINED3DTSS_COLORARG1 ,
7225 WINED3DTSS_COLORARG2 ,
7226 WINED3DTSS_COLOROP ,
7227 WINED3DTSS_RESULTARG ,
7228 WINED3DTSS_TEXCOORDINDEX ,
7229 WINED3DTSS_TEXTURETRANSFORMFLAGS
7232 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7233 WINED3DSAMP_ADDRESSU ,
7234 WINED3DSAMP_ADDRESSV ,
7235 WINED3DSAMP_ADDRESSW ,
7236 WINED3DSAMP_BORDERCOLOR ,
7237 WINED3DSAMP_MAGFILTER ,
7238 WINED3DSAMP_MINFILTER ,
7239 WINED3DSAMP_MIPFILTER ,
7240 WINED3DSAMP_MIPMAPLODBIAS ,
7241 WINED3DSAMP_MAXMIPLEVEL ,
7242 WINED3DSAMP_MAXANISOTROPY ,
7243 WINED3DSAMP_SRGBTEXTURE ,
7244 WINED3DSAMP_ELEMENTINDEX
7247 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7248 WINED3DRS_AMBIENT ,
7249 WINED3DRS_AMBIENTMATERIALSOURCE ,
7250 WINED3DRS_CLIPPING ,
7251 WINED3DRS_CLIPPLANEENABLE ,
7252 WINED3DRS_COLORVERTEX ,
7253 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7254 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7255 WINED3DRS_FOGDENSITY ,
7256 WINED3DRS_FOGEND ,
7257 WINED3DRS_FOGSTART ,
7258 WINED3DRS_FOGTABLEMODE ,
7259 WINED3DRS_FOGVERTEXMODE ,
7260 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7261 WINED3DRS_LIGHTING ,
7262 WINED3DRS_LOCALVIEWER ,
7263 WINED3DRS_MULTISAMPLEANTIALIAS ,
7264 WINED3DRS_MULTISAMPLEMASK ,
7265 WINED3DRS_NORMALIZENORMALS ,
7266 WINED3DRS_PATCHEDGESTYLE ,
7267 WINED3DRS_POINTSCALE_A ,
7268 WINED3DRS_POINTSCALE_B ,
7269 WINED3DRS_POINTSCALE_C ,
7270 WINED3DRS_POINTSCALEENABLE ,
7271 WINED3DRS_POINTSIZE ,
7272 WINED3DRS_POINTSIZE_MAX ,
7273 WINED3DRS_POINTSIZE_MIN ,
7274 WINED3DRS_POINTSPRITEENABLE ,
7275 WINED3DRS_RANGEFOGENABLE ,
7276 WINED3DRS_SPECULARMATERIALSOURCE ,
7277 WINED3DRS_TWEENFACTOR ,
7278 WINED3DRS_VERTEXBLEND ,
7279 WINED3DRS_CULLMODE ,
7280 WINED3DRS_FOGCOLOR
7283 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7284 WINED3DTSS_TEXCOORDINDEX ,
7285 WINED3DTSS_TEXTURETRANSFORMFLAGS
7288 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7289 WINED3DSAMP_DMAPOFFSET
7292 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7293 DWORD rep = StateTable[state].representative;
7294 DWORD idx;
7295 BYTE shift;
7296 UINT i;
7297 WineD3DContext *context;
7299 if(!rep) return;
7300 for(i = 0; i < This->numContexts; i++) {
7301 context = This->contexts[i];
7302 if(isStateDirty(context, rep)) continue;
7304 context->dirtyArray[context->numDirtyEntries++] = rep;
7305 idx = rep >> 5;
7306 shift = rep & 0x1f;
7307 context->isStateDirty[idx] |= (1 << shift);