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
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 */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
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; \
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; \
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); \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 globalChangeGlRam(_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); \
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);
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);
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);
166 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
169 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_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);
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);
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");
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);
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);
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);
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;
262 case WINED3DUSAGE_WRITEONLY:
264 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
265 glUsage = GL_DYNAMIC_DRAW_ARB;
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);
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));
288 object->Flags |= VBFLAG_VBOCREATEFAIL;
293 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
294 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
297 IWineD3DVertexBufferImpl *object;
298 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
299 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
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);
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
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) ) {
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);
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);
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);
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);
381 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
385 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
386 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
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;
416 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
419 IWineD3DStateBlockImpl *object;
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 */
438 temp_result = allocate_shader_constants(object);
439 if (WINED3D_OK != 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);
446 memset(object->streamFreq, 1, sizeof(object->streamFreq));
448 /* Reset the ref and type after kludging it */
449 object->wineD3DDevice = This;
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++) {
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 } else if (Type == WINED3DSBT_PIXELSTATE) {
519 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
520 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
522 object->changed.pixelShader = TRUE;
524 /* Pixel Shader Constants */
525 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
526 object->contained_ps_consts_f[i] = i;
527 object->changed.pixelShaderConstantsF[i] = TRUE;
529 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
530 for (i = 0; i < MAX_CONST_B; ++i) {
531 object->contained_ps_consts_b[i] = i;
532 object->changed.pixelShaderConstantsB[i] = TRUE;
534 object->num_contained_ps_consts_b = MAX_CONST_B;
535 for (i = 0; i < MAX_CONST_I; ++i) {
536 object->contained_ps_consts_i[i] = i;
537 object->changed.pixelShaderConstantsI[i] = TRUE;
539 object->num_contained_ps_consts_i = MAX_CONST_I;
541 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
542 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
543 object->contained_render_states[i] = SavedPixelStates_R[i];
545 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
546 for (j = 0; j < MAX_TEXTURES; j++) {
547 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
548 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
549 object->contained_tss_states[object->num_contained_tss_states].stage = j;
550 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
551 object->num_contained_tss_states++;
554 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
555 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
556 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
557 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
558 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
559 object->num_contained_sampler_states++;
563 } else if (Type == WINED3DSBT_VERTEXSTATE) {
565 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
566 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
568 object->changed.vertexShader = TRUE;
570 /* Vertex Shader Constants */
571 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
572 object->changed.vertexShaderConstantsF[i] = TRUE;
573 object->contained_vs_consts_f[i] = i;
575 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
576 for (i = 0; i < MAX_CONST_B; ++i) {
577 object->changed.vertexShaderConstantsB[i] = TRUE;
578 object->contained_vs_consts_b[i] = i;
580 object->num_contained_vs_consts_b = MAX_CONST_B;
581 for (i = 0; i < MAX_CONST_I; ++i) {
582 object->changed.vertexShaderConstantsI[i] = TRUE;
583 object->contained_vs_consts_i[i] = i;
585 object->num_contained_vs_consts_i = MAX_CONST_I;
586 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
587 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
588 object->contained_render_states[i] = SavedVertexStates_R[i];
590 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
591 for (j = 0; j < MAX_TEXTURES; j++) {
592 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
593 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
594 object->contained_tss_states[object->num_contained_tss_states].stage = j;
595 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
596 object->num_contained_tss_states++;
599 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
600 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
601 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
602 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
603 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
604 object->num_contained_sampler_states++;
608 for(j = 0; j < LIGHTMAP_SIZE; j++) {
610 LIST_FOR_EACH(e, &object->lightMap[j]) {
611 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
612 light->changed = TRUE;
613 light->enabledChanged = TRUE;
617 FIXME("Unrecognized state block type %d\n", Type);
620 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
624 /* ************************************
626 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
629 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
631 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.
633 ******************************** */
635 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) {
636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
637 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
638 unsigned int Size = 1;
639 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
640 TRACE("(%p) Create surface\n",This);
642 /** FIXME: Check ranges on the inputs are valid
645 * [in] Quality level. The valid range is between zero and one less than the level
646 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
647 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
648 * values of paired render targets, depth stencil surfaces, and the MultiSample type
650 *******************************/
655 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
657 * If this flag is set, the contents of the depth stencil buffer will be
658 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
659 * with a different depth surface.
661 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
662 ***************************/
664 if(MultisampleQuality < 0) {
665 FIXME("Invalid multisample level %d\n", MultisampleQuality);
666 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
669 if(MultisampleQuality > 0) {
670 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
671 MultisampleQuality=0;
674 /** FIXME: Check that the format is supported
676 *******************************/
678 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
679 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
681 *********************************/
682 if (WINED3DFMT_UNKNOWN == Format) {
684 } else if (Format == WINED3DFMT_DXT1) {
685 /* DXT1 is half byte per pixel */
686 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
688 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
689 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
690 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
692 /* The pitch is a multiple of 4 bytes */
693 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
697 /** Create and initialise the surface resource **/
698 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
699 /* "Standalone" surface */
700 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
702 object->currentDesc.Width = Width;
703 object->currentDesc.Height = Height;
704 object->currentDesc.MultiSampleType = MultiSample;
705 object->currentDesc.MultiSampleQuality = MultisampleQuality;
706 object->glDescription.level = Level;
710 object->Flags |= Discard ? SFLAG_DISCARD : 0;
711 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
712 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
715 if (WINED3DFMT_UNKNOWN != Format) {
716 object->bytesPerPixel = tableEntry->bpp;
718 object->bytesPerPixel = 0;
721 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
723 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
725 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
726 * this function is too deep to need to care about things like this.
727 * Levels need to be checked too, and possibly Type since they all affect what can be done.
728 * ****************************************/
730 case WINED3DPOOL_SCRATCH:
732 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
733 "which are mutually exclusive, setting lockable to TRUE\n");
736 case WINED3DPOOL_SYSTEMMEM:
737 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
738 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
739 case WINED3DPOOL_MANAGED:
740 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
741 "Usage of DYNAMIC which are mutually exclusive, not doing "
742 "anything just telling you.\n");
744 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
745 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
746 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
747 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
750 FIXME("(%p) Unknown pool %d\n", This, Pool);
754 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
755 FIXME("Trying to create a render target that isn't in the default pool\n");
758 /* mark the texture as dirty so that it gets loaded first time around*/
759 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
760 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
761 This, Width, Height, Format, debug_d3dformat(Format),
762 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
764 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
765 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
766 This->ddraw_primary = (IWineD3DSurface *) object;
768 /* Look at the implementation and set the correct Vtable */
771 /* Check if a 3D adapter is available when creating gl surfaces */
773 ERR("OpenGL surfaces are not available without opengl\n");
774 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
775 HeapFree(GetProcessHeap(), 0, object);
776 return WINED3DERR_NOTAVAILABLE;
781 object->lpVtbl = &IWineGDISurface_Vtbl;
785 /* To be sure to catch this */
786 ERR("Unknown requested surface implementation %d!\n", Impl);
787 IWineD3DSurface_Release((IWineD3DSurface *) object);
788 return WINED3DERR_INVALIDCALL;
791 list_init(&object->renderbuffers);
793 /* Call the private setup routine */
794 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
798 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
799 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
800 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
801 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
804 IWineD3DTextureImpl *object;
809 unsigned int pow2Width;
810 unsigned int pow2Height;
813 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
814 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
815 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
817 /* TODO: It should only be possible to create textures for formats
818 that are reported as supported */
819 if (WINED3DFMT_UNKNOWN >= Format) {
820 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
821 return WINED3DERR_INVALIDCALL;
824 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
825 D3DINITIALIZEBASETEXTURE(object->baseTexture);
826 object->width = Width;
827 object->height = Height;
829 /** Non-power2 support **/
830 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
834 /* Find the nearest pow2 match */
835 pow2Width = pow2Height = 1;
836 while (pow2Width < Width) pow2Width <<= 1;
837 while (pow2Height < Height) pow2Height <<= 1;
840 /** FIXME: add support for real non-power-two if it's provided by the video card **/
841 /* Precalculated scaling for 'faked' non power of two texture coords */
842 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
843 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
844 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
846 /* Calculate levels for mip mapping */
848 TRACE("calculating levels %d\n", object->baseTexture.levels);
849 object->baseTexture.levels++;
852 while (tmpW > 1 || tmpH > 1) {
853 tmpW = max(1, tmpW >> 1);
854 tmpH = max(1, tmpH >> 1);
855 object->baseTexture.levels++;
857 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
860 /* Generate all the surfaces */
863 for (i = 0; i < object->baseTexture.levels; i++)
865 /* use the callback to create the texture surface */
866 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
867 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
868 FIXME("Failed to create surface %p\n", object);
870 object->surfaces[i] = NULL;
871 IWineD3DTexture_Release((IWineD3DTexture *)object);
877 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
878 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
879 /* calculate the next mipmap level */
880 tmpW = max(1, tmpW >> 1);
881 tmpH = max(1, tmpH >> 1);
884 TRACE("(%p) : Created texture %p\n", This, object);
888 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
889 UINT Width, UINT Height, UINT Depth,
890 UINT Levels, DWORD Usage,
891 WINED3DFORMAT Format, WINED3DPOOL Pool,
892 IWineD3DVolumeTexture **ppVolumeTexture,
893 HANDLE *pSharedHandle, IUnknown *parent,
894 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
897 IWineD3DVolumeTextureImpl *object;
903 /* TODO: It should only be possible to create textures for formats
904 that are reported as supported */
905 if (WINED3DFMT_UNKNOWN >= Format) {
906 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
907 return WINED3DERR_INVALIDCALL;
910 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
911 D3DINITIALIZEBASETEXTURE(object->baseTexture);
913 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
914 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
916 object->width = Width;
917 object->height = Height;
918 object->depth = Depth;
920 /* Calculate levels for mip mapping */
922 object->baseTexture.levels++;
926 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
927 tmpW = max(1, tmpW >> 1);
928 tmpH = max(1, tmpH >> 1);
929 tmpD = max(1, tmpD >> 1);
930 object->baseTexture.levels++;
932 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
935 /* Generate all the surfaces */
940 for (i = 0; i < object->baseTexture.levels; i++)
943 /* Create the volume */
944 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
945 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
948 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
949 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
950 *ppVolumeTexture = NULL;
954 /* Set its container to this object */
955 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
957 /* calcualte the next mipmap level */
958 tmpW = max(1, tmpW >> 1);
959 tmpH = max(1, tmpH >> 1);
960 tmpD = max(1, tmpD >> 1);
963 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
964 TRACE("(%p) : Created volume texture %p\n", This, object);
968 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
969 UINT Width, UINT Height, UINT Depth,
971 WINED3DFORMAT Format, WINED3DPOOL Pool,
972 IWineD3DVolume** ppVolume,
973 HANDLE* pSharedHandle, IUnknown *parent) {
975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
976 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
977 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
979 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
981 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
982 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
984 object->currentDesc.Width = Width;
985 object->currentDesc.Height = Height;
986 object->currentDesc.Depth = Depth;
987 object->bytesPerPixel = formatDesc->bpp;
989 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
990 object->lockable = TRUE;
991 object->locked = FALSE;
992 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
993 object->dirty = TRUE;
995 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
998 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
999 UINT Levels, DWORD Usage,
1000 WINED3DFORMAT Format, WINED3DPOOL Pool,
1001 IWineD3DCubeTexture **ppCubeTexture,
1002 HANDLE *pSharedHandle, IUnknown *parent,
1003 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1006 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1010 unsigned int pow2EdgeLength = EdgeLength;
1012 /* TODO: It should only be possible to create textures for formats
1013 that are reported as supported */
1014 if (WINED3DFMT_UNKNOWN >= Format) {
1015 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1016 return WINED3DERR_INVALIDCALL;
1019 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1020 WARN("(%p) : Tried to create not supported cube texture\n", This);
1021 return WINED3DERR_INVALIDCALL;
1024 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1025 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1027 TRACE("(%p) Create Cube Texture\n", This);
1029 /** Non-power2 support **/
1031 /* Find the nearest pow2 match */
1033 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1035 object->edgeLength = EdgeLength;
1036 /* TODO: support for native non-power 2 */
1037 /* Precalculated scaling for 'faked' non power of two texture coords */
1038 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1040 /* Calculate levels for mip mapping */
1042 object->baseTexture.levels++;
1045 tmpW = max(1, tmpW >> 1);
1046 object->baseTexture.levels++;
1048 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1051 /* Generate all the surfaces */
1053 for (i = 0; i < object->baseTexture.levels; i++) {
1055 /* Create the 6 faces */
1056 for (j = 0; j < 6; j++) {
1058 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1059 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1061 if(hr!= WINED3D_OK) {
1065 for (l = 0; l < j; l++) {
1066 IWineD3DSurface_Release(object->surfaces[j][i]);
1068 for (k = 0; k < i; k++) {
1069 for (l = 0; l < 6; l++) {
1070 IWineD3DSurface_Release(object->surfaces[l][j]);
1074 FIXME("(%p) Failed to create surface\n",object);
1075 HeapFree(GetProcessHeap(),0,object);
1076 *ppCubeTexture = NULL;
1079 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1080 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1082 tmpW = max(1, tmpW >> 1);
1085 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1086 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1090 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1092 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1093 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1095 /* Just a check to see if we support this type of query */
1097 case WINED3DQUERYTYPE_OCCLUSION:
1098 TRACE("(%p) occlusion query\n", This);
1099 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1102 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1105 case WINED3DQUERYTYPE_EVENT:
1106 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1107 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1108 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1110 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1115 case WINED3DQUERYTYPE_VCACHE:
1116 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1117 case WINED3DQUERYTYPE_VERTEXSTATS:
1118 case WINED3DQUERYTYPE_TIMESTAMP:
1119 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1120 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1121 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1122 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1123 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1124 case WINED3DQUERYTYPE_PIXELTIMINGS:
1125 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1126 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1128 FIXME("(%p) Unhandled query type %d\n", This, Type);
1130 if(NULL == ppQuery || hr != WINED3D_OK) {
1134 D3DCREATEOBJECTINSTANCE(object, Query)
1135 object->type = Type;
1136 /* allocated the 'extended' data based on the type of query requested */
1138 case WINED3DQUERYTYPE_OCCLUSION:
1139 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1140 TRACE("(%p) Allocating data for an occlusion query\n", This);
1141 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1142 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1145 case WINED3DQUERYTYPE_EVENT:
1146 /* TODO: GL_APPLE_fence */
1147 if(GL_SUPPORT(APPLE_FENCE)) {
1148 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1149 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1150 checkGLcall("glGenFencesAPPLE");
1151 } else if(GL_SUPPORT(NV_FENCE)) {
1152 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1153 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1154 checkGLcall("glGenFencesNV");
1158 case WINED3DQUERYTYPE_VCACHE:
1159 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1160 case WINED3DQUERYTYPE_VERTEXSTATS:
1161 case WINED3DQUERYTYPE_TIMESTAMP:
1162 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1163 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1164 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1165 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1166 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1167 case WINED3DQUERYTYPE_PIXELTIMINGS:
1168 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1169 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1171 object->extendedData = 0;
1172 FIXME("(%p) Unhandled query type %d\n",This , Type);
1174 TRACE("(%p) : Created Query %p\n", This, object);
1178 /*****************************************************************************
1179 * IWineD3DDeviceImpl_SetupFullscreenWindow
1181 * Helper function that modifies a HWND's Style and ExStyle for proper
1185 * iface: Pointer to the IWineD3DDevice interface
1186 * window: Window to setup
1188 *****************************************************************************/
1189 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1192 LONG style, exStyle;
1193 /* Don't do anything if an original style is stored.
1194 * That shouldn't happen
1196 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1197 if (This->style || This->exStyle) {
1198 ERR("(%p): Want to change the window parameters of HWND %p, but "
1199 "another style is stored for restoration afterwards\n", This, window);
1202 /* Get the parameters and save them */
1203 style = GetWindowLongW(window, GWL_STYLE);
1204 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1205 This->style = style;
1206 This->exStyle = exStyle;
1208 /* Filter out window decorations */
1209 style &= ~WS_CAPTION;
1210 style &= ~WS_THICKFRAME;
1211 exStyle &= ~WS_EX_WINDOWEDGE;
1212 exStyle &= ~WS_EX_CLIENTEDGE;
1214 /* Make sure the window is managed, otherwise we won't get keyboard input */
1215 style |= WS_POPUP | WS_SYSMENU;
1217 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1218 This->style, This->exStyle, style, exStyle);
1220 SetWindowLongW(window, GWL_STYLE, style);
1221 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1223 /* Inform the window about the update. */
1224 SetWindowPos(window, HWND_TOP, 0, 0,
1225 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1226 ShowWindow(window, SW_NORMAL);
1229 /*****************************************************************************
1230 * IWineD3DDeviceImpl_RestoreWindow
1232 * Helper function that restores a windows' properties when taking it out
1233 * of fullscreen mode
1236 * iface: Pointer to the IWineD3DDevice interface
1237 * window: Window to setup
1239 *****************************************************************************/
1240 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1243 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1244 * switch, do nothing
1246 if (!This->style && !This->exStyle) return;
1248 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1249 This, window, This->style, This->exStyle);
1251 SetWindowLongW(window, GWL_STYLE, This->style);
1252 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1254 /* Delete the old values */
1258 /* Inform the window about the update */
1259 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1260 0, 0, 0, 0, /* Pos, Size, ignored */
1261 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1264 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1265 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1267 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1268 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1272 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1273 HRESULT hr = WINED3D_OK;
1274 IUnknown *bufferParent;
1276 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1278 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1279 * does a device hold a reference to a swap chain giving them a lifetime of the device
1280 * or does the swap chain notify the device of its destruction.
1281 *******************************/
1283 /* Check the params */
1284 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1285 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1286 return WINED3DERR_INVALIDCALL;
1287 } else if (pPresentationParameters->BackBufferCount > 1) {
1288 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");
1291 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1293 /*********************
1294 * Lookup the window Handle and the relating X window handle
1295 ********************/
1297 /* Setup hwnd we are using, plus which display this equates to */
1298 object->win_handle = pPresentationParameters->hDeviceWindow;
1299 if (!object->win_handle) {
1300 object->win_handle = This->createParms.hFocusWindow;
1303 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1304 hDc = GetDC(object->win_handle);
1305 TRACE("Using hDc %p\n", hDc);
1308 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1309 return WINED3DERR_NOTAVAILABLE;
1312 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1313 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1314 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1315 ReleaseDC(object->win_handle, hDc);
1317 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1318 * then the corresponding dimension of the client area of the hDeviceWindow
1319 * (or the focus window, if hDeviceWindow is NULL) is taken.
1320 **********************/
1322 if (pPresentationParameters->Windowed &&
1323 ((pPresentationParameters->BackBufferWidth == 0) ||
1324 (pPresentationParameters->BackBufferHeight == 0))) {
1327 GetClientRect(object->win_handle, &Rect);
1329 if (pPresentationParameters->BackBufferWidth == 0) {
1330 pPresentationParameters->BackBufferWidth = Rect.right;
1331 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1333 if (pPresentationParameters->BackBufferHeight == 0) {
1334 pPresentationParameters->BackBufferHeight = Rect.bottom;
1335 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1339 /* Put the correct figures in the presentation parameters */
1340 TRACE("Copying across presentation parameters\n");
1341 object->presentParms = *pPresentationParameters;
1343 TRACE("calling rendertarget CB\n");
1344 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1346 object->presentParms.BackBufferWidth,
1347 object->presentParms.BackBufferHeight,
1348 object->presentParms.BackBufferFormat,
1349 object->presentParms.MultiSampleType,
1350 object->presentParms.MultiSampleQuality,
1351 TRUE /* Lockable */,
1352 &object->frontBuffer,
1353 NULL /* pShared (always null)*/);
1354 if (object->frontBuffer != NULL) {
1355 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1357 ERR("Failed to create the front buffer\n");
1362 * Create an opengl context for the display visual
1363 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1364 * use different properties after that point in time. FIXME: How to handle when requested format
1365 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1366 * it chooses is identical to the one already being used!
1367 **********************************/
1368 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1370 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1371 if(!object->context)
1372 return E_OUTOFMEMORY;
1373 object->num_contexts = 1;
1376 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1379 if (!object->context[0]) {
1380 ERR("Failed to create a new context\n");
1381 hr = WINED3DERR_NOTAVAILABLE;
1384 TRACE("Context created (HWND=%p, glContext=%p)\n",
1385 object->win_handle, object->context[0]->glCtx);
1388 /*********************
1389 * Windowed / Fullscreen
1390 *******************/
1393 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1394 * so we should really check to see if there is a fullscreen swapchain already
1395 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1396 **************************************/
1398 if (!pPresentationParameters->Windowed) {
1405 /* Get info on the current display setup */
1407 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1410 /* Change the display settings */
1411 memset(&devmode, 0, sizeof(devmode));
1412 devmode.dmSize = sizeof(devmode);
1413 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1414 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1415 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1416 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1417 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1419 /* For GetDisplayMode */
1420 This->ddraw_width = devmode.dmPelsWidth;
1421 This->ddraw_height = devmode.dmPelsHeight;
1422 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1424 IWineD3DDevice_SetFullscreen(iface, TRUE);
1426 /* And finally clip mouse to our screen */
1427 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1428 ClipCursor(&clip_rc);
1431 /*********************
1432 * Create the back, front and stencil buffers
1433 *******************/
1434 if(object->presentParms.BackBufferCount > 0) {
1437 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1438 if(!object->backBuffer) {
1439 ERR("Out of memory\n");
1444 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1445 TRACE("calling rendertarget CB\n");
1446 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1448 object->presentParms.BackBufferWidth,
1449 object->presentParms.BackBufferHeight,
1450 object->presentParms.BackBufferFormat,
1451 object->presentParms.MultiSampleType,
1452 object->presentParms.MultiSampleQuality,
1453 TRUE /* Lockable */,
1454 &object->backBuffer[i],
1455 NULL /* pShared (always null)*/);
1456 if(hr == WINED3D_OK && object->backBuffer[i]) {
1457 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1459 ERR("Cannot create new back buffer\n");
1463 glDrawBuffer(GL_BACK);
1464 checkGLcall("glDrawBuffer(GL_BACK)");
1468 object->backBuffer = NULL;
1470 /* Single buffering - draw to front buffer */
1472 glDrawBuffer(GL_FRONT);
1473 checkGLcall("glDrawBuffer(GL_FRONT)");
1477 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1478 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1479 TRACE("Creating depth stencil buffer\n");
1480 if (This->depthStencilBuffer == NULL ) {
1481 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1483 object->presentParms.BackBufferWidth,
1484 object->presentParms.BackBufferHeight,
1485 object->presentParms.AutoDepthStencilFormat,
1486 object->presentParms.MultiSampleType,
1487 object->presentParms.MultiSampleQuality,
1488 FALSE /* FIXME: Discard */,
1489 &This->depthStencilBuffer,
1490 NULL /* pShared (always null)*/ );
1491 if (This->depthStencilBuffer != NULL)
1492 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1495 /** TODO: A check on width, height and multisample types
1496 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1497 ****************************/
1498 object->wantsDepthStencilBuffer = TRUE;
1500 object->wantsDepthStencilBuffer = FALSE;
1503 TRACE("Created swapchain %p\n", object);
1504 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1508 if (object->backBuffer) {
1510 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1511 if(object->backBuffer[i]) {
1512 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1513 IUnknown_Release(bufferParent); /* once for the get parent */
1514 if (IUnknown_Release(bufferParent) > 0) {
1515 FIXME("(%p) Something's still holding the back buffer\n",This);
1519 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1520 object->backBuffer = NULL;
1522 if(object->context[0])
1523 DestroyContext(This, object->context[0]);
1524 if(object->frontBuffer) {
1525 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1526 IUnknown_Release(bufferParent); /* once for the get parent */
1527 if (IUnknown_Release(bufferParent) > 0) {
1528 FIXME("(%p) Something's still holding the front buffer\n",This);
1531 HeapFree(GetProcessHeap(), 0, object);
1535 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1536 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1538 TRACE("(%p)\n", This);
1540 return This->NumberOfSwapChains;
1543 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1545 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1547 if(iSwapChain < This->NumberOfSwapChains) {
1548 *pSwapChain = This->swapchains[iSwapChain];
1549 IWineD3DSwapChain_AddRef(*pSwapChain);
1550 TRACE("(%p) returning %p\n", This, *pSwapChain);
1553 TRACE("Swapchain out of range\n");
1555 return WINED3DERR_INVALIDCALL;
1560 * Vertex Declaration
1562 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1563 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1565 IWineD3DVertexDeclarationImpl *object = NULL;
1566 HRESULT hr = WINED3D_OK;
1568 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1569 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1571 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1573 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1578 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1580 unsigned int idx, idx2;
1581 unsigned int offset;
1582 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1583 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1584 BOOL has_blend_idx = has_blend &&
1585 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1586 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1587 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1588 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1589 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1590 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1591 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1593 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1594 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1596 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1597 WINED3DVERTEXELEMENT *elements = NULL;
1600 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1601 if (has_blend_idx) num_blends--;
1603 /* Compute declaration size */
1604 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1605 has_psize + has_diffuse + has_specular + num_textures + 1;
1607 /* convert the declaration */
1608 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1612 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1615 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1616 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1617 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1620 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1621 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1623 elements[idx].UsageIndex = 0;
1626 if (has_blend && (num_blends > 0)) {
1627 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1628 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1630 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1631 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1632 elements[idx].UsageIndex = 0;
1635 if (has_blend_idx) {
1636 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1637 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1638 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1639 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1640 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1642 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1643 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1644 elements[idx].UsageIndex = 0;
1648 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1649 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1650 elements[idx].UsageIndex = 0;
1654 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1655 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1656 elements[idx].UsageIndex = 0;
1660 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1661 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1662 elements[idx].UsageIndex = 0;
1666 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1667 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1668 elements[idx].UsageIndex = 1;
1671 for (idx2 = 0; idx2 < num_textures; idx2++) {
1672 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1673 switch (numcoords) {
1674 case WINED3DFVF_TEXTUREFORMAT1:
1675 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1677 case WINED3DFVF_TEXTUREFORMAT2:
1678 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1680 case WINED3DFVF_TEXTUREFORMAT3:
1681 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1683 case WINED3DFVF_TEXTUREFORMAT4:
1684 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1687 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1688 elements[idx].UsageIndex = idx2;
1692 /* Now compute offsets, and initialize the rest of the fields */
1693 for (idx = 0, offset = 0; idx < size-1; idx++) {
1694 elements[idx].Stream = 0;
1695 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1696 elements[idx].Offset = offset;
1697 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1700 *ppVertexElements = elements;
1704 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1705 WINED3DVERTEXELEMENT* elements = NULL;
1709 size = ConvertFvfToDeclaration(Fvf, &elements);
1710 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1712 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1713 HeapFree(GetProcessHeap(), 0, elements);
1714 if (hr != S_OK) return hr;
1719 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1720 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1722 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1723 HRESULT hr = WINED3D_OK;
1724 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1725 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1727 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1729 if (vertex_declaration) {
1730 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1733 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1735 if (WINED3D_OK != hr) {
1736 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1737 IWineD3DVertexShader_Release(*ppVertexShader);
1738 return WINED3DERR_INVALIDCALL;
1744 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1746 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1747 HRESULT hr = WINED3D_OK;
1749 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1750 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1751 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1752 if (WINED3D_OK == hr) {
1753 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1755 WARN("(%p) : Failed to create pixel shader\n", This);
1761 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1763 IWineD3DPaletteImpl *object;
1765 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1767 /* Create the new object */
1768 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1770 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1771 return E_OUTOFMEMORY;
1774 object->lpVtbl = &IWineD3DPalette_Vtbl;
1776 object->Flags = Flags;
1777 object->parent = Parent;
1778 object->wineD3DDevice = This;
1779 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1781 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1784 HeapFree( GetProcessHeap(), 0, object);
1785 return E_OUTOFMEMORY;
1788 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1790 IWineD3DPalette_Release((IWineD3DPalette *) object);
1794 *Palette = (IWineD3DPalette *) object;
1799 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1801 IWineD3DSwapChainImpl *swapchain;
1805 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1806 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1808 /* TODO: Test if OpenGL is compiled in and loaded */
1810 TRACE("(%p) : Creating stateblock\n", This);
1811 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1812 hr = IWineD3DDevice_CreateStateBlock(iface,
1814 (IWineD3DStateBlock **)&This->stateBlock,
1816 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1817 WARN("Failed to create stateblock\n");
1820 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1821 This->updateStateBlock = This->stateBlock;
1822 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1824 hr = allocate_shader_constants(This->updateStateBlock);
1825 if (WINED3D_OK != hr)
1828 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1829 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1830 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1832 /* Initialize the texture unit mapping to a 1:1 mapping */
1833 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1834 if (state < GL_LIMITS(fragment_samplers)) {
1835 This->texUnitMap[state] = state;
1836 This->rev_tex_unit_map[state] = state;
1838 This->texUnitMap[state] = -1;
1839 This->rev_tex_unit_map[state] = -1;
1843 /* Setup the implicit swapchain */
1844 TRACE("Creating implicit swapchain\n");
1845 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1846 if (FAILED(hr) || !swapchain) {
1847 WARN("Failed to create implicit swapchain\n");
1851 This->NumberOfSwapChains = 1;
1852 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1853 if(!This->swapchains) {
1854 ERR("Out of memory!\n");
1855 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1856 return E_OUTOFMEMORY;
1858 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1860 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1862 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1863 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1864 This->render_targets[0] = swapchain->backBuffer[0];
1865 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1868 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1869 This->render_targets[0] = swapchain->frontBuffer;
1870 This->lastActiveRenderTarget = swapchain->frontBuffer;
1872 IWineD3DSurface_AddRef(This->render_targets[0]);
1873 This->activeContext = swapchain->context[0];
1874 This->lastThread = GetCurrentThreadId();
1876 /* Depth Stencil support */
1877 This->stencilBufferTarget = This->depthStencilBuffer;
1878 if (NULL != This->stencilBufferTarget) {
1879 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1882 /* Set up some starting GL setup */
1885 /* Setup all the devices defaults */
1886 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1888 IWineD3DImpl_CheckGraphicsMemory();
1891 { /* Set a default viewport */
1895 vp.Width = pPresentationParameters->BackBufferWidth;
1896 vp.Height = pPresentationParameters->BackBufferHeight;
1899 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1902 /* Initialize the current view state */
1903 This->view_ident = 1;
1904 This->contexts[0]->last_was_rhw = 0;
1905 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1906 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1908 switch(wined3d_settings.offscreen_rendering_mode) {
1911 This->offscreenBuffer = GL_BACK;
1914 case ORM_BACKBUFFER:
1916 if(GL_LIMITS(aux_buffers) > 0) {
1917 TRACE("Using auxilliary buffer for offscreen rendering\n");
1918 This->offscreenBuffer = GL_AUX0;
1920 TRACE("Using back buffer for offscreen rendering\n");
1921 This->offscreenBuffer = GL_BACK;
1926 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1929 /* Clear the screen */
1930 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1931 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1934 This->d3d_initialized = TRUE;
1938 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1942 TRACE("(%p)\n", This);
1944 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1946 /* I don't think that the interface guarants that the device is destroyed from the same thread
1947 * it was created. Thus make sure a context is active for the glDelete* calls
1949 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1951 TRACE("Deleting high order patches\n");
1952 for(i = 0; i < PATCHMAP_SIZE; i++) {
1953 struct list *e1, *e2;
1954 struct WineD3DRectPatch *patch;
1955 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1956 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1957 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1961 /* Delete the pbuffer context if there is any */
1962 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1964 /* Delete the mouse cursor texture */
1965 if(This->cursorTexture) {
1967 glDeleteTextures(1, &This->cursorTexture);
1969 This->cursorTexture = 0;
1972 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1973 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1975 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1976 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1979 /* Release the update stateblock */
1980 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1981 if(This->updateStateBlock != This->stateBlock)
1982 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1984 This->updateStateBlock = NULL;
1986 { /* because were not doing proper internal refcounts releasing the primary state block
1987 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1988 to set this->stateBlock = NULL; first */
1989 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1990 This->stateBlock = NULL;
1992 /* Release the stateblock */
1993 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1994 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1998 /* Release the buffers (with sanity checks)*/
1999 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2000 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2001 if(This->depthStencilBuffer != This->stencilBufferTarget)
2002 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2004 This->stencilBufferTarget = NULL;
2006 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2007 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2008 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2010 TRACE("Setting rendertarget to NULL\n");
2011 This->render_targets[0] = NULL;
2013 if (This->depthStencilBuffer) {
2014 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
2015 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2017 This->depthStencilBuffer = NULL;
2020 for(i=0; i < This->NumberOfSwapChains; i++) {
2021 TRACE("Releasing the implicit swapchain %d\n", i);
2022 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2023 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2027 HeapFree(GetProcessHeap(), 0, This->swapchains);
2028 This->swapchains = NULL;
2029 This->NumberOfSwapChains = 0;
2031 HeapFree(GetProcessHeap(), 0, This->render_targets);
2032 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2033 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2034 This->render_targets = NULL;
2035 This->fbo_color_attachments = NULL;
2036 This->draw_buffers = NULL;
2039 This->d3d_initialized = FALSE;
2043 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2045 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2047 /* Setup the window for fullscreen mode */
2048 if(fullscreen && !This->ddraw_fullscreen) {
2049 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2050 } else if(!fullscreen && This->ddraw_fullscreen) {
2051 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2054 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2055 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2056 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2059 This->ddraw_fullscreen = fullscreen;
2062 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2063 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2064 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2066 * There is no way to deactivate thread safety once it is enabled
2068 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2071 /*For now just store the flag(needed in case of ddraw) */
2072 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2077 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2081 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2084 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2086 /* Resize the screen even without a window:
2087 * The app could have unset it with SetCooperativeLevel, but not called
2088 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2089 * but we don't have any hwnd
2092 memset(&devmode, 0, sizeof(devmode));
2093 devmode.dmSize = sizeof(devmode);
2094 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2095 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2096 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2097 devmode.dmPelsWidth = pMode->Width;
2098 devmode.dmPelsHeight = pMode->Height;
2100 devmode.dmDisplayFrequency = pMode->RefreshRate;
2101 if (pMode->RefreshRate != 0) {
2102 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2105 /* Only change the mode if necessary */
2106 if( (This->ddraw_width == pMode->Width) &&
2107 (This->ddraw_height == pMode->Height) &&
2108 (This->ddraw_format == pMode->Format) &&
2109 (pMode->RefreshRate == 0) ) {
2113 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2114 if (ret != DISP_CHANGE_SUCCESSFUL) {
2115 if(devmode.dmDisplayFrequency != 0) {
2116 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2117 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2118 devmode.dmDisplayFrequency = 0;
2119 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2121 if(ret != DISP_CHANGE_SUCCESSFUL) {
2122 return WINED3DERR_NOTAVAILABLE;
2126 /* Store the new values */
2127 This->ddraw_width = pMode->Width;
2128 This->ddraw_height = pMode->Height;
2129 This->ddraw_format = pMode->Format;
2131 /* Only do this with a window of course */
2132 if(This->ddraw_window)
2133 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2135 /* And finally clip mouse to our screen */
2136 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2137 ClipCursor(&clip_rc);
2142 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2144 *ppD3D= This->wineD3D;
2145 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2146 IWineD3D_AddRef(*ppD3D);
2150 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2151 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2152 * into the video ram as possible and seeing how many fit
2153 * you can also get the correct initial value from nvidia and ATI's driver via X
2154 * texture memory is video memory + AGP memory
2155 *******************/
2156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2157 static BOOL showfixmes = TRUE;
2159 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2160 (wined3d_settings.emulated_textureram/(1024*1024)),
2161 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2164 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2165 (wined3d_settings.emulated_textureram/(1024*1024)),
2166 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2167 /* return simulated texture memory left */
2168 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2176 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2179 /* Update the current state block */
2180 This->updateStateBlock->changed.fvf = TRUE;
2182 if(This->updateStateBlock->fvf == fvf) {
2183 TRACE("Application is setting the old fvf over, nothing to do\n");
2187 This->updateStateBlock->fvf = fvf;
2188 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2189 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2194 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2195 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2196 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2197 *pfvf = This->stateBlock->fvf;
2202 * Get / Set Stream Source
2204 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2206 IWineD3DVertexBuffer *oldSrc;
2208 if (StreamNumber >= MAX_STREAMS) {
2209 WARN("Stream out of range %d\n", StreamNumber);
2210 return WINED3DERR_INVALIDCALL;
2213 oldSrc = This->stateBlock->streamSource[StreamNumber];
2214 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2216 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2218 if(oldSrc == pStreamData &&
2219 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2220 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2221 TRACE("Application is setting the old values over, nothing to do\n");
2225 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2227 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2228 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2231 /* Handle recording of state blocks */
2232 if (This->isRecordingState) {
2233 TRACE("Recording... not performing anything\n");
2237 /* Need to do a getParent and pass the reffs up */
2238 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2239 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2240 so for now, just count internally */
2241 if (pStreamData != NULL) {
2242 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2243 InterlockedIncrement(&vbImpl->bindCount);
2244 IWineD3DVertexBuffer_AddRef(pStreamData);
2246 if (oldSrc != NULL) {
2247 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2248 IWineD3DVertexBuffer_Release(oldSrc);
2251 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2256 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2259 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2260 This->stateBlock->streamSource[StreamNumber],
2261 This->stateBlock->streamOffset[StreamNumber],
2262 This->stateBlock->streamStride[StreamNumber]);
2264 if (StreamNumber >= MAX_STREAMS) {
2265 WARN("Stream out of range %d\n", StreamNumber);
2266 return WINED3DERR_INVALIDCALL;
2268 *pStream = This->stateBlock->streamSource[StreamNumber];
2269 *pStride = This->stateBlock->streamStride[StreamNumber];
2271 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2274 if (*pStream != NULL) {
2275 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2280 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2282 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2283 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2285 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2286 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2288 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2289 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2291 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2292 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2293 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2299 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2302 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2303 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2305 TRACE("(%p) : returning %d\n", This, *Divider);
2311 * Get / Set & Multiply Transform
2313 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2316 /* Most of this routine, comments included copied from ddraw tree initially: */
2317 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2319 /* Handle recording of state blocks */
2320 if (This->isRecordingState) {
2321 TRACE("Recording... not performing anything\n");
2322 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2323 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2328 * If the new matrix is the same as the current one,
2329 * we cut off any further processing. this seems to be a reasonable
2330 * optimization because as was noticed, some apps (warcraft3 for example)
2331 * tend towards setting the same matrix repeatedly for some reason.
2333 * From here on we assume that the new matrix is different, wherever it matters.
2335 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2336 TRACE("The app is setting the same matrix over again\n");
2339 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2343 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2344 where ViewMat = Camera space, WorldMat = world space.
2346 In OpenGL, camera and world space is combined into GL_MODELVIEW
2347 matrix. The Projection matrix stay projection matrix.
2350 /* Capture the times we can just ignore the change for now */
2351 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2352 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2353 /* Handled by the state manager */
2356 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2360 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2362 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2363 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2367 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2368 WINED3DMATRIX *mat = NULL;
2371 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2372 * below means it will be recorded in a state block change, but it
2373 * works regardless where it is recorded.
2374 * If this is found to be wrong, change to StateBlock.
2376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2377 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2379 if (State < HIGHEST_TRANSFORMSTATE)
2381 mat = &This->updateStateBlock->transforms[State];
2383 FIXME("Unhandled transform state!!\n");
2386 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2388 /* Apply change via set transform - will reapply to eg. lights this way */
2389 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2395 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2396 you can reference any indexes you want as long as that number max are enabled at any
2397 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2398 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2399 but when recording, just build a chain pretty much of commands to be replayed. */
2401 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2403 PLIGHTINFOEL *object = NULL;
2404 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2407 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2408 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2410 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2414 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2415 return WINED3DERR_INVALIDCALL;
2418 switch(pLight->Type) {
2419 case WINED3DLIGHT_POINT:
2420 case WINED3DLIGHT_SPOT:
2421 case WINED3DLIGHT_PARALLELPOINT:
2422 case WINED3DLIGHT_GLSPOT:
2423 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2426 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2427 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2428 return WINED3DERR_INVALIDCALL;
2432 case WINED3DLIGHT_DIRECTIONAL:
2433 /* Ignores attenuation */
2437 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2438 return WINED3DERR_INVALIDCALL;
2441 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2442 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2443 if(object->OriginalIndex == Index) break;
2448 TRACE("Adding new light\n");
2449 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2451 ERR("Out of memory error when allocating a light\n");
2452 return E_OUTOFMEMORY;
2454 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2455 object->glIndex = -1;
2456 object->OriginalIndex = Index;
2457 object->changed = TRUE;
2460 /* Initialize the object */
2461 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,
2462 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2463 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2464 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2465 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2466 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2467 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2469 /* Save away the information */
2470 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2472 switch (pLight->Type) {
2473 case WINED3DLIGHT_POINT:
2475 object->lightPosn[0] = pLight->Position.x;
2476 object->lightPosn[1] = pLight->Position.y;
2477 object->lightPosn[2] = pLight->Position.z;
2478 object->lightPosn[3] = 1.0f;
2479 object->cutoff = 180.0f;
2483 case WINED3DLIGHT_DIRECTIONAL:
2485 object->lightPosn[0] = -pLight->Direction.x;
2486 object->lightPosn[1] = -pLight->Direction.y;
2487 object->lightPosn[2] = -pLight->Direction.z;
2488 object->lightPosn[3] = 0.0;
2489 object->exponent = 0.0f;
2490 object->cutoff = 180.0f;
2493 case WINED3DLIGHT_SPOT:
2495 object->lightPosn[0] = pLight->Position.x;
2496 object->lightPosn[1] = pLight->Position.y;
2497 object->lightPosn[2] = pLight->Position.z;
2498 object->lightPosn[3] = 1.0;
2501 object->lightDirn[0] = pLight->Direction.x;
2502 object->lightDirn[1] = pLight->Direction.y;
2503 object->lightDirn[2] = pLight->Direction.z;
2504 object->lightDirn[3] = 1.0;
2507 * opengl-ish and d3d-ish spot lights use too different models for the
2508 * light "intensity" as a function of the angle towards the main light direction,
2509 * so we only can approximate very roughly.
2510 * however spot lights are rather rarely used in games (if ever used at all).
2511 * furthermore if still used, probably nobody pays attention to such details.
2513 if (pLight->Falloff == 0) {
2516 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2518 if (rho < 0.0001) rho = 0.0001f;
2519 object->exponent = -0.3/log(cos(rho/2));
2520 if (object->exponent > 128.0) {
2521 object->exponent = 128.0;
2523 object->cutoff = pLight->Phi*90/M_PI;
2529 FIXME("Unrecognized light type %d\n", pLight->Type);
2532 /* Update the live definitions if the light is currently assigned a glIndex */
2533 if (object->glIndex != -1 && !This->isRecordingState) {
2534 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2539 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2540 PLIGHTINFOEL *lightInfo = NULL;
2541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2542 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2544 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2546 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2547 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2548 if(lightInfo->OriginalIndex == Index) break;
2552 if (lightInfo == NULL) {
2553 TRACE("Light information requested but light not defined\n");
2554 return WINED3DERR_INVALIDCALL;
2557 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2562 * Get / Set Light Enable
2563 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2565 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2566 PLIGHTINFOEL *lightInfo = NULL;
2567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2568 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2570 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2572 /* Tests show true = 128...not clear why */
2573 Enable = Enable? 128: 0;
2575 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2576 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2577 if(lightInfo->OriginalIndex == Index) break;
2580 TRACE("Found light: %p\n", lightInfo);
2582 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2583 if (lightInfo == NULL) {
2585 TRACE("Light enabled requested but light not defined, so defining one!\n");
2586 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2588 /* Search for it again! Should be fairly quick as near head of list */
2589 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2590 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2591 if(lightInfo->OriginalIndex == Index) break;
2594 if (lightInfo == NULL) {
2595 FIXME("Adding default lights has failed dismally\n");
2596 return WINED3DERR_INVALIDCALL;
2600 lightInfo->enabledChanged = TRUE;
2602 if(lightInfo->glIndex != -1) {
2603 if(!This->isRecordingState) {
2604 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2607 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2608 lightInfo->glIndex = -1;
2610 TRACE("Light already disabled, nothing to do\n");
2613 if (lightInfo->glIndex != -1) {
2615 TRACE("Nothing to do as light was enabled\n");
2618 /* Find a free gl light */
2619 for(i = 0; i < This->maxConcurrentLights; i++) {
2620 if(This->stateBlock->activeLights[i] == NULL) {
2621 This->stateBlock->activeLights[i] = lightInfo;
2622 lightInfo->glIndex = i;
2626 if(lightInfo->glIndex == -1) {
2627 ERR("Too many concurrently active lights\n");
2628 return WINED3DERR_INVALIDCALL;
2631 /* i == lightInfo->glIndex */
2632 if(!This->isRecordingState) {
2633 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2641 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2643 PLIGHTINFOEL *lightInfo = NULL;
2644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2646 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2647 TRACE("(%p) : for idx(%d)\n", This, Index);
2649 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2650 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2651 if(lightInfo->OriginalIndex == Index) break;
2655 if (lightInfo == NULL) {
2656 TRACE("Light enabled state requested but light not defined\n");
2657 return WINED3DERR_INVALIDCALL;
2659 /* true is 128 according to SetLightEnable */
2660 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2665 * Get / Set Clip Planes
2667 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2669 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2671 /* Validate Index */
2672 if (Index >= GL_LIMITS(clipplanes)) {
2673 TRACE("Application has requested clipplane this device doesn't support\n");
2674 return WINED3DERR_INVALIDCALL;
2677 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2679 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2680 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2681 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2682 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2683 TRACE("Application is setting old values over, nothing to do\n");
2687 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2688 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2689 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2690 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2692 /* Handle recording of state blocks */
2693 if (This->isRecordingState) {
2694 TRACE("Recording... not performing anything\n");
2698 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2703 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2705 TRACE("(%p) : for idx %d\n", This, Index);
2707 /* Validate Index */
2708 if (Index >= GL_LIMITS(clipplanes)) {
2709 TRACE("Application has requested clipplane this device doesn't support\n");
2710 return WINED3DERR_INVALIDCALL;
2713 pPlane[0] = This->stateBlock->clipplane[Index][0];
2714 pPlane[1] = This->stateBlock->clipplane[Index][1];
2715 pPlane[2] = This->stateBlock->clipplane[Index][2];
2716 pPlane[3] = This->stateBlock->clipplane[Index][3];
2721 * Get / Set Clip Plane Status
2722 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2724 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2726 FIXME("(%p) : stub\n", This);
2727 if (NULL == pClipStatus) {
2728 return WINED3DERR_INVALIDCALL;
2730 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2731 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2735 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2737 FIXME("(%p) : stub\n", This);
2738 if (NULL == pClipStatus) {
2739 return WINED3DERR_INVALIDCALL;
2741 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2742 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2747 * Get / Set Material
2749 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2752 This->updateStateBlock->changed.material = TRUE;
2753 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2755 /* Handle recording of state blocks */
2756 if (This->isRecordingState) {
2757 TRACE("Recording... not performing anything\n");
2761 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2765 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2767 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2768 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2769 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2770 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2771 pMaterial->Ambient.b, pMaterial->Ambient.a);
2772 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2773 pMaterial->Specular.b, pMaterial->Specular.a);
2774 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2775 pMaterial->Emissive.b, pMaterial->Emissive.a);
2776 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2784 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2786 IWineD3DIndexBuffer *oldIdxs;
2788 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2789 oldIdxs = This->updateStateBlock->pIndexData;
2791 This->updateStateBlock->changed.indices = TRUE;
2792 This->updateStateBlock->pIndexData = pIndexData;
2794 /* Handle recording of state blocks */
2795 if (This->isRecordingState) {
2796 TRACE("Recording... not performing anything\n");
2800 if(oldIdxs != pIndexData) {
2801 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2802 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2803 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2808 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2811 *ppIndexData = This->stateBlock->pIndexData;
2813 /* up ref count on ppindexdata */
2815 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2816 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2818 TRACE("(%p) No index data set\n", This);
2820 TRACE("Returning %p\n", *ppIndexData);
2825 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2826 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2828 TRACE("(%p)->(%d)\n", This, BaseIndex);
2830 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2831 TRACE("Application is setting the old value over, nothing to do\n");
2835 This->updateStateBlock->baseVertexIndex = BaseIndex;
2837 if (This->isRecordingState) {
2838 TRACE("Recording... not performing anything\n");
2841 /* The base vertex index affects the stream sources */
2842 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2846 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, UINT* base_index) {
2847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2848 TRACE("(%p) : base_index %p\n", This, base_index);
2850 *base_index = This->stateBlock->baseVertexIndex;
2852 TRACE("Returning %u\n", *base_index);
2858 * Get / Set Viewports
2860 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2863 TRACE("(%p)\n", This);
2864 This->updateStateBlock->changed.viewport = TRUE;
2865 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2867 /* Handle recording of state blocks */
2868 if (This->isRecordingState) {
2869 TRACE("Recording... not performing anything\n");
2873 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2874 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2876 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2881 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2883 TRACE("(%p)\n", This);
2884 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2889 * Get / Set Render States
2890 * TODO: Verify against dx9 definitions
2892 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2895 DWORD oldValue = This->stateBlock->renderState[State];
2897 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2899 This->updateStateBlock->changed.renderState[State] = TRUE;
2900 This->updateStateBlock->renderState[State] = Value;
2902 /* Handle recording of state blocks */
2903 if (This->isRecordingState) {
2904 TRACE("Recording... not performing anything\n");
2908 /* Compared here and not before the assignment to allow proper stateblock recording */
2909 if(Value == oldValue) {
2910 TRACE("Application is setting the old value over, nothing to do\n");
2912 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2918 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2920 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2921 *pValue = This->stateBlock->renderState[State];
2926 * Get / Set Sampler States
2927 * TODO: Verify against dx9 definitions
2930 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2934 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2935 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2937 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2938 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2942 * SetSampler is designed to allow for more than the standard up to 8 textures
2943 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2944 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2946 * http://developer.nvidia.com/object/General_FAQ.html#t6
2948 * There are two new settings for GForce
2950 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2951 * and the texture one:
2952 * GL_MAX_TEXTURE_COORDS_ARB.
2953 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2956 oldValue = This->stateBlock->samplerState[Sampler][Type];
2957 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2958 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2960 /* Handle recording of state blocks */
2961 if (This->isRecordingState) {
2962 TRACE("Recording... not performing anything\n");
2966 if(oldValue == Value) {
2967 TRACE("Application is setting the old value over, nothing to do\n");
2971 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2976 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2979 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2980 This, Sampler, debug_d3dsamplerstate(Type), Type);
2982 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2983 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2986 *Value = This->stateBlock->samplerState[Sampler][Type];
2987 TRACE("(%p) : Returning %#x\n", This, *Value);
2992 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2995 This->updateStateBlock->changed.scissorRect = TRUE;
2996 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2997 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3000 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3002 if(This->isRecordingState) {
3003 TRACE("Recording... not performing anything\n");
3007 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3012 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3015 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3016 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3020 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3022 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3024 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3026 This->updateStateBlock->vertexDecl = pDecl;
3027 This->updateStateBlock->changed.vertexDecl = TRUE;
3029 if (This->isRecordingState) {
3030 TRACE("Recording... not performing anything\n");
3032 } else if(pDecl == oldDecl) {
3033 /* Checked after the assignment to allow proper stateblock recording */
3034 TRACE("Application is setting the old declaration over, nothing to do\n");
3038 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3042 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3045 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3047 *ppDecl = This->stateBlock->vertexDecl;
3048 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3052 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3054 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3056 This->updateStateBlock->vertexShader = pShader;
3057 This->updateStateBlock->changed.vertexShader = TRUE;
3059 if (This->isRecordingState) {
3060 TRACE("Recording... not performing anything\n");
3062 } else if(oldShader == pShader) {
3063 /* Checked here to allow proper stateblock recording */
3064 TRACE("App is setting the old shader over, nothing to do\n");
3068 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3070 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3075 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3078 if (NULL == ppShader) {
3079 return WINED3DERR_INVALIDCALL;
3081 *ppShader = This->stateBlock->vertexShader;
3082 if( NULL != *ppShader)
3083 IWineD3DVertexShader_AddRef(*ppShader);
3085 TRACE("(%p) : returning %p\n", This, *ppShader);
3089 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3090 IWineD3DDevice *iface,
3092 CONST BOOL *srcData,
3095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3096 int i, cnt = min(count, MAX_CONST_B - start);
3098 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3099 iface, srcData, start, count);
3101 if (srcData == NULL || cnt < 0)
3102 return WINED3DERR_INVALIDCALL;
3104 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3105 for (i = 0; i < cnt; i++)
3106 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3108 for (i = start; i < cnt + start; ++i) {
3109 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3112 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3117 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3118 IWineD3DDevice *iface,
3123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3124 int cnt = min(count, MAX_CONST_B - start);
3126 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3127 iface, dstData, start, count);
3129 if (dstData == NULL || cnt < 0)
3130 return WINED3DERR_INVALIDCALL;
3132 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3136 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3137 IWineD3DDevice *iface,
3142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3143 int i, cnt = min(count, MAX_CONST_I - start);
3145 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3146 iface, srcData, start, count);
3148 if (srcData == NULL || cnt < 0)
3149 return WINED3DERR_INVALIDCALL;
3151 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3152 for (i = 0; i < cnt; i++)
3153 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3154 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3156 for (i = start; i < cnt + start; ++i) {
3157 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3160 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3165 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3166 IWineD3DDevice *iface,
3171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3172 int cnt = min(count, MAX_CONST_I - start);
3174 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3175 iface, dstData, start, count);
3177 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3178 return WINED3DERR_INVALIDCALL;
3180 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3184 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3185 IWineD3DDevice *iface,
3187 CONST float *srcData,
3190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3193 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3194 iface, srcData, start, count);
3196 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3197 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3198 return WINED3DERR_INVALIDCALL;
3200 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3202 for (i = 0; i < count; i++)
3203 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3204 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3207 for (i = start; i < count + start; ++i) {
3208 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3209 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3210 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3211 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3212 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3214 ptr->idx[ptr->count++] = i;
3215 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3219 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3224 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3225 IWineD3DDevice *iface,
3230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3231 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3233 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3234 iface, dstData, start, count);
3236 if (dstData == NULL || cnt < 0)
3237 return WINED3DERR_INVALIDCALL;
3239 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3243 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3245 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3246 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3250 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3251 int i = This->rev_tex_unit_map[unit];
3252 int j = This->texUnitMap[stage];
3254 This->texUnitMap[stage] = unit;
3255 if (i != -1 && i != stage) {
3256 This->texUnitMap[i] = -1;
3259 This->rev_tex_unit_map[unit] = stage;
3260 if (j != -1 && j != unit) {
3261 This->rev_tex_unit_map[j] = -1;
3265 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3268 for (i = 0; i < MAX_TEXTURES; ++i) {
3269 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3270 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3271 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3272 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3273 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3274 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3275 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3276 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3278 if (color_op == WINED3DTOP_DISABLE) {
3279 /* Not used, and disable higher stages */
3280 while (i < MAX_TEXTURES) {
3281 This->fixed_function_usage_map[i] = FALSE;
3287 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3288 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3289 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3290 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3291 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3292 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3293 This->fixed_function_usage_map[i] = TRUE;
3295 This->fixed_function_usage_map[i] = FALSE;
3298 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3299 This->fixed_function_usage_map[i+1] = TRUE;
3304 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3307 device_update_fixed_function_usage_map(This);
3309 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3310 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3311 if (!This->fixed_function_usage_map[i]) continue;
3313 if (This->texUnitMap[i] != i) {
3314 device_map_stage(This, i, i);
3315 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3316 markTextureStagesDirty(This, i);
3322 /* Now work out the mapping */
3324 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3325 if (!This->fixed_function_usage_map[i]) continue;
3327 if (This->texUnitMap[i] != tex) {
3328 device_map_stage(This, i, tex);
3329 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3330 markTextureStagesDirty(This, i);
3337 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3338 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3341 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3342 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3343 device_map_stage(This, i, i);
3344 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3345 if (i < MAX_TEXTURES) {
3346 markTextureStagesDirty(This, i);
3352 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3353 int current_mapping = This->rev_tex_unit_map[unit];
3355 if (current_mapping == -1) {
3356 /* Not currently used */
3360 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3361 /* Used by a fragment sampler */
3363 if (!pshader_sampler_tokens) {
3364 /* No pixel shader, check fixed function */
3365 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3368 /* Pixel shader, check the shader's sampler map */
3369 return !pshader_sampler_tokens[current_mapping];
3372 /* Used by a vertex sampler */
3373 return !vshader_sampler_tokens[current_mapping];
3376 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3377 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3378 DWORD *pshader_sampler_tokens = NULL;
3379 int start = GL_LIMITS(combined_samplers) - 1;
3383 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3385 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3386 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3387 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3390 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3391 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3392 if (vshader_sampler_tokens[i]) {
3393 if (This->texUnitMap[vsampler_idx] != -1) {
3394 /* Already mapped somewhere */
3398 while (start >= 0) {
3399 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3400 device_map_stage(This, vsampler_idx, start);
3401 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3413 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3414 BOOL vs = use_vs(This);
3415 BOOL ps = use_ps(This);
3418 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3419 * that would be really messy and require shader recompilation
3420 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3421 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3424 device_map_psamplers(This);
3426 device_map_fixed_function_samplers(This);
3430 device_map_vsamplers(This, ps);
3434 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3436 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3437 This->updateStateBlock->pixelShader = pShader;
3438 This->updateStateBlock->changed.pixelShader = TRUE;
3440 /* Handle recording of state blocks */
3441 if (This->isRecordingState) {
3442 TRACE("Recording... not performing anything\n");
3445 if (This->isRecordingState) {
3446 TRACE("Recording... not performing anything\n");
3450 if(pShader == oldShader) {
3451 TRACE("App is setting the old pixel shader over, nothing to do\n");
3455 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3456 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3461 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3464 if (NULL == ppShader) {
3465 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3466 return WINED3DERR_INVALIDCALL;
3469 *ppShader = This->stateBlock->pixelShader;
3470 if (NULL != *ppShader) {
3471 IWineD3DPixelShader_AddRef(*ppShader);
3473 TRACE("(%p) : returning %p\n", This, *ppShader);
3477 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3478 IWineD3DDevice *iface,
3480 CONST BOOL *srcData,
3483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3484 int i, cnt = min(count, MAX_CONST_B - start);
3486 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3487 iface, srcData, start, count);
3489 if (srcData == NULL || cnt < 0)
3490 return WINED3DERR_INVALIDCALL;
3492 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3493 for (i = 0; i < cnt; i++)
3494 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3496 for (i = start; i < cnt + start; ++i) {
3497 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3500 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3505 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3506 IWineD3DDevice *iface,
3511 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3512 int cnt = min(count, MAX_CONST_B - start);
3514 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3515 iface, dstData, start, count);
3517 if (dstData == NULL || cnt < 0)
3518 return WINED3DERR_INVALIDCALL;
3520 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3524 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3525 IWineD3DDevice *iface,
3530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3531 int i, cnt = min(count, MAX_CONST_I - start);
3533 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3534 iface, srcData, start, count);
3536 if (srcData == NULL || cnt < 0)
3537 return WINED3DERR_INVALIDCALL;
3539 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3540 for (i = 0; i < cnt; i++)
3541 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3542 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3544 for (i = start; i < cnt + start; ++i) {
3545 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3548 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3553 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3554 IWineD3DDevice *iface,
3559 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3560 int cnt = min(count, MAX_CONST_I - start);
3562 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3563 iface, dstData, start, count);
3565 if (dstData == NULL || cnt < 0)
3566 return WINED3DERR_INVALIDCALL;
3568 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3572 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3573 IWineD3DDevice *iface,
3575 CONST float *srcData,
3578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3581 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3582 iface, srcData, start, count);
3584 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3585 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3586 return WINED3DERR_INVALIDCALL;
3588 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3590 for (i = 0; i < count; i++)
3591 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3592 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3595 for (i = start; i < count + start; ++i) {
3596 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3597 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3598 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3599 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3600 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3602 ptr->idx[ptr->count++] = i;
3603 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3607 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3612 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3613 IWineD3DDevice *iface,
3618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3619 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3621 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3622 iface, dstData, start, count);
3624 if (dstData == NULL || cnt < 0)
3625 return WINED3DERR_INVALIDCALL;
3627 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3631 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3633 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3634 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3636 DWORD DestFVF = dest->fvf;
3638 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3642 if (lpStrideData->u.s.normal.lpData) {
3643 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3646 if (lpStrideData->u.s.position.lpData == NULL) {
3647 ERR("Source has no position mask\n");
3648 return WINED3DERR_INVALIDCALL;
3651 /* We might access VBOs from this code, so hold the lock */
3654 if (dest->resource.allocatedMemory == NULL) {
3655 /* This may happen if we do direct locking into a vbo. Unlikely,
3656 * but theoretically possible(ddraw processvertices test)
3658 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3659 if(!dest->resource.allocatedMemory) {
3661 ERR("Out of memory\n");
3662 return E_OUTOFMEMORY;
3666 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3667 checkGLcall("glBindBufferARB");
3668 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3670 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3672 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3673 checkGLcall("glUnmapBufferARB");
3677 /* Get a pointer into the destination vbo(create one if none exists) and
3678 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3680 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3685 unsigned char extrabytes = 0;
3686 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3687 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3688 * this may write 4 extra bytes beyond the area that should be written
3690 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3691 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3692 if(!dest_conv_addr) {
3693 ERR("Out of memory\n");
3694 /* Continue without storing converted vertices */
3696 dest_conv = dest_conv_addr;
3700 * a) WINED3DRS_CLIPPING is enabled
3701 * b) WINED3DVOP_CLIP is passed
3703 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3704 static BOOL warned = FALSE;
3706 * The clipping code is not quite correct. Some things need
3707 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3708 * so disable clipping for now.
3709 * (The graphics in Half-Life are broken, and my processvertices
3710 * test crashes with IDirect3DDevice3)
3716 FIXME("Clipping is broken and disabled for now\n");
3718 } else doClip = FALSE;
3719 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3721 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3724 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3725 WINED3DTS_PROJECTION,
3727 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3728 WINED3DTS_WORLDMATRIX(0),
3731 TRACE("View mat:\n");
3732 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);
3733 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);
3734 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);
3735 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);
3737 TRACE("Proj mat:\n");
3738 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);
3739 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);
3740 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);
3741 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);
3743 TRACE("World mat:\n");
3744 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);
3745 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);
3746 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);
3747 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);
3749 /* Get the viewport */
3750 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3751 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3752 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3754 multiply_matrix(&mat,&view_mat,&world_mat);
3755 multiply_matrix(&mat,&proj_mat,&mat);
3757 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3759 for (i = 0; i < dwCount; i+= 1) {
3760 unsigned int tex_index;
3762 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3763 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3764 /* The position first */
3766 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3768 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3770 /* Multiplication with world, view and projection matrix */
3771 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);
3772 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);
3773 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);
3774 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);
3776 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3778 /* WARNING: The following things are taken from d3d7 and were not yet checked
3779 * against d3d8 or d3d9!
3782 /* Clipping conditions: From
3783 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3785 * A vertex is clipped if it does not match the following requirements
3789 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3791 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3792 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3797 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3798 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3801 /* "Normal" viewport transformation (not clipped)
3802 * 1) The values are divided by rhw
3803 * 2) The y axis is negative, so multiply it with -1
3804 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3805 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3806 * 4) Multiply x with Width/2 and add Width/2
3807 * 5) The same for the height
3808 * 6) Add the viewpoint X and Y to the 2D coordinates and
3809 * The minimum Z value to z
3810 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3812 * Well, basically it's simply a linear transformation into viewport
3824 z *= vp.MaxZ - vp.MinZ;
3826 x += vp.Width / 2 + vp.X;
3827 y += vp.Height / 2 + vp.Y;
3832 /* That vertex got clipped
3833 * Contrary to OpenGL it is not dropped completely, it just
3834 * undergoes a different calculation.
3836 TRACE("Vertex got clipped\n");
3843 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3844 * outside of the main vertex buffer memory. That needs some more
3849 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3852 ( (float *) dest_ptr)[0] = x;
3853 ( (float *) dest_ptr)[1] = y;
3854 ( (float *) dest_ptr)[2] = z;
3855 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3857 dest_ptr += 3 * sizeof(float);
3859 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3860 dest_ptr += sizeof(float);
3865 ( (float *) dest_conv)[0] = x * w;
3866 ( (float *) dest_conv)[1] = y * w;
3867 ( (float *) dest_conv)[2] = z * w;
3868 ( (float *) dest_conv)[3] = w;
3870 dest_conv += 3 * sizeof(float);
3872 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3873 dest_conv += sizeof(float);
3877 if (DestFVF & WINED3DFVF_PSIZE) {
3878 dest_ptr += sizeof(DWORD);
3879 if(dest_conv) dest_conv += sizeof(DWORD);
3881 if (DestFVF & WINED3DFVF_NORMAL) {
3883 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3884 /* AFAIK this should go into the lighting information */
3885 FIXME("Didn't expect the destination to have a normal\n");
3886 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3888 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3892 if (DestFVF & WINED3DFVF_DIFFUSE) {
3894 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3896 static BOOL warned = FALSE;
3899 ERR("No diffuse color in source, but destination has one\n");
3903 *( (DWORD *) dest_ptr) = 0xffffffff;
3904 dest_ptr += sizeof(DWORD);
3907 *( (DWORD *) dest_conv) = 0xffffffff;
3908 dest_conv += sizeof(DWORD);
3912 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3914 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3915 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3916 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3917 dest_conv += sizeof(DWORD);
3922 if (DestFVF & WINED3DFVF_SPECULAR) {
3923 /* What's the color value in the feedback buffer? */
3925 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3927 static BOOL warned = FALSE;
3930 ERR("No specular color in source, but destination has one\n");
3934 *( (DWORD *) dest_ptr) = 0xFF000000;
3935 dest_ptr += sizeof(DWORD);
3938 *( (DWORD *) dest_conv) = 0xFF000000;
3939 dest_conv += sizeof(DWORD);
3943 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3945 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3946 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3947 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3948 dest_conv += sizeof(DWORD);
3953 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3955 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3956 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3958 ERR("No source texture, but destination requests one\n");
3959 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3960 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3963 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3965 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3972 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3973 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3974 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3975 dwCount * get_flexible_vertex_size(DestFVF),
3977 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3978 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3985 #undef copy_and_next
3987 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3989 WineDirect3DVertexStridedData strided;
3990 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3991 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3994 ERR("Output vertex declaration not implemented yet\n");
3997 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3998 * and this call is quite performance critical, so don't call needlessly
4000 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4001 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4004 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4005 * control the streamIsUP flag, thus restore it afterwards.
4007 This->stateBlock->streamIsUP = FALSE;
4008 memset(&strided, 0, sizeof(strided));
4009 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4010 This->stateBlock->streamIsUP = streamWasUP;
4012 if(vbo || SrcStartIndex) {
4014 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4015 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4017 * Also get the start index in, but only loop over all elements if there's something to add at all.
4019 #define FIXSRC(type) \
4020 if(strided.u.s.type.VBO) { \
4021 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4022 strided.u.s.type.VBO = 0; \
4023 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4025 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4029 if(strided.u.s.type.lpData) { \
4030 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4033 FIXSRC(blendWeights);
4034 FIXSRC(blendMatrixIndices);
4039 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4040 FIXSRC(texCoords[i]);
4053 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4057 * Get / Set Texture Stage States
4058 * TODO: Verify against dx9 definitions
4060 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4062 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4064 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4066 if (Stage >= MAX_TEXTURES) {
4067 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4071 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4072 This->updateStateBlock->textureState[Stage][Type] = Value;
4074 if (This->isRecordingState) {
4075 TRACE("Recording... not performing anything\n");
4079 /* Checked after the assignments to allow proper stateblock recording */
4080 if(oldValue == Value) {
4081 TRACE("App is setting the old value over, nothing to do\n");
4085 if(Stage > This->stateBlock->lowest_disabled_stage &&
4086 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4087 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4088 * Changes in other states are important on disabled stages too
4093 if(Type == WINED3DTSS_COLOROP) {
4096 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4097 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4098 * they have to be disabled
4100 * The current stage is dirtified below.
4102 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4103 TRACE("Additionally dirtifying stage %d\n", i);
4104 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4106 This->stateBlock->lowest_disabled_stage = Stage;
4107 TRACE("New lowest disabled: %d\n", Stage);
4108 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4109 /* Previously disabled stage enabled. Stages above it may need enabling
4110 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4111 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4113 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4116 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4117 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4120 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4121 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4123 This->stateBlock->lowest_disabled_stage = i;
4124 TRACE("New lowest disabled: %d\n", i);
4126 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4127 /* TODO: Built a stage -> texture unit mapping for register combiners */
4131 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4136 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4138 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4139 *pValue = This->updateStateBlock->textureState[Stage][Type];
4146 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4148 IWineD3DBaseTexture *oldTexture;
4150 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4152 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4153 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4156 oldTexture = This->updateStateBlock->textures[Stage];
4158 if(pTexture != NULL) {
4159 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4161 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4162 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4163 return WINED3DERR_INVALIDCALL;
4165 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4168 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4169 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4171 This->updateStateBlock->changed.textures[Stage] = TRUE;
4172 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4173 This->updateStateBlock->textures[Stage] = pTexture;
4175 /* Handle recording of state blocks */
4176 if (This->isRecordingState) {
4177 TRACE("Recording... not performing anything\n");
4181 if(oldTexture == pTexture) {
4182 TRACE("App is setting the same texture again, nothing to do\n");
4186 /** NOTE: MSDN says that setTexture increases the reference count,
4187 * and the the application must set the texture back to null (or have a leaky application),
4188 * This means we should pass the refcount up to the parent
4189 *******************************/
4190 if (NULL != This->updateStateBlock->textures[Stage]) {
4191 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4192 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4194 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4195 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4196 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4197 * so the COLOROP and ALPHAOP have to be dirtified.
4199 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4200 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4202 if(bindCount == 1) {
4203 new->baseTexture.sampler = Stage;
4205 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4209 if (NULL != oldTexture) {
4210 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4211 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4213 IWineD3DBaseTexture_Release(oldTexture);
4214 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4215 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4216 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4219 if(bindCount && old->baseTexture.sampler == Stage) {
4221 /* Have to do a search for the other sampler(s) where the texture is bound to
4222 * Shouldn't happen as long as apps bind a texture only to one stage
4224 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4225 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4226 if(This->updateStateBlock->textures[i] == oldTexture) {
4227 old->baseTexture.sampler = i;
4234 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4239 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4242 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4244 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4245 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4248 *ppTexture=This->stateBlock->textures[Stage];
4250 IWineD3DBaseTexture_AddRef(*ppTexture);
4252 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4260 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4261 IWineD3DSurface **ppBackBuffer) {
4262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4263 IWineD3DSwapChain *swapChain;
4266 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4268 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4269 if (hr == WINED3D_OK) {
4270 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4271 IWineD3DSwapChain_Release(swapChain);
4273 *ppBackBuffer = NULL;
4278 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4280 WARN("(%p) : stub, calling idirect3d for now\n", This);
4281 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4284 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4286 IWineD3DSwapChain *swapChain;
4289 if(iSwapChain > 0) {
4290 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4291 if (hr == WINED3D_OK) {
4292 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4293 IWineD3DSwapChain_Release(swapChain);
4295 FIXME("(%p) Error getting display mode\n", This);
4298 /* Don't read the real display mode,
4299 but return the stored mode instead. X11 can't change the color
4300 depth, and some apps are pretty angry if they SetDisplayMode from
4301 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4303 Also don't relay to the swapchain because with ddraw it's possible
4304 that there isn't a swapchain at all */
4305 pMode->Width = This->ddraw_width;
4306 pMode->Height = This->ddraw_height;
4307 pMode->Format = This->ddraw_format;
4308 pMode->RefreshRate = 0;
4315 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4317 TRACE("(%p)->(%p)\n", This, hWnd);
4319 if(This->ddraw_fullscreen) {
4320 if(This->ddraw_window && This->ddraw_window != hWnd) {
4321 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4323 if(hWnd && This->ddraw_window != hWnd) {
4324 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4328 This->ddraw_window = hWnd;
4332 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4334 TRACE("(%p)->(%p)\n", This, hWnd);
4336 *hWnd = This->ddraw_window;
4341 * Stateblock related functions
4344 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4346 IWineD3DStateBlockImpl *object;
4347 HRESULT temp_result;
4350 TRACE("(%p)\n", This);
4352 if (This->isRecordingState) {
4353 return WINED3DERR_INVALIDCALL;
4356 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4357 if (NULL == object ) {
4358 FIXME("(%p)Error allocating memory for stateblock\n", This);
4359 return E_OUTOFMEMORY;
4361 TRACE("(%p) created object %p\n", This, object);
4362 object->wineD3DDevice= This;
4363 /** FIXME: object->parent = parent; **/
4364 object->parent = NULL;
4365 object->blockType = WINED3DSBT_RECORDED;
4367 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4369 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4370 list_init(&object->lightMap[i]);
4373 temp_result = allocate_shader_constants(object);
4374 if (WINED3D_OK != temp_result)
4377 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4378 This->updateStateBlock = object;
4379 This->isRecordingState = TRUE;
4381 TRACE("(%p) recording stateblock %p\n",This , object);
4385 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4388 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4390 if (!This->isRecordingState) {
4391 FIXME("(%p) not recording! returning error\n", This);
4392 *ppStateBlock = NULL;
4393 return WINED3DERR_INVALIDCALL;
4396 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4397 if(object->changed.renderState[i]) {
4398 object->contained_render_states[object->num_contained_render_states] = i;
4399 object->num_contained_render_states++;
4402 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4403 if(object->changed.transform[i]) {
4404 object->contained_transform_states[object->num_contained_transform_states] = i;
4405 object->num_contained_transform_states++;
4408 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4409 if(object->changed.vertexShaderConstantsF[i]) {
4410 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4411 object->num_contained_vs_consts_f++;
4414 for(i = 0; i < MAX_CONST_I; i++) {
4415 if(object->changed.vertexShaderConstantsI[i]) {
4416 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4417 object->num_contained_vs_consts_i++;
4420 for(i = 0; i < MAX_CONST_B; i++) {
4421 if(object->changed.vertexShaderConstantsB[i]) {
4422 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4423 object->num_contained_vs_consts_b++;
4426 for(i = 0; i < MAX_CONST_I; i++) {
4427 if(object->changed.pixelShaderConstantsI[i]) {
4428 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4429 object->num_contained_ps_consts_i++;
4432 for(i = 0; i < MAX_CONST_B; i++) {
4433 if(object->changed.pixelShaderConstantsB[i]) {
4434 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4435 object->num_contained_ps_consts_b++;
4438 for(i = 0; i < MAX_TEXTURES; i++) {
4439 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4440 if(object->changed.textureState[i][j]) {
4441 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4442 object->contained_tss_states[object->num_contained_tss_states].state = j;
4443 object->num_contained_tss_states++;
4447 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4448 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4449 if(object->changed.samplerState[i][j]) {
4450 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4451 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4452 object->num_contained_sampler_states++;
4457 *ppStateBlock = (IWineD3DStateBlock*) object;
4458 This->isRecordingState = FALSE;
4459 This->updateStateBlock = This->stateBlock;
4460 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4461 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4462 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4467 * Scene related functions
4469 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4470 /* At the moment we have no need for any functionality at the beginning
4472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4473 TRACE("(%p)\n", This);
4476 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4477 return WINED3DERR_INVALIDCALL;
4479 This->inScene = TRUE;
4483 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4485 TRACE("(%p)\n", This);
4487 if(!This->inScene) {
4488 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4489 return WINED3DERR_INVALIDCALL;
4492 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4493 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4495 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4498 checkGLcall("glFlush");
4501 This->inScene = FALSE;
4505 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4506 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4507 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4509 IWineD3DSwapChain *swapChain = NULL;
4511 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4513 TRACE("(%p) Presenting the frame\n", This);
4515 for(i = 0 ; i < swapchains ; i ++) {
4517 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4518 TRACE("presentinng chain %d, %p\n", i, swapChain);
4519 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4520 IWineD3DSwapChain_Release(swapChain);
4526 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4527 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4529 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4531 GLbitfield glMask = 0;
4533 CONST WINED3DRECT* curRect;
4535 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4536 Count, pRects, Flags, Color, Z, Stencil);
4538 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4539 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4540 /* TODO: What about depth stencil buffers without stencil bits? */
4541 return WINED3DERR_INVALIDCALL;
4544 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4545 * and not the last active one.
4547 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4550 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4551 apply_fbo_state(iface);
4554 if (Count > 0 && pRects) {
4560 /* Only set the values up once, as they are not changing */
4561 if (Flags & WINED3DCLEAR_STENCIL) {
4562 glClearStencil(Stencil);
4563 checkGLcall("glClearStencil");
4564 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4565 glStencilMask(0xFFFFFFFF);
4568 if (Flags & WINED3DCLEAR_ZBUFFER) {
4569 glDepthMask(GL_TRUE);
4571 checkGLcall("glClearDepth");
4572 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4573 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4576 if (Flags & WINED3DCLEAR_TARGET) {
4577 TRACE("Clearing screen with glClear to color %x\n", Color);
4578 glClearColor(D3DCOLOR_R(Color),
4582 checkGLcall("glClearColor");
4584 /* Clear ALL colors! */
4585 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4586 glMask = glMask | GL_COLOR_BUFFER_BIT;
4590 /* In drawable flag is set below */
4592 if (This->render_offscreen) {
4593 glScissor(This->stateBlock->viewport.X,
4594 This->stateBlock->viewport.Y,
4595 This->stateBlock->viewport.Width,
4596 This->stateBlock->viewport.Height);
4598 glScissor(This->stateBlock->viewport.X,
4599 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4600 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4601 This->stateBlock->viewport.Width,
4602 This->stateBlock->viewport.Height);
4604 checkGLcall("glScissor");
4606 checkGLcall("glClear");
4608 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4609 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4611 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4612 curRect[0].x2 < target->currentDesc.Width ||
4613 curRect[0].y2 < target->currentDesc.Height) {
4614 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4615 blt_to_drawable(This, target);
4619 /* Now process each rect in turn */
4620 for (i = 0; i < Count; i++) {
4621 /* Note gl uses lower left, width/height */
4622 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4623 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4624 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4625 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4627 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4628 * The rectangle is not cleared, no error is returned, but further rectanlges are
4629 * still cleared if they are valid
4631 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4632 TRACE("Rectangle with negative dimensions, ignoring\n");
4636 if(This->render_offscreen) {
4637 glScissor(curRect[i].x1, curRect[i].y1,
4638 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4640 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4641 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4643 checkGLcall("glScissor");
4646 checkGLcall("glClear");
4650 /* Restore the old values (why..?) */
4651 if (Flags & WINED3DCLEAR_STENCIL) {
4652 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4654 if (Flags & WINED3DCLEAR_TARGET) {
4655 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4656 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4657 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4658 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4659 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4664 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4665 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4667 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4668 target->Flags |= SFLAG_INTEXTURE;
4669 target->Flags &= ~SFLAG_INSYSMEM;
4671 target->Flags |= SFLAG_INDRAWABLE;
4672 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4680 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4681 UINT PrimitiveCount) {
4683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4685 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4686 debug_d3dprimitivetype(PrimitiveType),
4687 StartVertex, PrimitiveCount);
4689 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4690 if(This->stateBlock->streamIsUP) {
4691 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4692 This->stateBlock->streamIsUP = FALSE;
4695 if(This->stateBlock->loadBaseVertexIndex != 0) {
4696 This->stateBlock->loadBaseVertexIndex = 0;
4697 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4699 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4700 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4701 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4705 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4706 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4707 WINED3DPRIMITIVETYPE PrimitiveType,
4708 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4712 IWineD3DIndexBuffer *pIB;
4713 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4716 pIB = This->stateBlock->pIndexData;
4718 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4719 * without an index buffer set. (The first time at least...)
4720 * D3D8 simply dies, but I doubt it can do much harm to return
4721 * D3DERR_INVALIDCALL there as well. */
4722 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4723 return WINED3DERR_INVALIDCALL;
4726 if(This->stateBlock->streamIsUP) {
4727 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4728 This->stateBlock->streamIsUP = FALSE;
4730 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4732 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4733 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4734 minIndex, NumVertices, startIndex, primCount);
4736 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4737 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4743 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4744 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4745 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4748 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4749 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4754 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4755 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4756 UINT VertexStreamZeroStride) {
4757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4758 IWineD3DVertexBuffer *vb;
4760 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4761 debug_d3dprimitivetype(PrimitiveType),
4762 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4764 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4765 vb = This->stateBlock->streamSource[0];
4766 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4767 if(vb) IWineD3DVertexBuffer_Release(vb);
4768 This->stateBlock->streamOffset[0] = 0;
4769 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4770 This->stateBlock->streamIsUP = TRUE;
4771 This->stateBlock->loadBaseVertexIndex = 0;
4773 /* TODO: Only mark dirty if drawing from a different UP address */
4774 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4776 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4777 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4779 /* MSDN specifies stream zero settings must be set to NULL */
4780 This->stateBlock->streamStride[0] = 0;
4781 This->stateBlock->streamSource[0] = NULL;
4783 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4784 * the new stream sources or use UP drawing again
4789 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4790 UINT MinVertexIndex, UINT NumVertices,
4791 UINT PrimitiveCount, CONST void* pIndexData,
4792 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4793 UINT VertexStreamZeroStride) {
4795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4796 IWineD3DVertexBuffer *vb;
4797 IWineD3DIndexBuffer *ib;
4799 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4800 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4801 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4802 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4804 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4810 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4811 vb = This->stateBlock->streamSource[0];
4812 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4813 if(vb) IWineD3DVertexBuffer_Release(vb);
4814 This->stateBlock->streamIsUP = TRUE;
4815 This->stateBlock->streamOffset[0] = 0;
4816 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4818 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4819 This->stateBlock->baseVertexIndex = 0;
4820 This->stateBlock->loadBaseVertexIndex = 0;
4821 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4822 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4823 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4825 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4827 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4828 This->stateBlock->streamSource[0] = NULL;
4829 This->stateBlock->streamStride[0] = 0;
4830 ib = This->stateBlock->pIndexData;
4832 IWineD3DIndexBuffer_Release(ib);
4833 This->stateBlock->pIndexData = NULL;
4835 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4836 * SetStreamSource to specify a vertex buffer
4842 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4845 /* Mark the state dirty until we have nicer tracking
4846 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4849 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4850 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4851 This->stateBlock->baseVertexIndex = 0;
4852 This->up_strided = DrawPrimStrideData;
4853 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4854 This->up_strided = NULL;
4858 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
4859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4860 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
4862 /* Mark the state dirty until we have nicer tracking
4863 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4866 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4867 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4868 This->stateBlock->streamIsUP = TRUE;
4869 This->stateBlock->baseVertexIndex = 0;
4870 This->up_strided = DrawPrimStrideData;
4871 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
4872 This->up_strided = NULL;
4877 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4878 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4880 HRESULT hr = WINED3D_OK;
4881 WINED3DRESOURCETYPE sourceType;
4882 WINED3DRESOURCETYPE destinationType;
4885 /* TODO: think about moving the code into IWineD3DBaseTexture */
4887 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4889 /* verify that the source and destination textures aren't NULL */
4890 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4891 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4892 This, pSourceTexture, pDestinationTexture);
4893 hr = WINED3DERR_INVALIDCALL;
4896 if (pSourceTexture == pDestinationTexture) {
4897 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4898 This, pSourceTexture, pDestinationTexture);
4899 hr = WINED3DERR_INVALIDCALL;
4901 /* Verify that the source and destination textures are the same type */
4902 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4903 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4905 if (sourceType != destinationType) {
4906 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4908 hr = WINED3DERR_INVALIDCALL;
4911 /* check that both textures have the identical numbers of levels */
4912 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4913 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4914 hr = WINED3DERR_INVALIDCALL;
4917 if (WINED3D_OK == hr) {
4919 /* Make sure that the destination texture is loaded */
4920 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4922 /* Update every surface level of the texture */
4923 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4925 switch (sourceType) {
4926 case WINED3DRTYPE_TEXTURE:
4928 IWineD3DSurface *srcSurface;
4929 IWineD3DSurface *destSurface;
4931 for (i = 0 ; i < levels ; ++i) {
4932 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4933 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4934 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4935 IWineD3DSurface_Release(srcSurface);
4936 IWineD3DSurface_Release(destSurface);
4937 if (WINED3D_OK != hr) {
4938 WARN("(%p) : Call to update surface failed\n", This);
4944 case WINED3DRTYPE_CUBETEXTURE:
4946 IWineD3DSurface *srcSurface;
4947 IWineD3DSurface *destSurface;
4948 WINED3DCUBEMAP_FACES faceType;
4950 for (i = 0 ; i < levels ; ++i) {
4951 /* Update each cube face */
4952 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4953 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4954 if (WINED3D_OK != hr) {
4955 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4957 TRACE("Got srcSurface %p\n", srcSurface);
4959 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4960 if (WINED3D_OK != hr) {
4961 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4963 TRACE("Got desrSurface %p\n", destSurface);
4965 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4966 IWineD3DSurface_Release(srcSurface);
4967 IWineD3DSurface_Release(destSurface);
4968 if (WINED3D_OK != hr) {
4969 WARN("(%p) : Call to update surface failed\n", This);
4976 #if 0 /* TODO: Add support for volume textures */
4977 case WINED3DRTYPE_VOLUMETEXTURE:
4979 IWineD3DVolume srcVolume = NULL;
4980 IWineD3DSurface destVolume = NULL;
4982 for (i = 0 ; i < levels ; ++i) {
4983 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4984 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4985 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4986 IWineD3DVolume_Release(srcSurface);
4987 IWineD3DVolume_Release(destSurface);
4988 if (WINED3D_OK != hr) {
4989 WARN("(%p) : Call to update volume failed\n", This);
4997 FIXME("(%p) : Unsupported source and destination type\n", This);
4998 hr = WINED3DERR_INVALIDCALL;
5005 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5006 IWineD3DSwapChain *swapChain;
5008 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5009 if(hr == WINED3D_OK) {
5010 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5011 IWineD3DSwapChain_Release(swapChain);
5016 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5018 /* return a sensible default */
5020 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5021 FIXME("(%p) : stub\n", This);
5025 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5028 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5029 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5030 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5031 return WINED3DERR_INVALIDCALL;
5033 for (j = 0; j < 256; ++j) {
5034 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5035 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5036 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5037 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5039 TRACE("(%p) : returning\n", This);
5043 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5046 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5047 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5048 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5049 return WINED3DERR_INVALIDCALL;
5051 for (j = 0; j < 256; ++j) {
5052 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5053 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5054 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5055 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5057 TRACE("(%p) : returning\n", This);
5061 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5063 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5064 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5065 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5066 return WINED3DERR_INVALIDCALL;
5068 /*TODO: stateblocks */
5069 This->currentPalette = PaletteNumber;
5070 TRACE("(%p) : returning\n", This);
5074 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5076 if (PaletteNumber == NULL) {
5077 WARN("(%p) : returning Invalid Call\n", This);
5078 return WINED3DERR_INVALIDCALL;
5080 /*TODO: stateblocks */
5081 *PaletteNumber = This->currentPalette;
5082 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5086 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5088 static BOOL showFixmes = TRUE;
5090 FIXME("(%p) : stub\n", This);
5094 This->softwareVertexProcessing = bSoftware;
5099 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5101 static BOOL showFixmes = TRUE;
5103 FIXME("(%p) : stub\n", This);
5106 return This->softwareVertexProcessing;
5110 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5112 IWineD3DSwapChain *swapChain;
5115 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5117 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5118 if(hr == WINED3D_OK){
5119 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5120 IWineD3DSwapChain_Release(swapChain);
5122 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5128 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5130 static BOOL showfixmes = TRUE;
5131 if(nSegments != 0.0f) {
5133 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5140 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5142 static BOOL showfixmes = TRUE;
5144 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5150 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5152 /** TODO: remove casts to IWineD3DSurfaceImpl
5153 * NOTE: move code to surface to accomplish this
5154 ****************************************/
5155 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5156 int srcWidth, srcHeight;
5157 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5158 WINED3DFORMAT destFormat, srcFormat;
5160 int srcLeft, destLeft, destTop;
5161 WINED3DPOOL srcPool, destPool;
5163 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5164 glDescriptor *glDescription = NULL;
5167 CONVERT_TYPES convert = NO_CONVERSION;
5169 WINED3DSURFACE_DESC winedesc;
5171 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5172 memset(&winedesc, 0, sizeof(winedesc));
5173 winedesc.Width = &srcSurfaceWidth;
5174 winedesc.Height = &srcSurfaceHeight;
5175 winedesc.Pool = &srcPool;
5176 winedesc.Format = &srcFormat;
5178 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5180 winedesc.Width = &destSurfaceWidth;
5181 winedesc.Height = &destSurfaceHeight;
5182 winedesc.Pool = &destPool;
5183 winedesc.Format = &destFormat;
5184 winedesc.Size = &destSize;
5186 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5188 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5189 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5190 return WINED3DERR_INVALIDCALL;
5193 /* This call loads the opengl surface directly, instead of copying the surface to the
5194 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5195 * copy in sysmem and use regular surface loading.
5197 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5198 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5199 if(convert != NO_CONVERSION) {
5200 return IWineD3DSurface_BltFast(pDestinationSurface,
5201 pDestPoint ? pDestPoint->x : 0,
5202 pDestPoint ? pDestPoint->y : 0,
5203 pSourceSurface, (RECT *) pSourceRect, 0);
5206 if (destFormat == WINED3DFMT_UNKNOWN) {
5207 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5208 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5210 /* Get the update surface description */
5211 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5214 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5218 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5219 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5220 checkGLcall("glActiveTextureARB");
5223 /* Make sure the surface is loaded and up to date */
5224 IWineD3DSurface_PreLoad(pDestinationSurface);
5226 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5228 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5229 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5230 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5231 srcLeft = pSourceRect ? pSourceRect->left : 0;
5232 destLeft = pDestPoint ? pDestPoint->x : 0;
5233 destTop = pDestPoint ? pDestPoint->y : 0;
5236 /* This function doesn't support compressed textures
5237 the pitch is just bytesPerPixel * width */
5238 if(srcWidth != srcSurfaceWidth || srcLeft ){
5239 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5240 offset += srcLeft * pSrcSurface->bytesPerPixel;
5241 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5243 /* TODO DXT formats */
5245 if(pSourceRect != NULL && pSourceRect->top != 0){
5246 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5248 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5250 ,glDescription->level
5255 ,glDescription->glFormat
5256 ,glDescription->glType
5257 ,IWineD3DSurface_GetData(pSourceSurface)
5261 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5263 /* need to lock the surface to get the data */
5264 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5267 /* TODO: Cube and volume support */
5269 /* not a whole row so we have to do it a line at a time */
5272 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5273 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5275 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5277 glTexSubImage2D(glDescription->target
5278 ,glDescription->level
5283 ,glDescription->glFormat
5284 ,glDescription->glType
5285 ,data /* could be quicker using */
5290 } else { /* Full width, so just write out the whole texture */
5292 if (WINED3DFMT_DXT1 == destFormat ||
5293 WINED3DFMT_DXT2 == destFormat ||
5294 WINED3DFMT_DXT3 == destFormat ||
5295 WINED3DFMT_DXT4 == destFormat ||
5296 WINED3DFMT_DXT5 == destFormat) {
5297 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5298 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5299 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5300 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5301 } if (destFormat != srcFormat) {
5302 FIXME("Updating mixed format compressed texture is not curretly support\n");
5304 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5305 glDescription->level,
5306 glDescription->glFormatInternal,
5311 IWineD3DSurface_GetData(pSourceSurface));
5314 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5319 glTexSubImage2D(glDescription->target
5320 ,glDescription->level
5325 ,glDescription->glFormat
5326 ,glDescription->glType
5327 ,IWineD3DSurface_GetData(pSourceSurface)
5331 checkGLcall("glTexSubImage2D");
5335 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5336 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5337 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5342 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5344 struct WineD3DRectPatch *patch;
5348 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5350 if(!(Handle || pRectPatchInfo)) {
5351 /* TODO: Write a test for the return value, thus the FIXME */
5352 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5353 return WINED3DERR_INVALIDCALL;
5357 i = PATCHMAP_HASHFUNC(Handle);
5359 LIST_FOR_EACH(e, &This->patches[i]) {
5360 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5361 if(patch->Handle == Handle) {
5368 TRACE("Patch does not exist. Creating a new one\n");
5369 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5370 patch->Handle = Handle;
5371 list_add_head(&This->patches[i], &patch->entry);
5373 TRACE("Found existing patch %p\n", patch);
5376 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5377 * attributes we have to tesselate, read back, and draw. This needs a patch
5378 * management structure instance. Create one.
5380 * A possible improvement is to check if a vertex shader is used, and if not directly
5383 FIXME("Drawing an uncached patch. This is slow\n");
5384 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5387 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5388 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5389 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5391 TRACE("Tesselation density or patch info changed, retesselating\n");
5393 if(pRectPatchInfo) {
5394 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5396 patch->numSegs[0] = pNumSegs[0];
5397 patch->numSegs[1] = pNumSegs[1];
5398 patch->numSegs[2] = pNumSegs[2];
5399 patch->numSegs[3] = pNumSegs[3];
5401 hr = tesselate_rectpatch(This, patch);
5403 WARN("Patch tesselation failed\n");
5405 /* Do not release the handle to store the params of the patch */
5407 HeapFree(GetProcessHeap(), 0, patch);
5413 This->currentPatch = patch;
5414 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5415 This->currentPatch = NULL;
5417 /* Destroy uncached patches */
5419 HeapFree(GetProcessHeap(), 0, patch->mem);
5420 HeapFree(GetProcessHeap(), 0, patch);
5425 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5426 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5428 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5429 FIXME("(%p) : Stub\n", This);
5433 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5436 struct WineD3DRectPatch *patch;
5438 TRACE("(%p) Handle(%d)\n", This, Handle);
5440 i = PATCHMAP_HASHFUNC(Handle);
5441 LIST_FOR_EACH(e, &This->patches[i]) {
5442 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5443 if(patch->Handle == Handle) {
5444 TRACE("Deleting patch %p\n", patch);
5445 list_remove(&patch->entry);
5446 HeapFree(GetProcessHeap(), 0, patch->mem);
5447 HeapFree(GetProcessHeap(), 0, patch);
5452 /* TODO: Write a test for the return value */
5453 FIXME("Attempt to destroy nonexistant patch\n");
5454 return WINED3DERR_INVALIDCALL;
5457 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5459 IWineD3DSwapChain *swapchain;
5461 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5462 if (SUCCEEDED(hr)) {
5463 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5470 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5474 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5475 checkGLcall("glGenFramebuffersEXT()");
5477 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5478 checkGLcall("glBindFramebuffer()");
5481 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5482 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5483 IWineD3DBaseTextureImpl *texture_impl;
5484 GLenum texttarget, target;
5487 texttarget = surface_impl->glDescription.target;
5488 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5489 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5491 IWineD3DSurface_PreLoad(surface);
5493 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5494 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5495 glBindTexture(target, old_binding);
5497 /* Update base texture states array */
5498 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5499 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5500 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5501 if (texture_impl->baseTexture.bindCount) {
5502 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5505 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5508 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5510 checkGLcall("attach_surface_fbo");
5513 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5515 IWineD3DSwapChain *swapchain;
5517 swapchain = get_swapchain(surface);
5521 TRACE("Surface %p is onscreen\n", surface);
5523 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5524 buffer = surface_get_gl_buffer(surface, swapchain);
5525 glDrawBuffer(buffer);
5526 checkGLcall("glDrawBuffer()");
5528 TRACE("Surface %p is offscreen\n", surface);
5529 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5530 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5534 glEnable(GL_SCISSOR_TEST);
5536 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5538 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5539 rect->x2 - rect->x1, rect->y2 - rect->y1);
5541 checkGLcall("glScissor");
5543 glDisable(GL_SCISSOR_TEST);
5545 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5547 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5548 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5550 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5551 glClear(GL_COLOR_BUFFER_BIT);
5552 checkGLcall("glClear");
5554 if (This->render_offscreen) {
5555 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5557 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5558 checkGLcall("glBindFramebuffer()");
5561 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5562 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5563 glDrawBuffer(GL_BACK);
5564 checkGLcall("glDrawBuffer()");
5568 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5570 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5572 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5574 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5575 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5576 return WINED3DERR_INVALIDCALL;
5579 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5580 color_fill_fbo(iface, pSurface, pRect, color);
5583 /* Just forward this to the DirectDraw blitting engine */
5584 memset(&BltFx, 0, sizeof(BltFx));
5585 BltFx.dwSize = sizeof(BltFx);
5586 BltFx.u5.dwFillColor = color;
5587 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5591 /* rendertarget and deptth stencil functions */
5592 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5595 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5596 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5597 return WINED3DERR_INVALIDCALL;
5600 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5601 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5602 /* Note inc ref on returned surface */
5603 if(*ppRenderTarget != NULL)
5604 IWineD3DSurface_AddRef(*ppRenderTarget);
5608 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5610 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5611 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5612 IWineD3DSwapChainImpl *Swapchain;
5615 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5617 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5618 if(hr != WINED3D_OK) {
5619 ERR("Can't get the swapchain\n");
5623 /* Make sure to release the swapchain */
5624 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5626 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5627 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5628 return WINED3DERR_INVALIDCALL;
5630 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5631 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5632 return WINED3DERR_INVALIDCALL;
5635 if(Swapchain->frontBuffer != Front) {
5636 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5638 if(Swapchain->frontBuffer)
5639 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5640 Swapchain->frontBuffer = Front;
5642 if(Swapchain->frontBuffer) {
5643 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5647 if(Back && !Swapchain->backBuffer) {
5648 /* We need memory for the back buffer array - only one back buffer this way */
5649 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5650 if(!Swapchain->backBuffer) {
5651 ERR("Out of memory\n");
5652 return E_OUTOFMEMORY;
5656 if(Swapchain->backBuffer[0] != Back) {
5657 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5659 /* What to do about the context here in the case of multithreading? Not sure.
5660 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5663 if(!Swapchain->backBuffer[0]) {
5664 /* GL was told to draw to the front buffer at creation,
5667 glDrawBuffer(GL_BACK);
5668 checkGLcall("glDrawBuffer(GL_BACK)");
5669 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5670 Swapchain->presentParms.BackBufferCount = 1;
5672 /* That makes problems - disable for now */
5673 /* glDrawBuffer(GL_FRONT); */
5674 checkGLcall("glDrawBuffer(GL_FRONT)");
5675 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5676 Swapchain->presentParms.BackBufferCount = 0;
5680 if(Swapchain->backBuffer[0])
5681 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5682 Swapchain->backBuffer[0] = Back;
5684 if(Swapchain->backBuffer[0]) {
5685 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5687 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5695 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5697 *ppZStencilSurface = This->depthStencilBuffer;
5698 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5700 if(*ppZStencilSurface != NULL) {
5701 /* Note inc ref on returned surface */
5702 IWineD3DSurface_AddRef(*ppZStencilSurface);
5707 /* TODO: Handle stencil attachments */
5708 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5710 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5712 TRACE("Set depth stencil to %p\n", depth_stencil);
5714 if (depth_stencil_impl) {
5715 if (depth_stencil_impl->current_renderbuffer) {
5716 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5717 checkGLcall("glFramebufferRenderbufferEXT()");
5719 IWineD3DBaseTextureImpl *texture_impl;
5720 GLenum texttarget, target;
5721 GLint old_binding = 0;
5723 texttarget = depth_stencil_impl->glDescription.target;
5724 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5725 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5727 IWineD3DSurface_PreLoad(depth_stencil);
5729 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5730 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5731 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5732 glBindTexture(target, old_binding);
5734 /* Update base texture states array */
5735 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5736 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5737 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5738 if (texture_impl->baseTexture.bindCount) {
5739 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5742 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5745 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5746 checkGLcall("glFramebufferTexture2DEXT()");
5749 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5750 checkGLcall("glFramebufferTexture2DEXT()");
5754 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5756 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5758 TRACE("Set render target %u to %p\n", idx, render_target);
5761 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5762 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5764 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5765 checkGLcall("glFramebufferTexture2DEXT()");
5767 This->draw_buffers[idx] = GL_NONE;
5771 static void check_fbo_status(IWineD3DDevice *iface) {
5772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5775 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5776 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5777 TRACE("FBO complete\n");
5779 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5781 /* Dump the FBO attachments */
5782 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5783 IWineD3DSurfaceImpl *attachment;
5786 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5787 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5789 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5790 attachment->pow2Width, attachment->pow2Height);
5793 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5795 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5796 attachment->pow2Width, attachment->pow2Height);
5802 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5804 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5805 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5807 if (!ds_impl) return FALSE;
5809 if (ds_impl->current_renderbuffer) {
5810 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5811 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5814 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5815 rt_impl->pow2Height != ds_impl->pow2Height);
5818 void apply_fbo_state(IWineD3DDevice *iface) {
5819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5822 if (This->render_offscreen) {
5823 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5825 /* Apply render targets */
5826 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5827 IWineD3DSurface *render_target = This->render_targets[i];
5828 if (This->fbo_color_attachments[i] != render_target) {
5829 set_render_target_fbo(iface, i, render_target);
5830 This->fbo_color_attachments[i] = render_target;
5834 /* Apply depth targets */
5835 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5836 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5837 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5839 if (This->stencilBufferTarget) {
5840 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5842 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5843 This->fbo_depth_attachment = This->stencilBufferTarget;
5846 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5847 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5848 checkGLcall("glDrawBuffers()");
5850 glDrawBuffer(This->draw_buffers[0]);
5851 checkGLcall("glDrawBuffer()");
5854 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5857 check_fbo_status(iface);
5860 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5861 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5863 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5864 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5867 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5868 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5869 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5870 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5873 case WINED3DTEXF_LINEAR:
5874 gl_filter = GL_LINEAR;
5878 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5879 case WINED3DTEXF_NONE:
5880 case WINED3DTEXF_POINT:
5881 gl_filter = GL_NEAREST;
5885 /* Attach src surface to src fbo */
5886 src_swapchain = get_swapchain(src_surface);
5887 if (src_swapchain) {
5890 TRACE("Source surface %p is onscreen\n", src_surface);
5891 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5894 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5895 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5896 glReadBuffer(buffer);
5897 checkGLcall("glReadBuffer()");
5899 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5900 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5902 TRACE("Source surface %p is offscreen\n", src_surface);
5904 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5905 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5906 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5907 checkGLcall("glReadBuffer()");
5911 /* Attach dst surface to dst fbo */
5912 dst_swapchain = get_swapchain(dst_surface);
5913 if (dst_swapchain) {
5916 TRACE("Destination surface %p is onscreen\n", dst_surface);
5917 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5920 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5921 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5922 glDrawBuffer(buffer);
5923 checkGLcall("glDrawBuffer()");
5925 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5926 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5928 TRACE("Destination surface %p is offscreen\n", dst_surface);
5930 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5931 if(!src_swapchain) {
5932 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5936 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5937 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5938 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5939 checkGLcall("glDrawBuffer()");
5941 glDisable(GL_SCISSOR_TEST);
5942 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5945 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5946 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5947 checkGLcall("glBlitFramebuffer()");
5949 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5950 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5951 checkGLcall("glBlitFramebuffer()");
5954 if (This->render_offscreen) {
5955 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5957 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5958 checkGLcall("glBindFramebuffer()");
5961 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5962 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5963 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5964 glDrawBuffer(GL_BACK);
5965 checkGLcall("glDrawBuffer()");
5970 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5972 WINED3DVIEWPORT viewport;
5974 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5976 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5977 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5978 return WINED3DERR_INVALIDCALL;
5981 /* MSDN says that null disables the render target
5982 but a device must always be associated with a render target
5983 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5985 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5988 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5989 FIXME("Trying to set render target 0 to NULL\n");
5990 return WINED3DERR_INVALIDCALL;
5992 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5993 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);
5994 return WINED3DERR_INVALIDCALL;
5997 /* If we are trying to set what we already have, don't bother */
5998 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5999 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6002 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6003 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6004 This->render_targets[RenderTargetIndex] = pRenderTarget;
6006 /* Render target 0 is special */
6007 if(RenderTargetIndex == 0) {
6008 /* Finally, reset the viewport as the MSDN states. */
6009 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6010 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6013 viewport.MaxZ = 1.0f;
6014 viewport.MinZ = 0.0f;
6015 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6016 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6017 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6019 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6021 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6023 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6024 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6026 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6031 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6033 HRESULT hr = WINED3D_OK;
6034 IWineD3DSurface *tmp;
6036 TRACE("(%p) Swapping z-buffer\n",This);
6038 if (pNewZStencil == This->stencilBufferTarget) {
6039 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6041 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6042 * depending on the renter target implementation being used.
6043 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6044 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6045 * stencil buffer and incure an extra memory overhead
6046 ******************************************************/
6048 tmp = This->stencilBufferTarget;
6049 This->stencilBufferTarget = pNewZStencil;
6050 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6051 /* should we be calling the parent or the wined3d surface? */
6052 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6053 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6056 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6057 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6058 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6059 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6060 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6067 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6068 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6070 /* TODO: the use of Impl is deprecated. */
6071 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6072 WINED3DLOCKED_RECT lockedRect;
6074 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6076 /* some basic validation checks */
6077 if(This->cursorTexture) {
6078 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6080 glDeleteTextures(1, &This->cursorTexture);
6082 This->cursorTexture = 0;
6085 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6086 This->haveHardwareCursor = TRUE;
6088 This->haveHardwareCursor = FALSE;
6091 WINED3DLOCKED_RECT rect;
6093 /* MSDN: Cursor must be A8R8G8B8 */
6094 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6095 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6096 return WINED3DERR_INVALIDCALL;
6099 /* MSDN: Cursor must be smaller than the display mode */
6100 if(pSur->currentDesc.Width > This->ddraw_width ||
6101 pSur->currentDesc.Height > This->ddraw_height) {
6102 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);
6103 return WINED3DERR_INVALIDCALL;
6106 if (!This->haveHardwareCursor) {
6107 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6109 /* Do not store the surface's pointer because the application may
6110 * release it after setting the cursor image. Windows doesn't
6111 * addref the set surface, so we can't do this either without
6112 * creating circular refcount dependencies. Copy out the gl texture
6115 This->cursorWidth = pSur->currentDesc.Width;
6116 This->cursorHeight = pSur->currentDesc.Height;
6117 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6119 const GlPixelFormatDesc *glDesc;
6120 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6121 char *mem, *bits = (char *)rect.pBits;
6122 GLint intfmt = glDesc->glInternal;
6123 GLint format = glDesc->glFormat;
6124 GLint type = glDesc->glType;
6125 INT height = This->cursorHeight;
6126 INT width = This->cursorWidth;
6127 INT bpp = tableEntry->bpp;
6130 /* Reformat the texture memory (pitch and width can be
6132 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6133 for(i = 0; i < height; i++)
6134 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6135 IWineD3DSurface_UnlockRect(pCursorBitmap);
6138 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6139 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6140 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6143 /* Make sure that a proper texture unit is selected */
6144 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6145 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6146 checkGLcall("glActiveTextureARB");
6148 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6149 /* Create a new cursor texture */
6150 glGenTextures(1, &This->cursorTexture);
6151 checkGLcall("glGenTextures");
6152 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6153 checkGLcall("glBindTexture");
6154 /* Copy the bitmap memory into the cursor texture */
6155 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6156 HeapFree(GetProcessHeap(), 0, mem);
6157 checkGLcall("glTexImage2D");
6159 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6160 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6161 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6168 FIXME("A cursor texture was not returned.\n");
6169 This->cursorTexture = 0;
6174 /* Draw a hardware cursor */
6175 ICONINFO cursorInfo;
6177 /* Create and clear maskBits because it is not needed for
6178 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6180 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6181 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6182 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6183 WINED3DLOCK_NO_DIRTY_UPDATE |
6184 WINED3DLOCK_READONLY
6186 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6187 pSur->currentDesc.Height);
6189 cursorInfo.fIcon = FALSE;
6190 cursorInfo.xHotspot = XHotSpot;
6191 cursorInfo.yHotspot = YHotSpot;
6192 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6193 pSur->currentDesc.Height, 1,
6195 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6196 pSur->currentDesc.Height, 1,
6197 32, lockedRect.pBits);
6198 IWineD3DSurface_UnlockRect(pCursorBitmap);
6199 /* Create our cursor and clean up. */
6200 cursor = CreateIconIndirect(&cursorInfo);
6202 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6203 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6204 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6205 This->hardwareCursor = cursor;
6206 HeapFree(GetProcessHeap(), 0, maskBits);
6210 This->xHotSpot = XHotSpot;
6211 This->yHotSpot = YHotSpot;
6215 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6217 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6219 This->xScreenSpace = XScreenSpace;
6220 This->yScreenSpace = YScreenSpace;
6226 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6228 BOOL oldVisible = This->bCursorVisible;
6231 TRACE("(%p) : visible(%d)\n", This, bShow);
6234 * When ShowCursor is first called it should make the cursor appear at the OS's last
6235 * known cursor position. Because of this, some applications just repetitively call
6236 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6239 This->xScreenSpace = pt.x;
6240 This->yScreenSpace = pt.y;
6242 if (This->haveHardwareCursor) {
6243 This->bCursorVisible = bShow;
6245 SetCursor(This->hardwareCursor);
6251 if (This->cursorTexture)
6252 This->bCursorVisible = bShow;
6258 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6260 TRACE("(%p) : state (%u)\n", This, This->state);
6261 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6262 switch (This->state) {
6265 case WINED3DERR_DEVICELOST:
6267 ResourceList *resourceList = This->resources;
6268 while (NULL != resourceList) {
6269 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6270 return WINED3DERR_DEVICENOTRESET;
6271 resourceList = resourceList->next;
6273 return WINED3DERR_DEVICELOST;
6275 case WINED3DERR_DRIVERINTERNALERROR:
6276 return WINED3DERR_DRIVERINTERNALERROR;
6280 return WINED3DERR_DRIVERINTERNALERROR;
6284 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6286 /** FIXME: Resource tracking needs to be done,
6287 * The closes we can do to this is set the priorities of all managed textures low
6288 * and then reset them.
6289 ***********************************************************/
6290 FIXME("(%p) : stub\n", This);
6294 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6295 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6297 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6298 if(surface->Flags & SFLAG_DIBSECTION) {
6299 /* Release the DC */
6300 SelectObject(surface->hDC, surface->dib.holdbitmap);
6301 DeleteDC(surface->hDC);
6302 /* Release the DIB section */
6303 DeleteObject(surface->dib.DIBsection);
6304 surface->dib.bitmap_data = NULL;
6305 surface->resource.allocatedMemory = NULL;
6306 surface->Flags &= ~SFLAG_DIBSECTION;
6308 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6309 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6310 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6311 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6312 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6314 surface->pow2Width = surface->pow2Height = 1;
6315 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6316 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6318 if(surface->glDescription.textureName) {
6319 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6321 glDeleteTextures(1, &surface->glDescription.textureName);
6323 surface->glDescription.textureName = 0;
6324 surface->Flags &= ~SFLAG_CLIENT;
6326 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6327 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6328 surface->Flags |= SFLAG_NONPOW2;
6330 surface->Flags &= ~SFLAG_NONPOW2;
6332 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6333 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6336 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6338 IWineD3DSwapChainImpl *swapchain;
6340 BOOL DisplayModeChanged = FALSE;
6341 WINED3DDISPLAYMODE mode;
6342 TRACE("(%p)\n", This);
6344 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6346 ERR("Failed to get the first implicit swapchain\n");
6350 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6351 * on an existing gl context, so there's no real need for recreation.
6353 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6355 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6357 TRACE("New params:\n");
6358 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6359 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6360 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6361 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6362 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6363 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6364 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6365 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6366 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6367 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6368 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6369 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6370 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6372 /* No special treatment of these parameters. Just store them */
6373 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6374 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6375 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6376 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6378 /* What to do about these? */
6379 if(pPresentationParameters->BackBufferCount != 0 &&
6380 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6381 ERR("Cannot change the back buffer count yet\n");
6383 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6384 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6385 ERR("Cannot change the back buffer format yet\n");
6387 if(pPresentationParameters->hDeviceWindow != NULL &&
6388 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6389 ERR("Cannot change the device window yet\n");
6391 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6392 ERR("What do do about a changed auto depth stencil parameter?\n");
6395 if(pPresentationParameters->Windowed) {
6396 mode.Width = swapchain->orig_width;
6397 mode.Height = swapchain->orig_height;
6398 mode.RefreshRate = 0;
6399 mode.Format = swapchain->presentParms.BackBufferFormat;
6401 mode.Width = pPresentationParameters->BackBufferWidth;
6402 mode.Height = pPresentationParameters->BackBufferHeight;
6403 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6404 mode.Format = swapchain->presentParms.BackBufferFormat;
6407 /* Should Width == 800 && Height == 0 set 800x600? */
6408 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6409 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6410 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6417 vp.Width = pPresentationParameters->BackBufferWidth;
6418 vp.Height = pPresentationParameters->BackBufferHeight;
6422 if(!pPresentationParameters->Windowed) {
6423 DisplayModeChanged = TRUE;
6425 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6426 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6428 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6429 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6430 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6433 /* Now set the new viewport */
6434 IWineD3DDevice_SetViewport(iface, &vp);
6437 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6438 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6439 DisplayModeChanged) {
6441 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6442 if(!pPresentationParameters->Windowed) {
6443 IWineD3DDevice_SetFullscreen(iface, TRUE);
6446 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6448 /* Switching out of fullscreen mode? First set the original res, then change the window */
6449 if(pPresentationParameters->Windowed) {
6450 IWineD3DDevice_SetFullscreen(iface, FALSE);
6452 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6455 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6459 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6461 /** FIXME: always true at the moment **/
6462 if(!bEnableDialogs) {
6463 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6469 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6470 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6471 TRACE("(%p) : pParameters %p\n", This, pParameters);
6473 *pParameters = This->createParms;
6477 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6478 IWineD3DSwapChain *swapchain;
6479 HRESULT hrc = WINED3D_OK;
6481 TRACE("Relaying to swapchain\n");
6483 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6484 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6485 IWineD3DSwapChain_Release(swapchain);
6490 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6491 IWineD3DSwapChain *swapchain;
6492 HRESULT hrc = WINED3D_OK;
6494 TRACE("Relaying to swapchain\n");
6496 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6497 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6498 IWineD3DSwapChain_Release(swapchain);
6504 /** ********************************************************
6505 * Notification functions
6506 ** ********************************************************/
6507 /** This function must be called in the release of a resource when ref == 0,
6508 * the contents of resource must still be correct,
6509 * any handels to other resource held by the caller must be closed
6510 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6511 *****************************************************/
6512 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6514 ResourceList* resourceList;
6516 TRACE("(%p) : resource %p\n", This, resource);
6517 /* add a new texture to the frot of the linked list */
6518 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6519 resourceList->resource = resource;
6521 /* Get the old head */
6522 resourceList->next = This->resources;
6524 This->resources = resourceList;
6525 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6530 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6532 ResourceList* resourceList = NULL;
6533 ResourceList* previousResourceList = NULL;
6535 TRACE("(%p) : resource %p\n", This, resource);
6537 resourceList = This->resources;
6539 while (resourceList != NULL) {
6540 if(resourceList->resource == resource) break;
6541 previousResourceList = resourceList;
6542 resourceList = resourceList->next;
6545 if (resourceList == NULL) {
6546 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6549 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6551 /* make sure we don't leave a hole in the list */
6552 if (previousResourceList != NULL) {
6553 previousResourceList->next = resourceList->next;
6555 This->resources = resourceList->next;
6562 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6566 TRACE("(%p) : resource %p\n", This, resource);
6567 switch(IWineD3DResource_GetType(resource)){
6568 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6569 case WINED3DRTYPE_SURFACE: {
6572 /* Cleanup any FBO attachments if d3d is enabled */
6573 if(This->d3d_initialized) {
6574 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6575 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6576 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6577 set_render_target_fbo(iface, i, NULL);
6578 This->fbo_color_attachments[i] = NULL;
6581 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6582 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6583 set_depth_stencil_fbo(iface, NULL);
6584 This->fbo_depth_attachment = NULL;
6590 case WINED3DRTYPE_TEXTURE:
6591 case WINED3DRTYPE_CUBETEXTURE:
6592 case WINED3DRTYPE_VOLUMETEXTURE:
6593 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6594 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6595 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6596 This->stateBlock->textures[counter] = NULL;
6598 if (This->updateStateBlock != This->stateBlock ){
6599 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6600 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6601 This->updateStateBlock->textures[counter] = NULL;
6606 case WINED3DRTYPE_VOLUME:
6607 /* TODO: nothing really? */
6609 case WINED3DRTYPE_VERTEXBUFFER:
6610 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6613 TRACE("Cleaning up stream pointers\n");
6615 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6616 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6617 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6619 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6620 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6621 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6622 This->updateStateBlock->streamSource[streamNumber] = 0;
6623 /* Set changed flag? */
6626 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) */
6627 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6628 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6629 This->stateBlock->streamSource[streamNumber] = 0;
6632 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6633 else { /* This shouldn't happen */
6634 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6641 case WINED3DRTYPE_INDEXBUFFER:
6642 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6643 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6644 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6645 This->updateStateBlock->pIndexData = NULL;
6648 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6649 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6650 This->stateBlock->pIndexData = NULL;
6656 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6661 /* Remove the resoruce from the resourceStore */
6662 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6664 TRACE("Resource released\n");
6668 /**********************************************************
6669 * IWineD3DDevice VTbl follows
6670 **********************************************************/
6672 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6674 /*** IUnknown methods ***/
6675 IWineD3DDeviceImpl_QueryInterface,
6676 IWineD3DDeviceImpl_AddRef,
6677 IWineD3DDeviceImpl_Release,
6678 /*** IWineD3DDevice methods ***/
6679 IWineD3DDeviceImpl_GetParent,
6680 /*** Creation methods**/
6681 IWineD3DDeviceImpl_CreateVertexBuffer,
6682 IWineD3DDeviceImpl_CreateIndexBuffer,
6683 IWineD3DDeviceImpl_CreateStateBlock,
6684 IWineD3DDeviceImpl_CreateSurface,
6685 IWineD3DDeviceImpl_CreateTexture,
6686 IWineD3DDeviceImpl_CreateVolumeTexture,
6687 IWineD3DDeviceImpl_CreateVolume,
6688 IWineD3DDeviceImpl_CreateCubeTexture,
6689 IWineD3DDeviceImpl_CreateQuery,
6690 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6691 IWineD3DDeviceImpl_CreateVertexDeclaration,
6692 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6693 IWineD3DDeviceImpl_CreateVertexShader,
6694 IWineD3DDeviceImpl_CreatePixelShader,
6695 IWineD3DDeviceImpl_CreatePalette,
6696 /*** Odd functions **/
6697 IWineD3DDeviceImpl_Init3D,
6698 IWineD3DDeviceImpl_Uninit3D,
6699 IWineD3DDeviceImpl_SetFullscreen,
6700 IWineD3DDeviceImpl_SetMultithreaded,
6701 IWineD3DDeviceImpl_EvictManagedResources,
6702 IWineD3DDeviceImpl_GetAvailableTextureMem,
6703 IWineD3DDeviceImpl_GetBackBuffer,
6704 IWineD3DDeviceImpl_GetCreationParameters,
6705 IWineD3DDeviceImpl_GetDeviceCaps,
6706 IWineD3DDeviceImpl_GetDirect3D,
6707 IWineD3DDeviceImpl_GetDisplayMode,
6708 IWineD3DDeviceImpl_SetDisplayMode,
6709 IWineD3DDeviceImpl_GetHWND,
6710 IWineD3DDeviceImpl_SetHWND,
6711 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6712 IWineD3DDeviceImpl_GetRasterStatus,
6713 IWineD3DDeviceImpl_GetSwapChain,
6714 IWineD3DDeviceImpl_Reset,
6715 IWineD3DDeviceImpl_SetDialogBoxMode,
6716 IWineD3DDeviceImpl_SetCursorProperties,
6717 IWineD3DDeviceImpl_SetCursorPosition,
6718 IWineD3DDeviceImpl_ShowCursor,
6719 IWineD3DDeviceImpl_TestCooperativeLevel,
6720 /*** Getters and setters **/
6721 IWineD3DDeviceImpl_SetClipPlane,
6722 IWineD3DDeviceImpl_GetClipPlane,
6723 IWineD3DDeviceImpl_SetClipStatus,
6724 IWineD3DDeviceImpl_GetClipStatus,
6725 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6726 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6727 IWineD3DDeviceImpl_SetDepthStencilSurface,
6728 IWineD3DDeviceImpl_GetDepthStencilSurface,
6729 IWineD3DDeviceImpl_SetFVF,
6730 IWineD3DDeviceImpl_GetFVF,
6731 IWineD3DDeviceImpl_SetGammaRamp,
6732 IWineD3DDeviceImpl_GetGammaRamp,
6733 IWineD3DDeviceImpl_SetIndices,
6734 IWineD3DDeviceImpl_GetIndices,
6735 IWineD3DDeviceImpl_SetBaseVertexIndex,
6736 IWineD3DDeviceImpl_GetBaseVertexIndex,
6737 IWineD3DDeviceImpl_SetLight,
6738 IWineD3DDeviceImpl_GetLight,
6739 IWineD3DDeviceImpl_SetLightEnable,
6740 IWineD3DDeviceImpl_GetLightEnable,
6741 IWineD3DDeviceImpl_SetMaterial,
6742 IWineD3DDeviceImpl_GetMaterial,
6743 IWineD3DDeviceImpl_SetNPatchMode,
6744 IWineD3DDeviceImpl_GetNPatchMode,
6745 IWineD3DDeviceImpl_SetPaletteEntries,
6746 IWineD3DDeviceImpl_GetPaletteEntries,
6747 IWineD3DDeviceImpl_SetPixelShader,
6748 IWineD3DDeviceImpl_GetPixelShader,
6749 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6750 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6751 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6752 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6753 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6754 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6755 IWineD3DDeviceImpl_SetRenderState,
6756 IWineD3DDeviceImpl_GetRenderState,
6757 IWineD3DDeviceImpl_SetRenderTarget,
6758 IWineD3DDeviceImpl_GetRenderTarget,
6759 IWineD3DDeviceImpl_SetFrontBackBuffers,
6760 IWineD3DDeviceImpl_SetSamplerState,
6761 IWineD3DDeviceImpl_GetSamplerState,
6762 IWineD3DDeviceImpl_SetScissorRect,
6763 IWineD3DDeviceImpl_GetScissorRect,
6764 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6765 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6766 IWineD3DDeviceImpl_SetStreamSource,
6767 IWineD3DDeviceImpl_GetStreamSource,
6768 IWineD3DDeviceImpl_SetStreamSourceFreq,
6769 IWineD3DDeviceImpl_GetStreamSourceFreq,
6770 IWineD3DDeviceImpl_SetTexture,
6771 IWineD3DDeviceImpl_GetTexture,
6772 IWineD3DDeviceImpl_SetTextureStageState,
6773 IWineD3DDeviceImpl_GetTextureStageState,
6774 IWineD3DDeviceImpl_SetTransform,
6775 IWineD3DDeviceImpl_GetTransform,
6776 IWineD3DDeviceImpl_SetVertexDeclaration,
6777 IWineD3DDeviceImpl_GetVertexDeclaration,
6778 IWineD3DDeviceImpl_SetVertexShader,
6779 IWineD3DDeviceImpl_GetVertexShader,
6780 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6781 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6782 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6783 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6784 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6785 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6786 IWineD3DDeviceImpl_SetViewport,
6787 IWineD3DDeviceImpl_GetViewport,
6788 IWineD3DDeviceImpl_MultiplyTransform,
6789 IWineD3DDeviceImpl_ValidateDevice,
6790 IWineD3DDeviceImpl_ProcessVertices,
6791 /*** State block ***/
6792 IWineD3DDeviceImpl_BeginStateBlock,
6793 IWineD3DDeviceImpl_EndStateBlock,
6794 /*** Scene management ***/
6795 IWineD3DDeviceImpl_BeginScene,
6796 IWineD3DDeviceImpl_EndScene,
6797 IWineD3DDeviceImpl_Present,
6798 IWineD3DDeviceImpl_Clear,
6800 IWineD3DDeviceImpl_DrawPrimitive,
6801 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6802 IWineD3DDeviceImpl_DrawPrimitiveUP,
6803 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6804 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6805 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6806 IWineD3DDeviceImpl_DrawRectPatch,
6807 IWineD3DDeviceImpl_DrawTriPatch,
6808 IWineD3DDeviceImpl_DeletePatch,
6809 IWineD3DDeviceImpl_ColorFill,
6810 IWineD3DDeviceImpl_UpdateTexture,
6811 IWineD3DDeviceImpl_UpdateSurface,
6812 IWineD3DDeviceImpl_GetFrontBufferData,
6813 /*** object tracking ***/
6814 IWineD3DDeviceImpl_ResourceReleased
6818 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6819 WINED3DRS_ALPHABLENDENABLE ,
6820 WINED3DRS_ALPHAFUNC ,
6821 WINED3DRS_ALPHAREF ,
6822 WINED3DRS_ALPHATESTENABLE ,
6824 WINED3DRS_COLORWRITEENABLE ,
6825 WINED3DRS_DESTBLEND ,
6826 WINED3DRS_DITHERENABLE ,
6827 WINED3DRS_FILLMODE ,
6828 WINED3DRS_FOGDENSITY ,
6830 WINED3DRS_FOGSTART ,
6831 WINED3DRS_LASTPIXEL ,
6832 WINED3DRS_SHADEMODE ,
6833 WINED3DRS_SRCBLEND ,
6834 WINED3DRS_STENCILENABLE ,
6835 WINED3DRS_STENCILFAIL ,
6836 WINED3DRS_STENCILFUNC ,
6837 WINED3DRS_STENCILMASK ,
6838 WINED3DRS_STENCILPASS ,
6839 WINED3DRS_STENCILREF ,
6840 WINED3DRS_STENCILWRITEMASK ,
6841 WINED3DRS_STENCILZFAIL ,
6842 WINED3DRS_TEXTUREFACTOR ,
6853 WINED3DRS_ZWRITEENABLE
6856 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6857 WINED3DTSS_ADDRESSW ,
6858 WINED3DTSS_ALPHAARG0 ,
6859 WINED3DTSS_ALPHAARG1 ,
6860 WINED3DTSS_ALPHAARG2 ,
6861 WINED3DTSS_ALPHAOP ,
6862 WINED3DTSS_BUMPENVLOFFSET ,
6863 WINED3DTSS_BUMPENVLSCALE ,
6864 WINED3DTSS_BUMPENVMAT00 ,
6865 WINED3DTSS_BUMPENVMAT01 ,
6866 WINED3DTSS_BUMPENVMAT10 ,
6867 WINED3DTSS_BUMPENVMAT11 ,
6868 WINED3DTSS_COLORARG0 ,
6869 WINED3DTSS_COLORARG1 ,
6870 WINED3DTSS_COLORARG2 ,
6871 WINED3DTSS_COLOROP ,
6872 WINED3DTSS_RESULTARG ,
6873 WINED3DTSS_TEXCOORDINDEX ,
6874 WINED3DTSS_TEXTURETRANSFORMFLAGS
6877 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6878 WINED3DSAMP_ADDRESSU ,
6879 WINED3DSAMP_ADDRESSV ,
6880 WINED3DSAMP_ADDRESSW ,
6881 WINED3DSAMP_BORDERCOLOR ,
6882 WINED3DSAMP_MAGFILTER ,
6883 WINED3DSAMP_MINFILTER ,
6884 WINED3DSAMP_MIPFILTER ,
6885 WINED3DSAMP_MIPMAPLODBIAS ,
6886 WINED3DSAMP_MAXMIPLEVEL ,
6887 WINED3DSAMP_MAXANISOTROPY ,
6888 WINED3DSAMP_SRGBTEXTURE ,
6889 WINED3DSAMP_ELEMENTINDEX
6892 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6894 WINED3DRS_AMBIENTMATERIALSOURCE ,
6895 WINED3DRS_CLIPPING ,
6896 WINED3DRS_CLIPPLANEENABLE ,
6897 WINED3DRS_COLORVERTEX ,
6898 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6899 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6900 WINED3DRS_FOGDENSITY ,
6902 WINED3DRS_FOGSTART ,
6903 WINED3DRS_FOGTABLEMODE ,
6904 WINED3DRS_FOGVERTEXMODE ,
6905 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6906 WINED3DRS_LIGHTING ,
6907 WINED3DRS_LOCALVIEWER ,
6908 WINED3DRS_MULTISAMPLEANTIALIAS ,
6909 WINED3DRS_MULTISAMPLEMASK ,
6910 WINED3DRS_NORMALIZENORMALS ,
6911 WINED3DRS_PATCHEDGESTYLE ,
6912 WINED3DRS_POINTSCALE_A ,
6913 WINED3DRS_POINTSCALE_B ,
6914 WINED3DRS_POINTSCALE_C ,
6915 WINED3DRS_POINTSCALEENABLE ,
6916 WINED3DRS_POINTSIZE ,
6917 WINED3DRS_POINTSIZE_MAX ,
6918 WINED3DRS_POINTSIZE_MIN ,
6919 WINED3DRS_POINTSPRITEENABLE ,
6920 WINED3DRS_RANGEFOGENABLE ,
6921 WINED3DRS_SPECULARMATERIALSOURCE ,
6922 WINED3DRS_TWEENFACTOR ,
6923 WINED3DRS_VERTEXBLEND
6926 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6927 WINED3DTSS_TEXCOORDINDEX ,
6928 WINED3DTSS_TEXTURETRANSFORMFLAGS
6931 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6932 WINED3DSAMP_DMAPOFFSET
6935 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6936 DWORD rep = StateTable[state].representative;
6940 WineD3DContext *context;
6943 for(i = 0; i < This->numContexts; i++) {
6944 context = This->contexts[i];
6945 if(isStateDirty(context, rep)) continue;
6947 context->dirtyArray[context->numDirtyEntries++] = rep;
6950 context->isStateDirty[idx] |= (1 << shift);