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; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 WineD3DAdapterChangeGLRam(This, _size); \
104 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
105 if (object->resource.heapMemory == NULL && _size != 0) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
112 *pp##type = (IWineD3D##type *) object; \
113 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
114 TRACE("(%p) : Created resource %p\n", This, object); \
117 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
118 _basetexture.levels = Levels; \
119 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
120 _basetexture.LOD = 0; \
121 _basetexture.dirty = TRUE; \
122 _basetexture.is_srgb = FALSE; \
123 _basetexture.srgb_mode_change_count = 0; \
126 /**********************************************************
127 * Global variable / Constants follow
128 **********************************************************/
129 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
139 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
140 if (IsEqualGUID(riid, &IID_IUnknown)
141 || IsEqualGUID(riid, &IID_IWineD3DBase)
142 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
143 IUnknown_AddRef(iface);
148 return E_NOINTERFACE;
151 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 ULONG refCount = InterlockedIncrement(&This->ref);
155 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
159 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 ULONG refCount = InterlockedDecrement(&This->ref);
163 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
167 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
170 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
173 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
176 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
178 /* TODO: Clean up all the surfaces and textures! */
179 /* NOTE: You must release the parent if the object was created via a callback
180 ** ***************************/
182 if (!list_empty(&This->resources)) {
183 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
184 dumpResources(&This->resources);
187 if(This->contexts) ERR("Context array not freed!\n");
188 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
189 This->haveHardwareCursor = FALSE;
191 IWineD3D_Release(This->wineD3D);
192 This->wineD3D = NULL;
193 HeapFree(GetProcessHeap(), 0, This);
194 TRACE("Freed device %p\n", This);
200 /**********************************************************
201 * IWineD3DDevice implementation follows
202 **********************************************************/
203 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
205 *pParent = This->parent;
206 IUnknown_AddRef(This->parent);
210 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
211 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
212 GLenum error, glUsage;
213 DWORD vboUsage = object->resource.usage;
214 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
215 WARN("Creating a vbo failed once, not trying again\n");
219 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
221 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
222 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
225 /* Make sure that the gl error is cleared. Do not use checkGLcall
226 * here because checkGLcall just prints a fixme and continues. However,
227 * if an error during VBO creation occurs we can fall back to non-vbo operation
228 * with full functionality(but performance loss)
230 while(glGetError() != GL_NO_ERROR);
232 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
233 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
234 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
235 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
236 * to check if the rhw and color values are in the correct format.
239 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
240 error = glGetError();
241 if(object->vbo == 0 || error != GL_NO_ERROR) {
242 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
246 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
247 error = glGetError();
248 if(error != GL_NO_ERROR) {
249 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
253 /* Don't use static, because dx apps tend to update the buffer
254 * quite often even if they specify 0 usage. Because we always keep the local copy
255 * we never read from the vbo and can create a write only opengl buffer.
257 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
258 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
259 case WINED3DUSAGE_DYNAMIC:
260 TRACE("Gl usage = GL_STREAM_DRAW\n");
261 glUsage = GL_STREAM_DRAW_ARB;
263 case WINED3DUSAGE_WRITEONLY:
265 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
266 glUsage = GL_DYNAMIC_DRAW_ARB;
270 /* Reserve memory for the buffer. The amount of data won't change
271 * so we are safe with calling glBufferData once with a NULL ptr and
272 * calling glBufferSubData on updates
274 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
275 error = glGetError();
276 if(error != GL_NO_ERROR) {
277 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
285 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
286 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
287 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
289 object->Flags |= VBFLAG_VBOCREATEFAIL;
294 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
295 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
298 IWineD3DVertexBufferImpl *object;
299 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
300 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
304 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
305 *ppVertexBuffer = NULL;
306 return WINED3DERR_INVALIDCALL;
307 } else if(Pool == WINED3DPOOL_SCRATCH) {
308 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
309 * anyway, SCRATCH vertex buffers aren't useable anywhere
311 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
312 *ppVertexBuffer = NULL;
313 return WINED3DERR_INVALIDCALL;
316 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
318 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
319 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
323 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
324 * drawStridedFast (half-life 2).
326 * Basically converting the vertices in the buffer is quite expensive, and observations
327 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
328 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
330 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
331 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
332 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
333 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
335 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
336 * more. In this call we can convert dx7 buffers too.
338 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
339 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
340 (dxVersion > 7 || !conv) ) {
346 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
347 GLenum error, glUsage;
348 TRACE("Creating VBO for Index Buffer %p\n", object);
350 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
351 * restored on the next draw
353 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
355 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
356 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
361 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
362 error = glGetError();
363 if(error != GL_NO_ERROR || object->vbo == 0) {
364 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
368 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
369 error = glGetError();
370 if(error != GL_NO_ERROR) {
371 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
375 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
376 * copy no readback will be needed
378 glUsage = GL_STATIC_DRAW_ARB;
379 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
380 error = glGetError();
381 if(error != GL_NO_ERROR) {
382 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
386 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
390 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
391 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
396 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
397 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
398 HANDLE *sharedHandle, IUnknown *parent) {
399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
400 IWineD3DIndexBufferImpl *object;
401 TRACE("(%p) Creating index buffer\n", This);
403 /* Allocate the storage for the device */
404 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
406 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
407 CreateIndexBufferVBO(This, object);
410 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
411 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
412 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
417 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
420 IWineD3DStateBlockImpl *object;
424 D3DCREATEOBJECTINSTANCE(object, StateBlock)
425 object->blockType = Type;
427 for(i = 0; i < LIGHTMAP_SIZE; i++) {
428 list_init(&object->lightMap[i]);
431 /* Special case - Used during initialization to produce a placeholder stateblock
432 so other functions called can update a state block */
433 if (Type == WINED3DSBT_INIT) {
434 /* Don't bother increasing the reference count otherwise a device will never
435 be freed due to circular dependencies */
439 temp_result = allocate_shader_constants(object);
440 if (WINED3D_OK != temp_result)
443 /* Otherwise, might as well set the whole state block to the appropriate values */
444 if (This->stateBlock != NULL)
445 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
447 memset(object->streamFreq, 1, sizeof(object->streamFreq));
449 /* Reset the ref and type after kludging it */
450 object->wineD3DDevice = This;
452 object->blockType = Type;
454 TRACE("Updating changed flags appropriate for type %d\n", Type);
456 if (Type == WINED3DSBT_ALL) {
458 TRACE("ALL => Pretend everything has changed\n");
459 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
461 /* Lights are not part of the changed / set structure */
462 for(j = 0; j < LIGHTMAP_SIZE; j++) {
464 LIST_FOR_EACH(e, &object->lightMap[j]) {
465 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
466 light->changed = TRUE;
467 light->enabledChanged = TRUE;
470 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
471 object->contained_render_states[j - 1] = j;
473 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
474 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
475 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
476 object->contained_transform_states[j - 1] = j;
478 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
479 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
480 object->contained_vs_consts_f[j] = j;
482 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
483 for(j = 0; j < MAX_CONST_I; j++) {
484 object->contained_vs_consts_i[j] = j;
486 object->num_contained_vs_consts_i = MAX_CONST_I;
487 for(j = 0; j < MAX_CONST_B; j++) {
488 object->contained_vs_consts_b[j] = j;
490 object->num_contained_vs_consts_b = MAX_CONST_B;
491 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
492 object->contained_ps_consts_f[j] = j;
494 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
495 for(j = 0; j < MAX_CONST_I; j++) {
496 object->contained_ps_consts_i[j] = j;
498 object->num_contained_ps_consts_i = MAX_CONST_I;
499 for(j = 0; j < MAX_CONST_B; j++) {
500 object->contained_ps_consts_b[j] = j;
502 object->num_contained_ps_consts_b = MAX_CONST_B;
503 for(i = 0; i < MAX_TEXTURES; i++) {
504 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
505 object->contained_tss_states[object->num_contained_tss_states].stage = i;
506 object->contained_tss_states[object->num_contained_tss_states].state = j;
507 object->num_contained_tss_states++;
510 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
511 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
512 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
513 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
514 object->num_contained_sampler_states++;
518 for(i = 0; i < MAX_STREAMS; i++) {
519 if(object->streamSource[i]) {
520 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
523 if(object->pIndexData) {
524 IWineD3DIndexBuffer_AddRef(object->pIndexData);
526 if(object->vertexShader) {
527 IWineD3DVertexShader_AddRef(object->vertexShader);
529 if(object->pixelShader) {
530 IWineD3DPixelShader_AddRef(object->pixelShader);
533 } else if (Type == WINED3DSBT_PIXELSTATE) {
535 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
536 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
538 object->changed.pixelShader = TRUE;
540 /* Pixel Shader Constants */
541 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
542 object->contained_ps_consts_f[i] = i;
543 object->changed.pixelShaderConstantsF[i] = TRUE;
545 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
546 for (i = 0; i < MAX_CONST_B; ++i) {
547 object->contained_ps_consts_b[i] = i;
548 object->changed.pixelShaderConstantsB[i] = TRUE;
550 object->num_contained_ps_consts_b = MAX_CONST_B;
551 for (i = 0; i < MAX_CONST_I; ++i) {
552 object->contained_ps_consts_i[i] = i;
553 object->changed.pixelShaderConstantsI[i] = TRUE;
555 object->num_contained_ps_consts_i = MAX_CONST_I;
557 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
558 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
559 object->contained_render_states[i] = SavedPixelStates_R[i];
561 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
562 for (j = 0; j < MAX_TEXTURES; j++) {
563 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
564 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
565 object->contained_tss_states[object->num_contained_tss_states].stage = j;
566 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
567 object->num_contained_tss_states++;
570 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
571 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
572 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
573 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
574 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
575 object->num_contained_sampler_states++;
578 if(object->pixelShader) {
579 IWineD3DPixelShader_AddRef(object->pixelShader);
582 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
583 * on them. This makes releasing the buffer easier
585 for(i = 0; i < MAX_STREAMS; i++) {
586 object->streamSource[i] = NULL;
588 object->pIndexData = NULL;
589 object->vertexShader = NULL;
591 } else if (Type == WINED3DSBT_VERTEXSTATE) {
593 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
594 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
596 object->changed.vertexShader = TRUE;
598 /* Vertex Shader Constants */
599 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
600 object->changed.vertexShaderConstantsF[i] = TRUE;
601 object->contained_vs_consts_f[i] = i;
603 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
604 for (i = 0; i < MAX_CONST_B; ++i) {
605 object->changed.vertexShaderConstantsB[i] = TRUE;
606 object->contained_vs_consts_b[i] = i;
608 object->num_contained_vs_consts_b = MAX_CONST_B;
609 for (i = 0; i < MAX_CONST_I; ++i) {
610 object->changed.vertexShaderConstantsI[i] = TRUE;
611 object->contained_vs_consts_i[i] = i;
613 object->num_contained_vs_consts_i = MAX_CONST_I;
614 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
615 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
616 object->contained_render_states[i] = SavedVertexStates_R[i];
618 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
619 for (j = 0; j < MAX_TEXTURES; j++) {
620 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
621 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
622 object->contained_tss_states[object->num_contained_tss_states].stage = j;
623 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
624 object->num_contained_tss_states++;
627 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
628 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
629 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
630 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
631 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
632 object->num_contained_sampler_states++;
636 for(j = 0; j < LIGHTMAP_SIZE; j++) {
638 LIST_FOR_EACH(e, &object->lightMap[j]) {
639 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
640 light->changed = TRUE;
641 light->enabledChanged = TRUE;
645 for(i = 0; i < MAX_STREAMS; i++) {
646 if(object->streamSource[i]) {
647 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
650 if(object->vertexShader) {
651 IWineD3DVertexShader_AddRef(object->vertexShader);
653 object->pIndexData = NULL;
654 object->pixelShader = NULL;
656 FIXME("Unrecognized state block type %d\n", Type);
659 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
663 /* ************************************
665 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
668 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
670 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.
672 ******************************** */
674 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) {
675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
676 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
677 unsigned int Size = 1;
678 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
679 TRACE("(%p) Create surface\n",This);
681 /** FIXME: Check ranges on the inputs are valid
684 * [in] Quality level. The valid range is between zero and one less than the level
685 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
686 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
687 * values of paired render targets, depth stencil surfaces, and the MultiSample type
689 *******************************/
694 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
696 * If this flag is set, the contents of the depth stencil buffer will be
697 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
698 * with a different depth surface.
700 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
701 ***************************/
703 if(MultisampleQuality < 0) {
704 FIXME("Invalid multisample level %d\n", MultisampleQuality);
705 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
708 if(MultisampleQuality > 0) {
709 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
710 MultisampleQuality=0;
713 /** FIXME: Check that the format is supported
715 *******************************/
717 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
718 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
720 *********************************/
721 if (WINED3DFMT_UNKNOWN == Format) {
723 } else if (Format == WINED3DFMT_DXT1) {
724 /* DXT1 is half byte per pixel */
725 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
727 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
728 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
729 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
731 /* The pitch is a multiple of 4 bytes */
732 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
736 /** Create and initialise the surface resource **/
737 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
738 /* "Standalone" surface */
739 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
741 object->currentDesc.Width = Width;
742 object->currentDesc.Height = Height;
743 object->currentDesc.MultiSampleType = MultiSample;
744 object->currentDesc.MultiSampleQuality = MultisampleQuality;
745 object->glDescription.level = Level;
749 object->Flags |= Discard ? SFLAG_DISCARD : 0;
750 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
751 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
754 if (WINED3DFMT_UNKNOWN != Format) {
755 object->bytesPerPixel = tableEntry->bpp;
757 object->bytesPerPixel = 0;
760 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
762 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
764 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
765 * this function is too deep to need to care about things like this.
766 * Levels need to be checked too, and possibly Type since they all affect what can be done.
767 * ****************************************/
769 case WINED3DPOOL_SCRATCH:
771 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
772 "which are mutually exclusive, setting lockable to TRUE\n");
775 case WINED3DPOOL_SYSTEMMEM:
776 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
777 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
778 case WINED3DPOOL_MANAGED:
779 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
780 "Usage of DYNAMIC which are mutually exclusive, not doing "
781 "anything just telling you.\n");
783 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
784 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
785 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
786 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
789 FIXME("(%p) Unknown pool %d\n", This, Pool);
793 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
794 FIXME("Trying to create a render target that isn't in the default pool\n");
797 /* mark the texture as dirty so that it gets loaded first time around*/
798 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
799 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
800 This, Width, Height, Format, debug_d3dformat(Format),
801 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
803 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
804 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
805 This->ddraw_primary = (IWineD3DSurface *) object;
807 /* Look at the implementation and set the correct Vtable */
810 /* Check if a 3D adapter is available when creating gl surfaces */
812 ERR("OpenGL surfaces are not available without opengl\n");
813 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
814 HeapFree(GetProcessHeap(), 0, object);
815 return WINED3DERR_NOTAVAILABLE;
820 object->lpVtbl = &IWineGDISurface_Vtbl;
824 /* To be sure to catch this */
825 ERR("Unknown requested surface implementation %d!\n", Impl);
826 IWineD3DSurface_Release((IWineD3DSurface *) object);
827 return WINED3DERR_INVALIDCALL;
830 list_init(&object->renderbuffers);
832 /* Call the private setup routine */
833 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
837 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
838 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
839 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
840 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
843 IWineD3DTextureImpl *object;
848 unsigned int pow2Width;
849 unsigned int pow2Height;
850 const GlPixelFormatDesc *glDesc;
851 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
854 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
855 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
856 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
858 /* TODO: It should only be possible to create textures for formats
859 that are reported as supported */
860 if (WINED3DFMT_UNKNOWN >= Format) {
861 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
862 return WINED3DERR_INVALIDCALL;
865 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
866 D3DINITIALIZEBASETEXTURE(object->baseTexture);
867 object->width = Width;
868 object->height = Height;
870 /** Non-power2 support **/
871 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
875 /* Find the nearest pow2 match */
876 pow2Width = pow2Height = 1;
877 while (pow2Width < Width) pow2Width <<= 1;
878 while (pow2Height < Height) pow2Height <<= 1;
880 if(pow2Width != Width || pow2Height != Height) {
882 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
883 HeapFree(GetProcessHeap(), 0, object);
885 return WINED3DERR_INVALIDCALL;
892 /** FIXME: add support for real non-power-two if it's provided by the video card **/
893 /* Precalculated scaling for 'faked' non power of two texture coords */
894 if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
895 (Width != pow2Width || Height != pow2Height)) {
896 object->baseTexture.pow2Matrix[0] = (float)Width;
897 object->baseTexture.pow2Matrix[5] = (float)Height;
898 object->baseTexture.pow2Matrix[10] = 1.0;
899 object->baseTexture.pow2Matrix[15] = 1.0;
900 object->target = GL_TEXTURE_RECTANGLE_ARB;
902 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
903 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
904 object->baseTexture.pow2Matrix[10] = 1.0;
905 object->baseTexture.pow2Matrix[15] = 1.0;
906 object->target = GL_TEXTURE_2D;
908 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
910 /* Calculate levels for mip mapping */
911 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
912 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
913 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
914 return WINED3DERR_INVALIDCALL;
917 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
918 return WINED3DERR_INVALIDCALL;
920 object->baseTexture.levels = 1;
921 } else if (Levels == 0) {
922 TRACE("calculating levels %d\n", object->baseTexture.levels);
923 object->baseTexture.levels++;
926 while (tmpW > 1 || tmpH > 1) {
927 tmpW = max(1, tmpW >> 1);
928 tmpH = max(1, tmpH >> 1);
929 object->baseTexture.levels++;
931 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
934 /* Generate all the surfaces */
937 for (i = 0; i < object->baseTexture.levels; i++)
939 /* use the callback to create the texture surface */
940 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
941 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
942 FIXME("Failed to create surface %p\n", object);
944 object->surfaces[i] = NULL;
945 IWineD3DTexture_Release((IWineD3DTexture *)object);
951 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
952 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
953 /* calculate the next mipmap level */
954 tmpW = max(1, tmpW >> 1);
955 tmpH = max(1, tmpH >> 1);
957 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
959 TRACE("(%p) : Created texture %p\n", This, object);
963 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
964 UINT Width, UINT Height, UINT Depth,
965 UINT Levels, DWORD Usage,
966 WINED3DFORMAT Format, WINED3DPOOL Pool,
967 IWineD3DVolumeTexture **ppVolumeTexture,
968 HANDLE *pSharedHandle, IUnknown *parent,
969 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
972 IWineD3DVolumeTextureImpl *object;
977 const GlPixelFormatDesc *glDesc;
979 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
981 /* TODO: It should only be possible to create textures for formats
982 that are reported as supported */
983 if (WINED3DFMT_UNKNOWN >= Format) {
984 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
985 return WINED3DERR_INVALIDCALL;
987 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
988 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
989 return WINED3DERR_INVALIDCALL;
992 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
993 D3DINITIALIZEBASETEXTURE(object->baseTexture);
995 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
996 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
998 object->width = Width;
999 object->height = Height;
1000 object->depth = Depth;
1002 /* Is NP2 support for volumes needed? */
1003 object->baseTexture.pow2Matrix[ 0] = 1.0;
1004 object->baseTexture.pow2Matrix[ 5] = 1.0;
1005 object->baseTexture.pow2Matrix[10] = 1.0;
1006 object->baseTexture.pow2Matrix[15] = 1.0;
1008 /* Calculate levels for mip mapping */
1009 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1010 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1011 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1012 return WINED3DERR_INVALIDCALL;
1015 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1016 return WINED3DERR_INVALIDCALL;
1019 } else if (Levels == 0) {
1020 object->baseTexture.levels++;
1024 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1025 tmpW = max(1, tmpW >> 1);
1026 tmpH = max(1, tmpH >> 1);
1027 tmpD = max(1, tmpD >> 1);
1028 object->baseTexture.levels++;
1030 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1033 /* Generate all the surfaces */
1038 for (i = 0; i < object->baseTexture.levels; i++)
1041 /* Create the volume */
1042 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
1043 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1046 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1047 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1048 *ppVolumeTexture = NULL;
1052 /* Set its container to this object */
1053 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1055 /* calcualte the next mipmap level */
1056 tmpW = max(1, tmpW >> 1);
1057 tmpH = max(1, tmpH >> 1);
1058 tmpD = max(1, tmpD >> 1);
1060 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1062 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1063 TRACE("(%p) : Created volume texture %p\n", This, object);
1067 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1068 UINT Width, UINT Height, UINT Depth,
1070 WINED3DFORMAT Format, WINED3DPOOL Pool,
1071 IWineD3DVolume** ppVolume,
1072 HANDLE* pSharedHandle, IUnknown *parent) {
1074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1075 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1076 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1078 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1079 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1080 return WINED3DERR_INVALIDCALL;
1083 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1085 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1086 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1088 object->currentDesc.Width = Width;
1089 object->currentDesc.Height = Height;
1090 object->currentDesc.Depth = Depth;
1091 object->bytesPerPixel = formatDesc->bpp;
1093 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1094 object->lockable = TRUE;
1095 object->locked = FALSE;
1096 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1097 object->dirty = TRUE;
1099 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1102 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1103 UINT Levels, DWORD Usage,
1104 WINED3DFORMAT Format, WINED3DPOOL Pool,
1105 IWineD3DCubeTexture **ppCubeTexture,
1106 HANDLE *pSharedHandle, IUnknown *parent,
1107 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1110 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1114 unsigned int pow2EdgeLength = EdgeLength;
1115 const GlPixelFormatDesc *glDesc;
1116 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1118 /* TODO: It should only be possible to create textures for formats
1119 that are reported as supported */
1120 if (WINED3DFMT_UNKNOWN >= Format) {
1121 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1122 return WINED3DERR_INVALIDCALL;
1125 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1126 WARN("(%p) : Tried to create not supported cube texture\n", This);
1127 return WINED3DERR_INVALIDCALL;
1130 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1131 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1133 TRACE("(%p) Create Cube Texture\n", This);
1135 /** Non-power2 support **/
1137 /* Find the nearest pow2 match */
1139 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1141 object->edgeLength = EdgeLength;
1142 /* TODO: support for native non-power 2 */
1143 /* Precalculated scaling for 'faked' non power of two texture coords */
1144 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1145 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1146 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1147 object->baseTexture.pow2Matrix[15] = 1.0;
1149 /* Calculate levels for mip mapping */
1150 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1151 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1152 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1153 HeapFree(GetProcessHeap(), 0, object);
1154 *ppCubeTexture = NULL;
1156 return WINED3DERR_INVALIDCALL;
1159 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1160 HeapFree(GetProcessHeap(), 0, object);
1161 *ppCubeTexture = NULL;
1163 return WINED3DERR_INVALIDCALL;
1166 } else if (Levels == 0) {
1167 object->baseTexture.levels++;
1170 tmpW = max(1, tmpW >> 1);
1171 object->baseTexture.levels++;
1173 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1176 /* Generate all the surfaces */
1178 for (i = 0; i < object->baseTexture.levels; i++) {
1180 /* Create the 6 faces */
1181 for (j = 0; j < 6; j++) {
1183 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1184 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1186 if(hr!= WINED3D_OK) {
1190 for (l = 0; l < j; l++) {
1191 IWineD3DSurface_Release(object->surfaces[l][i]);
1193 for (k = 0; k < i; k++) {
1194 for (l = 0; l < 6; l++) {
1195 IWineD3DSurface_Release(object->surfaces[l][k]);
1199 FIXME("(%p) Failed to create surface\n",object);
1200 HeapFree(GetProcessHeap(),0,object);
1201 *ppCubeTexture = NULL;
1204 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1205 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1207 tmpW = max(1, tmpW >> 1);
1209 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1211 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1212 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1216 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1218 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1219 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1221 /* Just a check to see if we support this type of query */
1223 case WINED3DQUERYTYPE_OCCLUSION:
1224 TRACE("(%p) occlusion query\n", This);
1225 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1228 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1231 case WINED3DQUERYTYPE_EVENT:
1232 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1233 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1234 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1236 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1241 case WINED3DQUERYTYPE_VCACHE:
1242 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1243 case WINED3DQUERYTYPE_VERTEXSTATS:
1244 case WINED3DQUERYTYPE_TIMESTAMP:
1245 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1246 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1247 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1248 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1249 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1250 case WINED3DQUERYTYPE_PIXELTIMINGS:
1251 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1252 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1254 FIXME("(%p) Unhandled query type %d\n", This, Type);
1256 if(NULL == ppQuery || hr != WINED3D_OK) {
1260 D3DCREATEOBJECTINSTANCE(object, Query)
1261 object->type = Type;
1262 /* allocated the 'extended' data based on the type of query requested */
1264 case WINED3DQUERYTYPE_OCCLUSION:
1265 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1266 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1268 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1269 TRACE("(%p) Allocating data for an occlusion query\n", This);
1270 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1273 case WINED3DQUERYTYPE_EVENT:
1274 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1275 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1277 if(GL_SUPPORT(APPLE_FENCE)) {
1278 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1279 checkGLcall("glGenFencesAPPLE");
1280 } else if(GL_SUPPORT(NV_FENCE)) {
1281 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1282 checkGLcall("glGenFencesNV");
1286 case WINED3DQUERYTYPE_VCACHE:
1287 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1288 case WINED3DQUERYTYPE_VERTEXSTATS:
1289 case WINED3DQUERYTYPE_TIMESTAMP:
1290 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1291 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1292 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1293 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1294 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1295 case WINED3DQUERYTYPE_PIXELTIMINGS:
1296 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1297 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1299 object->extendedData = 0;
1300 FIXME("(%p) Unhandled query type %d\n",This , Type);
1302 TRACE("(%p) : Created Query %p\n", This, object);
1306 /*****************************************************************************
1307 * IWineD3DDeviceImpl_SetupFullscreenWindow
1309 * Helper function that modifies a HWND's Style and ExStyle for proper
1313 * iface: Pointer to the IWineD3DDevice interface
1314 * window: Window to setup
1316 *****************************************************************************/
1317 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1320 LONG style, exStyle;
1321 /* Don't do anything if an original style is stored.
1322 * That shouldn't happen
1324 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1325 if (This->style || This->exStyle) {
1326 ERR("(%p): Want to change the window parameters of HWND %p, but "
1327 "another style is stored for restoration afterwards\n", This, window);
1330 /* Get the parameters and save them */
1331 style = GetWindowLongW(window, GWL_STYLE);
1332 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1333 This->style = style;
1334 This->exStyle = exStyle;
1336 /* Filter out window decorations */
1337 style &= ~WS_CAPTION;
1338 style &= ~WS_THICKFRAME;
1339 exStyle &= ~WS_EX_WINDOWEDGE;
1340 exStyle &= ~WS_EX_CLIENTEDGE;
1342 /* Make sure the window is managed, otherwise we won't get keyboard input */
1343 style |= WS_POPUP | WS_SYSMENU;
1345 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1346 This->style, This->exStyle, style, exStyle);
1348 SetWindowLongW(window, GWL_STYLE, style);
1349 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1351 /* Inform the window about the update. */
1352 SetWindowPos(window, HWND_TOP, 0, 0,
1353 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1354 ShowWindow(window, SW_NORMAL);
1357 /*****************************************************************************
1358 * IWineD3DDeviceImpl_RestoreWindow
1360 * Helper function that restores a windows' properties when taking it out
1361 * of fullscreen mode
1364 * iface: Pointer to the IWineD3DDevice interface
1365 * window: Window to setup
1367 *****************************************************************************/
1368 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1371 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1372 * switch, do nothing
1374 if (!This->style && !This->exStyle) return;
1376 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1377 This, window, This->style, This->exStyle);
1379 SetWindowLongW(window, GWL_STYLE, This->style);
1380 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1382 /* Delete the old values */
1386 /* Inform the window about the update */
1387 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1388 0, 0, 0, 0, /* Pos, Size, ignored */
1389 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1392 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1393 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1395 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1396 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1400 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1401 HRESULT hr = WINED3D_OK;
1402 IUnknown *bufferParent;
1403 BOOL displaymode_set = FALSE;
1405 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1407 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1408 * does a device hold a reference to a swap chain giving them a lifetime of the device
1409 * or does the swap chain notify the device of its destruction.
1410 *******************************/
1412 /* Check the params */
1413 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1414 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1415 return WINED3DERR_INVALIDCALL;
1416 } else if (pPresentationParameters->BackBufferCount > 1) {
1417 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");
1420 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1422 /*********************
1423 * Lookup the window Handle and the relating X window handle
1424 ********************/
1426 /* Setup hwnd we are using, plus which display this equates to */
1427 object->win_handle = pPresentationParameters->hDeviceWindow;
1428 if (!object->win_handle) {
1429 object->win_handle = This->createParms.hFocusWindow;
1431 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1433 hDc = GetDC(object->win_handle);
1434 TRACE("Using hDc %p\n", hDc);
1437 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1438 return WINED3DERR_NOTAVAILABLE;
1441 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1442 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1443 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1444 ReleaseDC(object->win_handle, hDc);
1446 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1447 * then the corresponding dimension of the client area of the hDeviceWindow
1448 * (or the focus window, if hDeviceWindow is NULL) is taken.
1449 **********************/
1451 if (pPresentationParameters->Windowed &&
1452 ((pPresentationParameters->BackBufferWidth == 0) ||
1453 (pPresentationParameters->BackBufferHeight == 0) ||
1454 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1457 GetClientRect(object->win_handle, &Rect);
1459 if (pPresentationParameters->BackBufferWidth == 0) {
1460 pPresentationParameters->BackBufferWidth = Rect.right;
1461 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1463 if (pPresentationParameters->BackBufferHeight == 0) {
1464 pPresentationParameters->BackBufferHeight = Rect.bottom;
1465 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1467 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1468 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1469 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1473 /* Put the correct figures in the presentation parameters */
1474 TRACE("Copying across presentation parameters\n");
1475 object->presentParms = *pPresentationParameters;
1477 TRACE("calling rendertarget CB\n");
1478 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1480 object->presentParms.BackBufferWidth,
1481 object->presentParms.BackBufferHeight,
1482 object->presentParms.BackBufferFormat,
1483 object->presentParms.MultiSampleType,
1484 object->presentParms.MultiSampleQuality,
1485 TRUE /* Lockable */,
1486 &object->frontBuffer,
1487 NULL /* pShared (always null)*/);
1488 if (object->frontBuffer != NULL) {
1489 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1490 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1492 ERR("Failed to create the front buffer\n");
1496 /*********************
1497 * Windowed / Fullscreen
1498 *******************/
1501 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1502 * so we should really check to see if there is a fullscreen swapchain already
1503 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1504 **************************************/
1506 if (!pPresentationParameters->Windowed) {
1513 /* Get info on the current display setup */
1515 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1518 /* Change the display settings */
1519 memset(&devmode, 0, sizeof(devmode));
1520 devmode.dmSize = sizeof(devmode);
1521 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1522 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1523 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1524 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1525 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1526 displaymode_set = TRUE;
1528 /* For GetDisplayMode */
1529 This->ddraw_width = devmode.dmPelsWidth;
1530 This->ddraw_height = devmode.dmPelsHeight;
1531 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1533 IWineD3DDevice_SetFullscreen(iface, TRUE);
1535 /* And finally clip mouse to our screen */
1536 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1537 ClipCursor(&clip_rc);
1541 * Create an opengl context for the display visual
1542 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1543 * use different properties after that point in time. FIXME: How to handle when requested format
1544 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1545 * it chooses is identical to the one already being used!
1546 **********************************/
1547 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1549 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1550 if(!object->context)
1551 return E_OUTOFMEMORY;
1552 object->num_contexts = 1;
1554 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1555 if (!object->context[0]) {
1556 ERR("Failed to create a new context\n");
1557 hr = WINED3DERR_NOTAVAILABLE;
1560 TRACE("Context created (HWND=%p, glContext=%p)\n",
1561 object->win_handle, object->context[0]->glCtx);
1564 /*********************
1565 * Create the back, front and stencil buffers
1566 *******************/
1567 if(object->presentParms.BackBufferCount > 0) {
1570 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1571 if(!object->backBuffer) {
1572 ERR("Out of memory\n");
1577 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1578 TRACE("calling rendertarget CB\n");
1579 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1581 object->presentParms.BackBufferWidth,
1582 object->presentParms.BackBufferHeight,
1583 object->presentParms.BackBufferFormat,
1584 object->presentParms.MultiSampleType,
1585 object->presentParms.MultiSampleQuality,
1586 TRUE /* Lockable */,
1587 &object->backBuffer[i],
1588 NULL /* pShared (always null)*/);
1589 if(hr == WINED3D_OK && object->backBuffer[i]) {
1590 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1592 ERR("Cannot create new back buffer\n");
1596 glDrawBuffer(GL_BACK);
1597 checkGLcall("glDrawBuffer(GL_BACK)");
1601 object->backBuffer = NULL;
1603 /* Single buffering - draw to front buffer */
1605 glDrawBuffer(GL_FRONT);
1606 checkGLcall("glDrawBuffer(GL_FRONT)");
1610 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1611 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1612 TRACE("Creating depth stencil buffer\n");
1613 if (This->auto_depth_stencil_buffer == NULL ) {
1614 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1616 object->presentParms.BackBufferWidth,
1617 object->presentParms.BackBufferHeight,
1618 object->presentParms.AutoDepthStencilFormat,
1619 object->presentParms.MultiSampleType,
1620 object->presentParms.MultiSampleQuality,
1621 FALSE /* FIXME: Discard */,
1622 &This->auto_depth_stencil_buffer,
1623 NULL /* pShared (always null)*/ );
1624 if (This->auto_depth_stencil_buffer != NULL)
1625 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1628 /** TODO: A check on width, height and multisample types
1629 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1630 ****************************/
1631 object->wantsDepthStencilBuffer = TRUE;
1633 object->wantsDepthStencilBuffer = FALSE;
1636 TRACE("Created swapchain %p\n", object);
1637 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1641 if (displaymode_set) {
1647 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1650 /* Get info on the current display setup */
1652 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1655 /* Change the display settings */
1656 memset(&devmode, 0, sizeof(devmode));
1657 devmode.dmSize = sizeof(devmode);
1658 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1659 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1660 devmode.dmPelsWidth = object->orig_width;
1661 devmode.dmPelsHeight = object->orig_height;
1662 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1665 if (object->backBuffer) {
1667 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1668 if(object->backBuffer[i]) {
1669 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1670 IUnknown_Release(bufferParent); /* once for the get parent */
1671 if (IUnknown_Release(bufferParent) > 0) {
1672 FIXME("(%p) Something's still holding the back buffer\n",This);
1676 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1677 object->backBuffer = NULL;
1679 if(object->context[0])
1680 DestroyContext(This, object->context[0]);
1681 if(object->frontBuffer) {
1682 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1683 IUnknown_Release(bufferParent); /* once for the get parent */
1684 if (IUnknown_Release(bufferParent) > 0) {
1685 FIXME("(%p) Something's still holding the front buffer\n",This);
1688 HeapFree(GetProcessHeap(), 0, object);
1692 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1693 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1695 TRACE("(%p)\n", This);
1697 return This->NumberOfSwapChains;
1700 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1702 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1704 if(iSwapChain < This->NumberOfSwapChains) {
1705 *pSwapChain = This->swapchains[iSwapChain];
1706 IWineD3DSwapChain_AddRef(*pSwapChain);
1707 TRACE("(%p) returning %p\n", This, *pSwapChain);
1710 TRACE("Swapchain out of range\n");
1712 return WINED3DERR_INVALIDCALL;
1717 * Vertex Declaration
1719 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1720 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1722 IWineD3DVertexDeclarationImpl *object = NULL;
1723 HRESULT hr = WINED3D_OK;
1725 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1726 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1728 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1730 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1735 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1737 unsigned int idx, idx2;
1738 unsigned int offset;
1739 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1740 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1741 BOOL has_blend_idx = has_blend &&
1742 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1743 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1744 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1745 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1746 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1747 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1748 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1750 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1751 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1753 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1754 WINED3DVERTEXELEMENT *elements = NULL;
1757 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1758 if (has_blend_idx) num_blends--;
1760 /* Compute declaration size */
1761 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1762 has_psize + has_diffuse + has_specular + num_textures + 1;
1764 /* convert the declaration */
1765 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1769 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1772 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1773 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1774 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1777 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1778 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1780 elements[idx].UsageIndex = 0;
1783 if (has_blend && (num_blends > 0)) {
1784 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1785 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1787 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1788 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1789 elements[idx].UsageIndex = 0;
1792 if (has_blend_idx) {
1793 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1794 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1795 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1796 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1797 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1799 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1800 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1801 elements[idx].UsageIndex = 0;
1805 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1806 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1807 elements[idx].UsageIndex = 0;
1811 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1812 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1813 elements[idx].UsageIndex = 0;
1817 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1818 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1819 elements[idx].UsageIndex = 0;
1823 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1824 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1825 elements[idx].UsageIndex = 1;
1828 for (idx2 = 0; idx2 < num_textures; idx2++) {
1829 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1830 switch (numcoords) {
1831 case WINED3DFVF_TEXTUREFORMAT1:
1832 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1834 case WINED3DFVF_TEXTUREFORMAT2:
1835 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1837 case WINED3DFVF_TEXTUREFORMAT3:
1838 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1840 case WINED3DFVF_TEXTUREFORMAT4:
1841 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1844 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1845 elements[idx].UsageIndex = idx2;
1849 /* Now compute offsets, and initialize the rest of the fields */
1850 for (idx = 0, offset = 0; idx < size-1; idx++) {
1851 elements[idx].Stream = 0;
1852 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1853 elements[idx].Offset = offset;
1854 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1857 *ppVertexElements = elements;
1861 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1862 WINED3DVERTEXELEMENT* elements = NULL;
1866 size = ConvertFvfToDeclaration(Fvf, &elements);
1867 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1869 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1870 HeapFree(GetProcessHeap(), 0, elements);
1871 if (hr != S_OK) return hr;
1876 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1877 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1879 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1880 HRESULT hr = WINED3D_OK;
1881 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1882 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1884 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1886 if (vertex_declaration) {
1887 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1890 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1892 if (WINED3D_OK != hr) {
1893 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1894 IWineD3DVertexShader_Release(*ppVertexShader);
1895 return WINED3DERR_INVALIDCALL;
1901 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1903 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1904 HRESULT hr = WINED3D_OK;
1906 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1907 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1908 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1909 if (WINED3D_OK == hr) {
1910 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1912 WARN("(%p) : Failed to create pixel shader\n", This);
1918 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1920 IWineD3DPaletteImpl *object;
1922 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1924 /* Create the new object */
1925 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1927 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1928 return E_OUTOFMEMORY;
1931 object->lpVtbl = &IWineD3DPalette_Vtbl;
1933 object->Flags = Flags;
1934 object->parent = Parent;
1935 object->wineD3DDevice = This;
1936 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1938 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1941 HeapFree( GetProcessHeap(), 0, object);
1942 return E_OUTOFMEMORY;
1945 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1947 IWineD3DPalette_Release((IWineD3DPalette *) object);
1951 *Palette = (IWineD3DPalette *) object;
1956 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1960 HDC dcb = NULL, dcs = NULL;
1961 WINEDDCOLORKEY colorkey;
1963 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1966 GetObjectA(hbm, sizeof(BITMAP), &bm);
1967 dcb = CreateCompatibleDC(NULL);
1969 SelectObject(dcb, hbm);
1973 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1974 * couldn't be loaded
1976 memset(&bm, 0, sizeof(bm));
1981 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1982 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1983 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1985 ERR("Wine logo requested, but failed to create surface\n");
1990 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1991 if(FAILED(hr)) goto out;
1992 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1993 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1995 colorkey.dwColorSpaceLowValue = 0;
1996 colorkey.dwColorSpaceHighValue = 0;
1997 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1999 /* Fill the surface with a white color to show that wined3d is there */
2000 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2013 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2015 IWineD3DSwapChainImpl *swapchain;
2019 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2020 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2022 /* TODO: Test if OpenGL is compiled in and loaded */
2024 TRACE("(%p) : Creating stateblock\n", This);
2025 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2026 hr = IWineD3DDevice_CreateStateBlock(iface,
2028 (IWineD3DStateBlock **)&This->stateBlock,
2030 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2031 WARN("Failed to create stateblock\n");
2034 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2035 This->updateStateBlock = This->stateBlock;
2036 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2038 hr = allocate_shader_constants(This->updateStateBlock);
2039 if (WINED3D_OK != hr) {
2043 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2044 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2045 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2047 /* Initialize the texture unit mapping to a 1:1 mapping */
2048 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2049 if (state < GL_LIMITS(fragment_samplers)) {
2050 This->texUnitMap[state] = state;
2051 This->rev_tex_unit_map[state] = state;
2053 This->texUnitMap[state] = -1;
2054 This->rev_tex_unit_map[state] = -1;
2058 /* Setup the implicit swapchain */
2059 TRACE("Creating implicit swapchain\n");
2060 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2061 if (FAILED(hr) || !swapchain) {
2062 WARN("Failed to create implicit swapchain\n");
2066 This->NumberOfSwapChains = 1;
2067 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2068 if(!This->swapchains) {
2069 ERR("Out of memory!\n");
2072 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2074 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2075 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2076 This->render_targets[0] = swapchain->backBuffer[0];
2077 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2080 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2081 This->render_targets[0] = swapchain->frontBuffer;
2082 This->lastActiveRenderTarget = swapchain->frontBuffer;
2084 IWineD3DSurface_AddRef(This->render_targets[0]);
2085 This->activeContext = swapchain->context[0];
2086 This->lastThread = GetCurrentThreadId();
2088 /* Depth Stencil support */
2089 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2090 if (NULL != This->stencilBufferTarget) {
2091 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2094 /* Set up some starting GL setup */
2097 /* Setup all the devices defaults */
2098 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2100 IWineD3DImpl_CheckGraphicsMemory();
2103 { /* Set a default viewport */
2107 vp.Width = pPresentationParameters->BackBufferWidth;
2108 vp.Height = pPresentationParameters->BackBufferHeight;
2111 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2114 /* Initialize the current view state */
2115 This->view_ident = 1;
2116 This->contexts[0]->last_was_rhw = 0;
2117 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2118 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2120 switch(wined3d_settings.offscreen_rendering_mode) {
2123 This->offscreenBuffer = GL_BACK;
2126 case ORM_BACKBUFFER:
2128 if(GL_LIMITS(aux_buffers) > 0) {
2129 TRACE("Using auxilliary buffer for offscreen rendering\n");
2130 This->offscreenBuffer = GL_AUX0;
2132 TRACE("Using back buffer for offscreen rendering\n");
2133 This->offscreenBuffer = GL_BACK;
2138 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2141 /* Clear the screen */
2142 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2143 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2146 This->d3d_initialized = TRUE;
2148 if(wined3d_settings.logo) {
2149 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2154 HeapFree(GetProcessHeap(), 0, This->render_targets);
2155 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2156 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2157 HeapFree(GetProcessHeap(), 0, This->swapchains);
2158 This->NumberOfSwapChains = 0;
2160 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2162 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2163 if(This->stateBlock) {
2164 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2165 This->stateBlock = NULL;
2170 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2174 TRACE("(%p)\n", This);
2176 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2178 /* I don't think that the interface guarants that the device is destroyed from the same thread
2179 * it was created. Thus make sure a context is active for the glDelete* calls
2181 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2183 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2185 TRACE("Deleting high order patches\n");
2186 for(i = 0; i < PATCHMAP_SIZE; i++) {
2187 struct list *e1, *e2;
2188 struct WineD3DRectPatch *patch;
2189 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2190 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2191 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2195 /* Delete the palette conversion shader if it is around */
2196 if(This->paletteConversionShader) {
2197 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2198 This->paletteConversionShader = 0;
2201 /* Delete the pbuffer context if there is any */
2202 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2204 /* Delete the mouse cursor texture */
2205 if(This->cursorTexture) {
2207 glDeleteTextures(1, &This->cursorTexture);
2209 This->cursorTexture = 0;
2212 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2213 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2215 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2216 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2219 /* Release the update stateblock */
2220 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2221 if(This->updateStateBlock != This->stateBlock)
2222 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2224 This->updateStateBlock = NULL;
2226 { /* because were not doing proper internal refcounts releasing the primary state block
2227 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2228 to set this->stateBlock = NULL; first */
2229 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2230 This->stateBlock = NULL;
2232 /* Release the stateblock */
2233 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2234 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2238 /* Release the buffers (with sanity checks)*/
2239 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2240 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2241 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2242 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2244 This->stencilBufferTarget = NULL;
2246 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2247 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2248 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2250 TRACE("Setting rendertarget to NULL\n");
2251 This->render_targets[0] = NULL;
2253 if (This->auto_depth_stencil_buffer) {
2254 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2255 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2257 This->auto_depth_stencil_buffer = NULL;
2260 for(i=0; i < This->NumberOfSwapChains; i++) {
2261 TRACE("Releasing the implicit swapchain %d\n", i);
2262 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2263 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2267 HeapFree(GetProcessHeap(), 0, This->swapchains);
2268 This->swapchains = NULL;
2269 This->NumberOfSwapChains = 0;
2271 HeapFree(GetProcessHeap(), 0, This->render_targets);
2272 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2273 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2274 This->render_targets = NULL;
2275 This->fbo_color_attachments = NULL;
2276 This->draw_buffers = NULL;
2279 This->d3d_initialized = FALSE;
2283 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2285 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2287 /* Setup the window for fullscreen mode */
2288 if(fullscreen && !This->ddraw_fullscreen) {
2289 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2290 } else if(!fullscreen && This->ddraw_fullscreen) {
2291 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2294 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2295 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2296 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2299 This->ddraw_fullscreen = fullscreen;
2302 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2303 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2304 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2306 * There is no way to deactivate thread safety once it is enabled.
2308 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2311 /*For now just store the flag(needed in case of ddraw) */
2312 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2317 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2321 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2324 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2326 /* Resize the screen even without a window:
2327 * The app could have unset it with SetCooperativeLevel, but not called
2328 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2329 * but we don't have any hwnd
2332 memset(&devmode, 0, sizeof(devmode));
2333 devmode.dmSize = sizeof(devmode);
2334 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2335 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2336 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2337 devmode.dmPelsWidth = pMode->Width;
2338 devmode.dmPelsHeight = pMode->Height;
2340 devmode.dmDisplayFrequency = pMode->RefreshRate;
2341 if (pMode->RefreshRate != 0) {
2342 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2345 /* Only change the mode if necessary */
2346 if( (This->ddraw_width == pMode->Width) &&
2347 (This->ddraw_height == pMode->Height) &&
2348 (This->ddraw_format == pMode->Format) &&
2349 (pMode->RefreshRate == 0) ) {
2353 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2354 if (ret != DISP_CHANGE_SUCCESSFUL) {
2355 if(devmode.dmDisplayFrequency != 0) {
2356 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2357 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2358 devmode.dmDisplayFrequency = 0;
2359 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2361 if(ret != DISP_CHANGE_SUCCESSFUL) {
2362 return WINED3DERR_NOTAVAILABLE;
2366 /* Store the new values */
2367 This->ddraw_width = pMode->Width;
2368 This->ddraw_height = pMode->Height;
2369 This->ddraw_format = pMode->Format;
2371 /* Only do this with a window of course */
2372 if(This->ddraw_window)
2373 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2375 /* And finally clip mouse to our screen */
2376 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2377 ClipCursor(&clip_rc);
2382 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2384 *ppD3D= This->wineD3D;
2385 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2386 IWineD3D_AddRef(*ppD3D);
2390 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2393 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2394 (This->adapter->TextureRam/(1024*1024)),
2395 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2396 /* return simulated texture memory left */
2397 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2405 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2408 /* Update the current state block */
2409 This->updateStateBlock->changed.fvf = TRUE;
2411 if(This->updateStateBlock->fvf == fvf) {
2412 TRACE("Application is setting the old fvf over, nothing to do\n");
2416 This->updateStateBlock->fvf = fvf;
2417 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2418 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2423 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2425 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2426 *pfvf = This->stateBlock->fvf;
2431 * Get / Set Stream Source
2433 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2435 IWineD3DVertexBuffer *oldSrc;
2437 if (StreamNumber >= MAX_STREAMS) {
2438 WARN("Stream out of range %d\n", StreamNumber);
2439 return WINED3DERR_INVALIDCALL;
2442 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2443 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2445 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2447 if(oldSrc == pStreamData &&
2448 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2449 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2450 TRACE("Application is setting the old values over, nothing to do\n");
2454 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2456 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2457 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2460 /* Handle recording of state blocks */
2461 if (This->isRecordingState) {
2462 TRACE("Recording... not performing anything\n");
2463 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2464 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2468 /* Need to do a getParent and pass the reffs up */
2469 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2470 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2471 so for now, just count internally */
2472 if (pStreamData != NULL) {
2473 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2474 InterlockedIncrement(&vbImpl->bindCount);
2475 IWineD3DVertexBuffer_AddRef(pStreamData);
2477 if (oldSrc != NULL) {
2478 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2479 IWineD3DVertexBuffer_Release(oldSrc);
2482 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2487 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2490 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2491 This->stateBlock->streamSource[StreamNumber],
2492 This->stateBlock->streamOffset[StreamNumber],
2493 This->stateBlock->streamStride[StreamNumber]);
2495 if (StreamNumber >= MAX_STREAMS) {
2496 WARN("Stream out of range %d\n", StreamNumber);
2497 return WINED3DERR_INVALIDCALL;
2499 *pStream = This->stateBlock->streamSource[StreamNumber];
2500 *pStride = This->stateBlock->streamStride[StreamNumber];
2502 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2505 if (*pStream != NULL) {
2506 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2511 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2513 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2514 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2516 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2517 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2519 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2520 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2522 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2523 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2524 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2530 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2533 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2534 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2536 TRACE("(%p) : returning %d\n", This, *Divider);
2542 * Get / Set & Multiply Transform
2544 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2547 /* Most of this routine, comments included copied from ddraw tree initially: */
2548 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2550 /* Handle recording of state blocks */
2551 if (This->isRecordingState) {
2552 TRACE("Recording... not performing anything\n");
2553 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2554 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2559 * If the new matrix is the same as the current one,
2560 * we cut off any further processing. this seems to be a reasonable
2561 * optimization because as was noticed, some apps (warcraft3 for example)
2562 * tend towards setting the same matrix repeatedly for some reason.
2564 * From here on we assume that the new matrix is different, wherever it matters.
2566 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2567 TRACE("The app is setting the same matrix over again\n");
2570 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2574 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2575 where ViewMat = Camera space, WorldMat = world space.
2577 In OpenGL, camera and world space is combined into GL_MODELVIEW
2578 matrix. The Projection matrix stay projection matrix.
2581 /* Capture the times we can just ignore the change for now */
2582 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2583 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2584 /* Handled by the state manager */
2587 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2591 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2593 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2594 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2598 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2599 WINED3DMATRIX *mat = NULL;
2602 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2603 * below means it will be recorded in a state block change, but it
2604 * works regardless where it is recorded.
2605 * If this is found to be wrong, change to StateBlock.
2607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2608 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2610 if (State < HIGHEST_TRANSFORMSTATE)
2612 mat = &This->updateStateBlock->transforms[State];
2614 FIXME("Unhandled transform state!!\n");
2617 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2619 /* Apply change via set transform - will reapply to eg. lights this way */
2620 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2626 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2627 you can reference any indexes you want as long as that number max are enabled at any
2628 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2629 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2630 but when recording, just build a chain pretty much of commands to be replayed. */
2632 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2634 PLIGHTINFOEL *object = NULL;
2635 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2639 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2641 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2645 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2646 return WINED3DERR_INVALIDCALL;
2649 switch(pLight->Type) {
2650 case WINED3DLIGHT_POINT:
2651 case WINED3DLIGHT_SPOT:
2652 case WINED3DLIGHT_PARALLELPOINT:
2653 case WINED3DLIGHT_GLSPOT:
2654 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2657 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2658 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2659 return WINED3DERR_INVALIDCALL;
2663 case WINED3DLIGHT_DIRECTIONAL:
2664 /* Ignores attenuation */
2668 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2669 return WINED3DERR_INVALIDCALL;
2672 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2673 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2674 if(object->OriginalIndex == Index) break;
2679 TRACE("Adding new light\n");
2680 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2682 ERR("Out of memory error when allocating a light\n");
2683 return E_OUTOFMEMORY;
2685 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2686 object->glIndex = -1;
2687 object->OriginalIndex = Index;
2688 object->changed = TRUE;
2691 /* Initialize the object */
2692 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,
2693 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2694 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2695 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2696 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2697 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2698 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2700 /* Save away the information */
2701 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2703 switch (pLight->Type) {
2704 case WINED3DLIGHT_POINT:
2706 object->lightPosn[0] = pLight->Position.x;
2707 object->lightPosn[1] = pLight->Position.y;
2708 object->lightPosn[2] = pLight->Position.z;
2709 object->lightPosn[3] = 1.0f;
2710 object->cutoff = 180.0f;
2714 case WINED3DLIGHT_DIRECTIONAL:
2716 object->lightPosn[0] = -pLight->Direction.x;
2717 object->lightPosn[1] = -pLight->Direction.y;
2718 object->lightPosn[2] = -pLight->Direction.z;
2719 object->lightPosn[3] = 0.0;
2720 object->exponent = 0.0f;
2721 object->cutoff = 180.0f;
2724 case WINED3DLIGHT_SPOT:
2726 object->lightPosn[0] = pLight->Position.x;
2727 object->lightPosn[1] = pLight->Position.y;
2728 object->lightPosn[2] = pLight->Position.z;
2729 object->lightPosn[3] = 1.0;
2732 object->lightDirn[0] = pLight->Direction.x;
2733 object->lightDirn[1] = pLight->Direction.y;
2734 object->lightDirn[2] = pLight->Direction.z;
2735 object->lightDirn[3] = 1.0;
2738 * opengl-ish and d3d-ish spot lights use too different models for the
2739 * light "intensity" as a function of the angle towards the main light direction,
2740 * so we only can approximate very roughly.
2741 * however spot lights are rather rarely used in games (if ever used at all).
2742 * furthermore if still used, probably nobody pays attention to such details.
2744 if (pLight->Falloff == 0) {
2745 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2746 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2747 * will always be 1.0 for both of them, and we don't have to care for the
2748 * rest of the rather complex calculation
2750 object->exponent = 0;
2752 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2753 if (rho < 0.0001) rho = 0.0001f;
2754 object->exponent = -0.3/log(cos(rho/2));
2756 if (object->exponent > 128.0) {
2757 object->exponent = 128.0;
2759 object->cutoff = pLight->Phi*90/M_PI;
2765 FIXME("Unrecognized light type %d\n", pLight->Type);
2768 /* Update the live definitions if the light is currently assigned a glIndex */
2769 if (object->glIndex != -1 && !This->isRecordingState) {
2770 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2775 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2776 PLIGHTINFOEL *lightInfo = NULL;
2777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2778 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2780 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2782 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2783 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2784 if(lightInfo->OriginalIndex == Index) break;
2788 if (lightInfo == NULL) {
2789 TRACE("Light information requested but light not defined\n");
2790 return WINED3DERR_INVALIDCALL;
2793 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2798 * Get / Set Light Enable
2799 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2801 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2802 PLIGHTINFOEL *lightInfo = NULL;
2803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2804 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2806 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2808 /* Tests show true = 128...not clear why */
2809 Enable = Enable? 128: 0;
2811 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2812 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2813 if(lightInfo->OriginalIndex == Index) break;
2816 TRACE("Found light: %p\n", lightInfo);
2818 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2819 if (lightInfo == NULL) {
2821 TRACE("Light enabled requested but light not defined, so defining one!\n");
2822 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2824 /* Search for it again! Should be fairly quick as near head of list */
2825 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2826 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2827 if(lightInfo->OriginalIndex == Index) break;
2830 if (lightInfo == NULL) {
2831 FIXME("Adding default lights has failed dismally\n");
2832 return WINED3DERR_INVALIDCALL;
2836 lightInfo->enabledChanged = TRUE;
2838 if(lightInfo->glIndex != -1) {
2839 if(!This->isRecordingState) {
2840 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2843 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2844 lightInfo->glIndex = -1;
2846 TRACE("Light already disabled, nothing to do\n");
2848 lightInfo->enabled = FALSE;
2850 lightInfo->enabled = TRUE;
2851 if (lightInfo->glIndex != -1) {
2853 TRACE("Nothing to do as light was enabled\n");
2856 /* Find a free gl light */
2857 for(i = 0; i < This->maxConcurrentLights; i++) {
2858 if(This->stateBlock->activeLights[i] == NULL) {
2859 This->stateBlock->activeLights[i] = lightInfo;
2860 lightInfo->glIndex = i;
2864 if(lightInfo->glIndex == -1) {
2865 /* Our tests show that Windows returns D3D_OK in this situation, even with
2866 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2867 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2868 * as well for those lights.
2870 * TODO: Test how this affects rendering
2872 FIXME("Too many concurrently active lights\n");
2876 /* i == lightInfo->glIndex */
2877 if(!This->isRecordingState) {
2878 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2886 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2888 PLIGHTINFOEL *lightInfo = NULL;
2889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2891 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2892 TRACE("(%p) : for idx(%d)\n", This, Index);
2894 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2895 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2896 if(lightInfo->OriginalIndex == Index) break;
2900 if (lightInfo == NULL) {
2901 TRACE("Light enabled state requested but light not defined\n");
2902 return WINED3DERR_INVALIDCALL;
2904 /* true is 128 according to SetLightEnable */
2905 *pEnable = lightInfo->enabled ? 128 : 0;
2910 * Get / Set Clip Planes
2912 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2914 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2916 /* Validate Index */
2917 if (Index >= GL_LIMITS(clipplanes)) {
2918 TRACE("Application has requested clipplane this device doesn't support\n");
2919 return WINED3DERR_INVALIDCALL;
2922 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2924 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2925 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2926 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2927 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2928 TRACE("Application is setting old values over, nothing to do\n");
2932 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2933 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2934 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2935 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2937 /* Handle recording of state blocks */
2938 if (This->isRecordingState) {
2939 TRACE("Recording... not performing anything\n");
2943 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2948 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2950 TRACE("(%p) : for idx %d\n", This, Index);
2952 /* Validate Index */
2953 if (Index >= GL_LIMITS(clipplanes)) {
2954 TRACE("Application has requested clipplane this device doesn't support\n");
2955 return WINED3DERR_INVALIDCALL;
2958 pPlane[0] = This->stateBlock->clipplane[Index][0];
2959 pPlane[1] = This->stateBlock->clipplane[Index][1];
2960 pPlane[2] = This->stateBlock->clipplane[Index][2];
2961 pPlane[3] = This->stateBlock->clipplane[Index][3];
2966 * Get / Set Clip Plane Status
2967 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2969 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2971 FIXME("(%p) : stub\n", This);
2972 if (NULL == pClipStatus) {
2973 return WINED3DERR_INVALIDCALL;
2975 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2976 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2980 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2982 FIXME("(%p) : stub\n", This);
2983 if (NULL == pClipStatus) {
2984 return WINED3DERR_INVALIDCALL;
2986 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2987 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2992 * Get / Set Material
2994 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2997 This->updateStateBlock->changed.material = TRUE;
2998 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3000 /* Handle recording of state blocks */
3001 if (This->isRecordingState) {
3002 TRACE("Recording... not performing anything\n");
3006 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3010 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3012 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3013 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3014 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3015 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3016 pMaterial->Ambient.b, pMaterial->Ambient.a);
3017 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3018 pMaterial->Specular.b, pMaterial->Specular.a);
3019 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3020 pMaterial->Emissive.b, pMaterial->Emissive.a);
3021 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3029 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3031 IWineD3DIndexBuffer *oldIdxs;
3033 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3034 oldIdxs = This->updateStateBlock->pIndexData;
3036 This->updateStateBlock->changed.indices = TRUE;
3037 This->updateStateBlock->pIndexData = pIndexData;
3039 /* Handle recording of state blocks */
3040 if (This->isRecordingState) {
3041 TRACE("Recording... not performing anything\n");
3042 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3043 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3047 if(oldIdxs != pIndexData) {
3048 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3049 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3050 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3055 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3058 *ppIndexData = This->stateBlock->pIndexData;
3060 /* up ref count on ppindexdata */
3062 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3063 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3065 TRACE("(%p) No index data set\n", This);
3067 TRACE("Returning %p\n", *ppIndexData);
3072 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3073 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3075 TRACE("(%p)->(%d)\n", This, BaseIndex);
3077 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3078 TRACE("Application is setting the old value over, nothing to do\n");
3082 This->updateStateBlock->baseVertexIndex = BaseIndex;
3084 if (This->isRecordingState) {
3085 TRACE("Recording... not performing anything\n");
3088 /* The base vertex index affects the stream sources */
3089 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3093 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3094 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3095 TRACE("(%p) : base_index %p\n", This, base_index);
3097 *base_index = This->stateBlock->baseVertexIndex;
3099 TRACE("Returning %u\n", *base_index);
3105 * Get / Set Viewports
3107 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3110 TRACE("(%p)\n", This);
3111 This->updateStateBlock->changed.viewport = TRUE;
3112 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3114 /* Handle recording of state blocks */
3115 if (This->isRecordingState) {
3116 TRACE("Recording... not performing anything\n");
3120 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3121 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3123 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3128 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3130 TRACE("(%p)\n", This);
3131 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3136 * Get / Set Render States
3137 * TODO: Verify against dx9 definitions
3139 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3142 DWORD oldValue = This->stateBlock->renderState[State];
3144 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3146 This->updateStateBlock->changed.renderState[State] = TRUE;
3147 This->updateStateBlock->renderState[State] = Value;
3149 /* Handle recording of state blocks */
3150 if (This->isRecordingState) {
3151 TRACE("Recording... not performing anything\n");
3155 /* Compared here and not before the assignment to allow proper stateblock recording */
3156 if(Value == oldValue) {
3157 TRACE("Application is setting the old value over, nothing to do\n");
3159 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3165 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3167 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3168 *pValue = This->stateBlock->renderState[State];
3173 * Get / Set Sampler States
3174 * TODO: Verify against dx9 definitions
3177 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3181 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3182 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3184 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3185 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3189 * SetSampler is designed to allow for more than the standard up to 8 textures
3190 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3191 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3193 * http://developer.nvidia.com/object/General_FAQ.html#t6
3195 * There are two new settings for GForce
3197 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3198 * and the texture one:
3199 * GL_MAX_TEXTURE_COORDS_ARB.
3200 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3203 oldValue = This->stateBlock->samplerState[Sampler][Type];
3204 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3205 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3207 /* Handle recording of state blocks */
3208 if (This->isRecordingState) {
3209 TRACE("Recording... not performing anything\n");
3213 if(oldValue == Value) {
3214 TRACE("Application is setting the old value over, nothing to do\n");
3218 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3223 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3226 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3227 This, Sampler, debug_d3dsamplerstate(Type), Type);
3229 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3230 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3233 *Value = This->stateBlock->samplerState[Sampler][Type];
3234 TRACE("(%p) : Returning %#x\n", This, *Value);
3239 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3242 This->updateStateBlock->changed.scissorRect = TRUE;
3243 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3244 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3247 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3249 if(This->isRecordingState) {
3250 TRACE("Recording... not performing anything\n");
3254 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3259 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3262 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3263 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3267 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3269 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3271 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3273 This->updateStateBlock->vertexDecl = pDecl;
3274 This->updateStateBlock->changed.vertexDecl = TRUE;
3276 if (This->isRecordingState) {
3277 TRACE("Recording... not performing anything\n");
3279 } else if(pDecl == oldDecl) {
3280 /* Checked after the assignment to allow proper stateblock recording */
3281 TRACE("Application is setting the old declaration over, nothing to do\n");
3285 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3289 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3292 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3294 *ppDecl = This->stateBlock->vertexDecl;
3295 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3299 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3301 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3303 This->updateStateBlock->vertexShader = pShader;
3304 This->updateStateBlock->changed.vertexShader = TRUE;
3306 if (This->isRecordingState) {
3307 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3308 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3309 TRACE("Recording... not performing anything\n");
3311 } else if(oldShader == pShader) {
3312 /* Checked here to allow proper stateblock recording */
3313 TRACE("App is setting the old shader over, nothing to do\n");
3317 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3318 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3319 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3321 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3326 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3327 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3329 if (NULL == ppShader) {
3330 return WINED3DERR_INVALIDCALL;
3332 *ppShader = This->stateBlock->vertexShader;
3333 if( NULL != *ppShader)
3334 IWineD3DVertexShader_AddRef(*ppShader);
3336 TRACE("(%p) : returning %p\n", This, *ppShader);
3340 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3341 IWineD3DDevice *iface,
3343 CONST BOOL *srcData,
3346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3347 int i, cnt = min(count, MAX_CONST_B - start);
3349 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3350 iface, srcData, start, count);
3352 if (srcData == NULL || cnt < 0)
3353 return WINED3DERR_INVALIDCALL;
3355 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3356 for (i = 0; i < cnt; i++)
3357 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3359 for (i = start; i < cnt + start; ++i) {
3360 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3363 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3368 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3369 IWineD3DDevice *iface,
3374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3375 int cnt = min(count, MAX_CONST_B - start);
3377 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3378 iface, dstData, start, count);
3380 if (dstData == NULL || cnt < 0)
3381 return WINED3DERR_INVALIDCALL;
3383 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3387 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3388 IWineD3DDevice *iface,
3393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3394 int i, cnt = min(count, MAX_CONST_I - start);
3396 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3397 iface, srcData, start, count);
3399 if (srcData == NULL || cnt < 0)
3400 return WINED3DERR_INVALIDCALL;
3402 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3403 for (i = 0; i < cnt; i++)
3404 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3405 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3407 for (i = start; i < cnt + start; ++i) {
3408 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3411 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3416 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3417 IWineD3DDevice *iface,
3422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3423 int cnt = min(count, MAX_CONST_I - start);
3425 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3426 iface, dstData, start, count);
3428 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3429 return WINED3DERR_INVALIDCALL;
3431 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3435 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3436 IWineD3DDevice *iface,
3438 CONST float *srcData,
3441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3444 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3445 iface, srcData, start, count);
3447 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3448 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3449 return WINED3DERR_INVALIDCALL;
3451 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3453 for (i = 0; i < count; i++)
3454 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3455 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3458 for (i = start; i < count + start; ++i) {
3459 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3460 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3461 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3462 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3463 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3465 ptr->idx[ptr->count++] = i;
3466 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3470 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3475 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3476 IWineD3DDevice *iface,
3481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3482 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3484 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3485 iface, dstData, start, count);
3487 if (dstData == NULL || cnt < 0)
3488 return WINED3DERR_INVALIDCALL;
3490 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3494 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3496 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3497 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3501 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3502 int i = This->rev_tex_unit_map[unit];
3503 int j = This->texUnitMap[stage];
3505 This->texUnitMap[stage] = unit;
3506 if (i != -1 && i != stage) {
3507 This->texUnitMap[i] = -1;
3510 This->rev_tex_unit_map[unit] = stage;
3511 if (j != -1 && j != unit) {
3512 This->rev_tex_unit_map[j] = -1;
3516 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3519 for (i = 0; i < MAX_TEXTURES; ++i) {
3520 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3521 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3522 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3523 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3524 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3525 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3526 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3527 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3529 if (color_op == WINED3DTOP_DISABLE) {
3530 /* Not used, and disable higher stages */
3531 while (i < MAX_TEXTURES) {
3532 This->fixed_function_usage_map[i] = FALSE;
3538 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3539 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3540 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3541 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3542 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3543 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3544 This->fixed_function_usage_map[i] = TRUE;
3546 This->fixed_function_usage_map[i] = FALSE;
3549 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3550 This->fixed_function_usage_map[i+1] = TRUE;
3555 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3558 device_update_fixed_function_usage_map(This);
3560 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3561 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3562 if (!This->fixed_function_usage_map[i]) continue;
3564 if (This->texUnitMap[i] != i) {
3565 device_map_stage(This, i, i);
3566 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3567 markTextureStagesDirty(This, i);
3573 /* Now work out the mapping */
3575 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3576 if (!This->fixed_function_usage_map[i]) continue;
3578 if (This->texUnitMap[i] != tex) {
3579 device_map_stage(This, i, tex);
3580 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3581 markTextureStagesDirty(This, i);
3588 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3589 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3592 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3593 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3594 device_map_stage(This, i, i);
3595 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3596 if (i < MAX_TEXTURES) {
3597 markTextureStagesDirty(This, i);
3603 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3604 int current_mapping = This->rev_tex_unit_map[unit];
3606 if (current_mapping == -1) {
3607 /* Not currently used */
3611 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3612 /* Used by a fragment sampler */
3614 if (!pshader_sampler_tokens) {
3615 /* No pixel shader, check fixed function */
3616 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3619 /* Pixel shader, check the shader's sampler map */
3620 return !pshader_sampler_tokens[current_mapping];
3623 /* Used by a vertex sampler */
3624 return !vshader_sampler_tokens[current_mapping];
3627 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3628 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3629 DWORD *pshader_sampler_tokens = NULL;
3630 int start = GL_LIMITS(combined_samplers) - 1;
3634 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3636 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3637 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3638 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3641 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3642 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3643 if (vshader_sampler_tokens[i]) {
3644 if (This->texUnitMap[vsampler_idx] != -1) {
3645 /* Already mapped somewhere */
3649 while (start >= 0) {
3650 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3651 device_map_stage(This, vsampler_idx, start);
3652 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3664 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3665 BOOL vs = use_vs(This);
3666 BOOL ps = use_ps(This);
3669 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3670 * that would be really messy and require shader recompilation
3671 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3672 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3675 device_map_psamplers(This);
3677 device_map_fixed_function_samplers(This);
3681 device_map_vsamplers(This, ps);
3685 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3687 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3688 This->updateStateBlock->pixelShader = pShader;
3689 This->updateStateBlock->changed.pixelShader = TRUE;
3691 /* Handle recording of state blocks */
3692 if (This->isRecordingState) {
3693 TRACE("Recording... not performing anything\n");
3696 if (This->isRecordingState) {
3697 TRACE("Recording... not performing anything\n");
3698 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3699 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3703 if(pShader == oldShader) {
3704 TRACE("App is setting the old pixel shader over, nothing to do\n");
3708 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3709 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3711 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3712 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3717 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3720 if (NULL == ppShader) {
3721 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3722 return WINED3DERR_INVALIDCALL;
3725 *ppShader = This->stateBlock->pixelShader;
3726 if (NULL != *ppShader) {
3727 IWineD3DPixelShader_AddRef(*ppShader);
3729 TRACE("(%p) : returning %p\n", This, *ppShader);
3733 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3734 IWineD3DDevice *iface,
3736 CONST BOOL *srcData,
3739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3740 int i, cnt = min(count, MAX_CONST_B - start);
3742 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3743 iface, srcData, start, count);
3745 if (srcData == NULL || cnt < 0)
3746 return WINED3DERR_INVALIDCALL;
3748 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3749 for (i = 0; i < cnt; i++)
3750 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3752 for (i = start; i < cnt + start; ++i) {
3753 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3756 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3761 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3762 IWineD3DDevice *iface,
3767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3768 int cnt = min(count, MAX_CONST_B - start);
3770 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3771 iface, dstData, start, count);
3773 if (dstData == NULL || cnt < 0)
3774 return WINED3DERR_INVALIDCALL;
3776 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3780 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3781 IWineD3DDevice *iface,
3786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3787 int i, cnt = min(count, MAX_CONST_I - start);
3789 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3790 iface, srcData, start, count);
3792 if (srcData == NULL || cnt < 0)
3793 return WINED3DERR_INVALIDCALL;
3795 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3796 for (i = 0; i < cnt; i++)
3797 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3798 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3800 for (i = start; i < cnt + start; ++i) {
3801 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3804 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3809 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3810 IWineD3DDevice *iface,
3815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3816 int cnt = min(count, MAX_CONST_I - start);
3818 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3819 iface, dstData, start, count);
3821 if (dstData == NULL || cnt < 0)
3822 return WINED3DERR_INVALIDCALL;
3824 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3828 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3829 IWineD3DDevice *iface,
3831 CONST float *srcData,
3834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3837 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3838 iface, srcData, start, count);
3840 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3841 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3842 return WINED3DERR_INVALIDCALL;
3844 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3846 for (i = 0; i < count; i++)
3847 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3848 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3851 for (i = start; i < count + start; ++i) {
3852 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3853 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3854 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3855 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3856 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3858 ptr->idx[ptr->count++] = i;
3859 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3863 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3868 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3869 IWineD3DDevice *iface,
3874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3875 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3877 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3878 iface, dstData, start, count);
3880 if (dstData == NULL || cnt < 0)
3881 return WINED3DERR_INVALIDCALL;
3883 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3887 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3889 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3890 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3892 DWORD DestFVF = dest->fvf;
3894 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3898 if (lpStrideData->u.s.normal.lpData) {
3899 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3902 if (lpStrideData->u.s.position.lpData == NULL) {
3903 ERR("Source has no position mask\n");
3904 return WINED3DERR_INVALIDCALL;
3907 /* We might access VBOs from this code, so hold the lock */
3910 if (dest->resource.allocatedMemory == NULL) {
3911 /* This may happen if we do direct locking into a vbo. Unlikely,
3912 * but theoretically possible(ddraw processvertices test)
3914 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3915 if(!dest->resource.allocatedMemory) {
3917 ERR("Out of memory\n");
3918 return E_OUTOFMEMORY;
3922 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3923 checkGLcall("glBindBufferARB");
3924 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3926 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3928 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3929 checkGLcall("glUnmapBufferARB");
3933 /* Get a pointer into the destination vbo(create one if none exists) and
3934 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3936 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3941 unsigned char extrabytes = 0;
3942 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3943 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3944 * this may write 4 extra bytes beyond the area that should be written
3946 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3947 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3948 if(!dest_conv_addr) {
3949 ERR("Out of memory\n");
3950 /* Continue without storing converted vertices */
3952 dest_conv = dest_conv_addr;
3956 * a) WINED3DRS_CLIPPING is enabled
3957 * b) WINED3DVOP_CLIP is passed
3959 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3960 static BOOL warned = FALSE;
3962 * The clipping code is not quite correct. Some things need
3963 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3964 * so disable clipping for now.
3965 * (The graphics in Half-Life are broken, and my processvertices
3966 * test crashes with IDirect3DDevice3)
3972 FIXME("Clipping is broken and disabled for now\n");
3974 } else doClip = FALSE;
3975 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3977 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3980 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3981 WINED3DTS_PROJECTION,
3983 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3984 WINED3DTS_WORLDMATRIX(0),
3987 TRACE("View mat:\n");
3988 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);
3989 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);
3990 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);
3991 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);
3993 TRACE("Proj mat:\n");
3994 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);
3995 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);
3996 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);
3997 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);
3999 TRACE("World mat:\n");
4000 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);
4001 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);
4002 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);
4003 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);
4005 /* Get the viewport */
4006 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4007 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4008 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4010 multiply_matrix(&mat,&view_mat,&world_mat);
4011 multiply_matrix(&mat,&proj_mat,&mat);
4013 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4015 for (i = 0; i < dwCount; i+= 1) {
4016 unsigned int tex_index;
4018 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4019 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4020 /* The position first */
4022 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4024 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4026 /* Multiplication with world, view and projection matrix */
4027 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);
4028 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);
4029 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);
4030 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);
4032 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4034 /* WARNING: The following things are taken from d3d7 and were not yet checked
4035 * against d3d8 or d3d9!
4038 /* Clipping conditions: From
4039 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
4041 * A vertex is clipped if it does not match the following requirements
4045 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4047 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4048 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4053 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4054 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4057 /* "Normal" viewport transformation (not clipped)
4058 * 1) The values are divided by rhw
4059 * 2) The y axis is negative, so multiply it with -1
4060 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4061 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4062 * 4) Multiply x with Width/2 and add Width/2
4063 * 5) The same for the height
4064 * 6) Add the viewpoint X and Y to the 2D coordinates and
4065 * The minimum Z value to z
4066 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4068 * Well, basically it's simply a linear transformation into viewport
4080 z *= vp.MaxZ - vp.MinZ;
4082 x += vp.Width / 2 + vp.X;
4083 y += vp.Height / 2 + vp.Y;
4088 /* That vertex got clipped
4089 * Contrary to OpenGL it is not dropped completely, it just
4090 * undergoes a different calculation.
4092 TRACE("Vertex got clipped\n");
4099 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4100 * outside of the main vertex buffer memory. That needs some more
4105 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4108 ( (float *) dest_ptr)[0] = x;
4109 ( (float *) dest_ptr)[1] = y;
4110 ( (float *) dest_ptr)[2] = z;
4111 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4113 dest_ptr += 3 * sizeof(float);
4115 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4116 dest_ptr += sizeof(float);
4121 ( (float *) dest_conv)[0] = x * w;
4122 ( (float *) dest_conv)[1] = y * w;
4123 ( (float *) dest_conv)[2] = z * w;
4124 ( (float *) dest_conv)[3] = w;
4126 dest_conv += 3 * sizeof(float);
4128 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4129 dest_conv += sizeof(float);
4133 if (DestFVF & WINED3DFVF_PSIZE) {
4134 dest_ptr += sizeof(DWORD);
4135 if(dest_conv) dest_conv += sizeof(DWORD);
4137 if (DestFVF & WINED3DFVF_NORMAL) {
4139 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4140 /* AFAIK this should go into the lighting information */
4141 FIXME("Didn't expect the destination to have a normal\n");
4142 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4144 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4148 if (DestFVF & WINED3DFVF_DIFFUSE) {
4150 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4152 static BOOL warned = FALSE;
4155 ERR("No diffuse color in source, but destination has one\n");
4159 *( (DWORD *) dest_ptr) = 0xffffffff;
4160 dest_ptr += sizeof(DWORD);
4163 *( (DWORD *) dest_conv) = 0xffffffff;
4164 dest_conv += sizeof(DWORD);
4168 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4170 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4171 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4172 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4173 dest_conv += sizeof(DWORD);
4178 if (DestFVF & WINED3DFVF_SPECULAR) {
4179 /* What's the color value in the feedback buffer? */
4181 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4183 static BOOL warned = FALSE;
4186 ERR("No specular color in source, but destination has one\n");
4190 *( (DWORD *) dest_ptr) = 0xFF000000;
4191 dest_ptr += sizeof(DWORD);
4194 *( (DWORD *) dest_conv) = 0xFF000000;
4195 dest_conv += sizeof(DWORD);
4199 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4201 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4202 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4203 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4204 dest_conv += sizeof(DWORD);
4209 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4211 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4212 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4214 ERR("No source texture, but destination requests one\n");
4215 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4216 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4219 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4221 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4228 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4229 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4230 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4231 dwCount * get_flexible_vertex_size(DestFVF),
4233 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4234 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4241 #undef copy_and_next
4243 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4245 WineDirect3DVertexStridedData strided;
4246 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4247 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4250 ERR("Output vertex declaration not implemented yet\n");
4253 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
4254 * and this call is quite performance critical, so don't call needlessly
4256 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4257 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4260 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4261 * control the streamIsUP flag, thus restore it afterwards.
4263 This->stateBlock->streamIsUP = FALSE;
4264 memset(&strided, 0, sizeof(strided));
4265 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4266 This->stateBlock->streamIsUP = streamWasUP;
4268 if(vbo || SrcStartIndex) {
4270 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4271 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4273 * Also get the start index in, but only loop over all elements if there's something to add at all.
4275 #define FIXSRC(type) \
4276 if(strided.u.s.type.VBO) { \
4277 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4278 strided.u.s.type.VBO = 0; \
4279 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4281 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4285 if(strided.u.s.type.lpData) { \
4286 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4289 FIXSRC(blendWeights);
4290 FIXSRC(blendMatrixIndices);
4295 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4296 FIXSRC(texCoords[i]);
4309 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4313 * Get / Set Texture Stage States
4314 * TODO: Verify against dx9 definitions
4316 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4318 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4320 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4322 if (Stage >= MAX_TEXTURES) {
4323 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4327 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4328 This->updateStateBlock->textureState[Stage][Type] = Value;
4330 if (This->isRecordingState) {
4331 TRACE("Recording... not performing anything\n");
4335 /* Checked after the assignments to allow proper stateblock recording */
4336 if(oldValue == Value) {
4337 TRACE("App is setting the old value over, nothing to do\n");
4341 if(Stage > This->stateBlock->lowest_disabled_stage &&
4342 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4343 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4344 * Changes in other states are important on disabled stages too
4349 if(Type == WINED3DTSS_COLOROP) {
4352 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4353 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4354 * they have to be disabled
4356 * The current stage is dirtified below.
4358 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4359 TRACE("Additionally dirtifying stage %d\n", i);
4360 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4362 This->stateBlock->lowest_disabled_stage = Stage;
4363 TRACE("New lowest disabled: %d\n", Stage);
4364 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4365 /* Previously disabled stage enabled. Stages above it may need enabling
4366 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4367 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4369 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4372 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4373 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4376 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4377 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4379 This->stateBlock->lowest_disabled_stage = i;
4380 TRACE("New lowest disabled: %d\n", i);
4382 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4383 /* TODO: Built a stage -> texture unit mapping for register combiners */
4387 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4392 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4394 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4395 *pValue = This->updateStateBlock->textureState[Stage][Type];
4402 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4404 IWineD3DBaseTexture *oldTexture;
4406 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4408 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4409 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4412 oldTexture = This->updateStateBlock->textures[Stage];
4414 if(pTexture != NULL) {
4415 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4417 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4418 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4419 return WINED3DERR_INVALIDCALL;
4421 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4424 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4425 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4427 This->updateStateBlock->changed.textures[Stage] = TRUE;
4428 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4429 This->updateStateBlock->textures[Stage] = pTexture;
4431 /* Handle recording of state blocks */
4432 if (This->isRecordingState) {
4433 TRACE("Recording... not performing anything\n");
4437 if(oldTexture == pTexture) {
4438 TRACE("App is setting the same texture again, nothing to do\n");
4442 /** NOTE: MSDN says that setTexture increases the reference count,
4443 * and that the application must set the texture back to null (or have a leaky application),
4444 * This means we should pass the refcount up to the parent
4445 *******************************/
4446 if (NULL != This->updateStateBlock->textures[Stage]) {
4447 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4448 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4450 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4451 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4452 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4453 * so the COLOROP and ALPHAOP have to be dirtified.
4455 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4456 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4458 if(bindCount == 1) {
4459 new->baseTexture.sampler = Stage;
4461 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4465 if (NULL != oldTexture) {
4466 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4467 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4469 IWineD3DBaseTexture_Release(oldTexture);
4470 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4471 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4472 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4475 if(bindCount && old->baseTexture.sampler == Stage) {
4477 /* Have to do a search for the other sampler(s) where the texture is bound to
4478 * Shouldn't happen as long as apps bind a texture only to one stage
4480 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4481 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4482 if(This->updateStateBlock->textures[i] == oldTexture) {
4483 old->baseTexture.sampler = i;
4490 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4495 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4498 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4500 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4501 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4504 *ppTexture=This->stateBlock->textures[Stage];
4506 IWineD3DBaseTexture_AddRef(*ppTexture);
4508 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4516 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4517 IWineD3DSurface **ppBackBuffer) {
4518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4519 IWineD3DSwapChain *swapChain;
4522 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4524 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4525 if (hr == WINED3D_OK) {
4526 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4527 IWineD3DSwapChain_Release(swapChain);
4529 *ppBackBuffer = NULL;
4534 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4536 WARN("(%p) : stub, calling idirect3d for now\n", This);
4537 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4540 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4542 IWineD3DSwapChain *swapChain;
4545 if(iSwapChain > 0) {
4546 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4547 if (hr == WINED3D_OK) {
4548 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4549 IWineD3DSwapChain_Release(swapChain);
4551 FIXME("(%p) Error getting display mode\n", This);
4554 /* Don't read the real display mode,
4555 but return the stored mode instead. X11 can't change the color
4556 depth, and some apps are pretty angry if they SetDisplayMode from
4557 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4559 Also don't relay to the swapchain because with ddraw it's possible
4560 that there isn't a swapchain at all */
4561 pMode->Width = This->ddraw_width;
4562 pMode->Height = This->ddraw_height;
4563 pMode->Format = This->ddraw_format;
4564 pMode->RefreshRate = 0;
4571 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4573 TRACE("(%p)->(%p)\n", This, hWnd);
4575 if(This->ddraw_fullscreen) {
4576 if(This->ddraw_window && This->ddraw_window != hWnd) {
4577 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4579 if(hWnd && This->ddraw_window != hWnd) {
4580 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4584 This->ddraw_window = hWnd;
4588 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4590 TRACE("(%p)->(%p)\n", This, hWnd);
4592 *hWnd = This->ddraw_window;
4597 * Stateblock related functions
4600 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4602 IWineD3DStateBlockImpl *object;
4603 HRESULT temp_result;
4606 TRACE("(%p)\n", This);
4608 if (This->isRecordingState) {
4609 return WINED3DERR_INVALIDCALL;
4612 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4613 if (NULL == object ) {
4614 FIXME("(%p)Error allocating memory for stateblock\n", This);
4615 return E_OUTOFMEMORY;
4617 TRACE("(%p) created object %p\n", This, object);
4618 object->wineD3DDevice= This;
4619 /** FIXME: object->parent = parent; **/
4620 object->parent = NULL;
4621 object->blockType = WINED3DSBT_RECORDED;
4623 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4625 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4626 list_init(&object->lightMap[i]);
4629 temp_result = allocate_shader_constants(object);
4630 if (WINED3D_OK != temp_result)
4633 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4634 This->updateStateBlock = object;
4635 This->isRecordingState = TRUE;
4637 TRACE("(%p) recording stateblock %p\n",This , object);
4641 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4644 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4646 if (!This->isRecordingState) {
4647 FIXME("(%p) not recording! returning error\n", This);
4648 *ppStateBlock = NULL;
4649 return WINED3DERR_INVALIDCALL;
4652 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4653 if(object->changed.renderState[i]) {
4654 object->contained_render_states[object->num_contained_render_states] = i;
4655 object->num_contained_render_states++;
4658 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4659 if(object->changed.transform[i]) {
4660 object->contained_transform_states[object->num_contained_transform_states] = i;
4661 object->num_contained_transform_states++;
4664 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4665 if(object->changed.vertexShaderConstantsF[i]) {
4666 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4667 object->num_contained_vs_consts_f++;
4670 for(i = 0; i < MAX_CONST_I; i++) {
4671 if(object->changed.vertexShaderConstantsI[i]) {
4672 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4673 object->num_contained_vs_consts_i++;
4676 for(i = 0; i < MAX_CONST_B; i++) {
4677 if(object->changed.vertexShaderConstantsB[i]) {
4678 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4679 object->num_contained_vs_consts_b++;
4682 for(i = 0; i < MAX_CONST_I; i++) {
4683 if(object->changed.pixelShaderConstantsI[i]) {
4684 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4685 object->num_contained_ps_consts_i++;
4688 for(i = 0; i < MAX_CONST_B; i++) {
4689 if(object->changed.pixelShaderConstantsB[i]) {
4690 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4691 object->num_contained_ps_consts_b++;
4694 for(i = 0; i < MAX_TEXTURES; i++) {
4695 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4696 if(object->changed.textureState[i][j]) {
4697 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4698 object->contained_tss_states[object->num_contained_tss_states].state = j;
4699 object->num_contained_tss_states++;
4703 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4704 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4705 if(object->changed.samplerState[i][j]) {
4706 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4707 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4708 object->num_contained_sampler_states++;
4713 *ppStateBlock = (IWineD3DStateBlock*) object;
4714 This->isRecordingState = FALSE;
4715 This->updateStateBlock = This->stateBlock;
4716 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4717 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4718 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4723 * Scene related functions
4725 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4726 /* At the moment we have no need for any functionality at the beginning
4728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4729 TRACE("(%p)\n", This);
4732 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4733 return WINED3DERR_INVALIDCALL;
4735 This->inScene = TRUE;
4739 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4741 TRACE("(%p)\n", This);
4743 if(!This->inScene) {
4744 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4745 return WINED3DERR_INVALIDCALL;
4748 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4749 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4751 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4754 checkGLcall("glFlush");
4757 This->inScene = FALSE;
4761 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4762 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4763 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4765 IWineD3DSwapChain *swapChain = NULL;
4767 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4769 TRACE("(%p) Presenting the frame\n", This);
4771 for(i = 0 ; i < swapchains ; i ++) {
4773 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4774 TRACE("presentinng chain %d, %p\n", i, swapChain);
4775 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4776 IWineD3DSwapChain_Release(swapChain);
4782 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4783 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4785 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4787 GLbitfield glMask = 0;
4789 WINED3DRECT curRect;
4791 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4792 UINT drawable_width, drawable_height;
4794 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4795 Count, pRects, Flags, Color, Z, Stencil);
4797 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4798 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4799 /* TODO: What about depth stencil buffers without stencil bits? */
4800 return WINED3DERR_INVALIDCALL;
4803 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4804 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4805 * for the cleared parts, and the untouched parts.
4807 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4808 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4809 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4810 * checking all this if the dest surface is in the drawable anyway.
4812 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4814 if(vp->X != 0 || vp->Y != 0 ||
4815 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4816 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4819 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4820 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4821 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4822 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4823 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4826 if(Count > 0 && pRects && (
4827 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4828 pRects[0].x2 < target->currentDesc.Width ||
4829 pRects[0].y2 < target->currentDesc.Height)) {
4830 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4837 target->get_drawable_size(target, &drawable_width, &drawable_height);
4839 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4840 * and not the last active one.
4842 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4845 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4846 apply_fbo_state(iface);
4849 /* Only set the values up once, as they are not changing */
4850 if (Flags & WINED3DCLEAR_STENCIL) {
4851 glClearStencil(Stencil);
4852 checkGLcall("glClearStencil");
4853 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4854 glStencilMask(0xFFFFFFFF);
4857 if (Flags & WINED3DCLEAR_ZBUFFER) {
4858 glDepthMask(GL_TRUE);
4860 checkGLcall("glClearDepth");
4861 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4862 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4865 if (Flags & WINED3DCLEAR_TARGET) {
4866 TRACE("Clearing screen with glClear to color %x\n", Color);
4867 glClearColor(D3DCOLOR_R(Color),
4871 checkGLcall("glClearColor");
4873 /* Clear ALL colors! */
4874 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4875 glMask = glMask | GL_COLOR_BUFFER_BIT;
4878 vp_rect.left = vp->X;
4879 vp_rect.top = vp->Y;
4880 vp_rect.right = vp->X + vp->Width;
4881 vp_rect.bottom = vp->Y + vp->Height;
4882 if (!(Count > 0 && pRects)) {
4883 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4884 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4886 if(This->render_offscreen) {
4887 glScissor(vp_rect.left, vp_rect.top,
4888 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4890 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4891 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4893 checkGLcall("glScissor");
4895 checkGLcall("glClear");
4897 /* Now process each rect in turn */
4898 for (i = 0; i < Count; i++) {
4899 /* Note gl uses lower left, width/height */
4900 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
4901 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4902 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4904 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4905 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4906 curRect.x1, (target->currentDesc.Height - curRect.y2),
4907 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4909 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4910 * The rectangle is not cleared, no error is returned, but further rectanlges are
4911 * still cleared if they are valid
4913 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4914 TRACE("Rectangle with negative dimensions, ignoring\n");
4918 if(This->render_offscreen) {
4919 glScissor(curRect.x1, curRect.y1,
4920 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4922 glScissor(curRect.x1, drawable_height - curRect.y2,
4923 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4925 checkGLcall("glScissor");
4928 checkGLcall("glClear");
4932 /* Restore the old values (why..?) */
4933 if (Flags & WINED3DCLEAR_STENCIL) {
4934 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4936 if (Flags & WINED3DCLEAR_TARGET) {
4937 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4938 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4939 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4940 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4941 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4943 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4944 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4946 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
4947 /* TODO: Move the fbo logic into ModifyLocation() */
4948 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4949 target->Flags |= SFLAG_INTEXTURE;
4960 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4961 UINT PrimitiveCount) {
4963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4965 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4966 debug_d3dprimitivetype(PrimitiveType),
4967 StartVertex, PrimitiveCount);
4969 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4970 if(This->stateBlock->streamIsUP) {
4971 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4972 This->stateBlock->streamIsUP = FALSE;
4975 if(This->stateBlock->loadBaseVertexIndex != 0) {
4976 This->stateBlock->loadBaseVertexIndex = 0;
4977 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4979 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4980 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4981 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4985 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4986 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4987 WINED3DPRIMITIVETYPE PrimitiveType,
4988 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4992 IWineD3DIndexBuffer *pIB;
4993 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4996 pIB = This->stateBlock->pIndexData;
4998 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4999 * without an index buffer set. (The first time at least...)
5000 * D3D8 simply dies, but I doubt it can do much harm to return
5001 * D3DERR_INVALIDCALL there as well. */
5002 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5003 return WINED3DERR_INVALIDCALL;
5006 if(This->stateBlock->streamIsUP) {
5007 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5008 This->stateBlock->streamIsUP = FALSE;
5010 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5012 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5013 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5014 minIndex, NumVertices, startIndex, primCount);
5016 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5017 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5023 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5024 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5025 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5028 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5029 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5034 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5035 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5036 UINT VertexStreamZeroStride) {
5037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5038 IWineD3DVertexBuffer *vb;
5040 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5041 debug_d3dprimitivetype(PrimitiveType),
5042 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5044 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5045 vb = This->stateBlock->streamSource[0];
5046 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5047 if(vb) IWineD3DVertexBuffer_Release(vb);
5048 This->stateBlock->streamOffset[0] = 0;
5049 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5050 This->stateBlock->streamIsUP = TRUE;
5051 This->stateBlock->loadBaseVertexIndex = 0;
5053 /* TODO: Only mark dirty if drawing from a different UP address */
5054 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5056 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5057 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5059 /* MSDN specifies stream zero settings must be set to NULL */
5060 This->stateBlock->streamStride[0] = 0;
5061 This->stateBlock->streamSource[0] = NULL;
5063 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5064 * the new stream sources or use UP drawing again
5069 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5070 UINT MinVertexIndex, UINT NumVertices,
5071 UINT PrimitiveCount, CONST void* pIndexData,
5072 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5073 UINT VertexStreamZeroStride) {
5075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5076 IWineD3DVertexBuffer *vb;
5077 IWineD3DIndexBuffer *ib;
5079 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5080 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5081 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5082 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5084 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5090 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5091 vb = This->stateBlock->streamSource[0];
5092 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5093 if(vb) IWineD3DVertexBuffer_Release(vb);
5094 This->stateBlock->streamIsUP = TRUE;
5095 This->stateBlock->streamOffset[0] = 0;
5096 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5098 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5099 This->stateBlock->baseVertexIndex = 0;
5100 This->stateBlock->loadBaseVertexIndex = 0;
5101 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5102 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5103 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5105 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5107 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5108 This->stateBlock->streamSource[0] = NULL;
5109 This->stateBlock->streamStride[0] = 0;
5110 ib = This->stateBlock->pIndexData;
5112 IWineD3DIndexBuffer_Release(ib);
5113 This->stateBlock->pIndexData = NULL;
5115 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5116 * SetStreamSource to specify a vertex buffer
5122 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5125 /* Mark the state dirty until we have nicer tracking
5126 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5129 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5130 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5131 This->stateBlock->baseVertexIndex = 0;
5132 This->up_strided = DrawPrimStrideData;
5133 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5134 This->up_strided = NULL;
5138 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5140 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5142 /* Mark the state dirty until we have nicer tracking
5143 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5146 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5147 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5148 This->stateBlock->streamIsUP = TRUE;
5149 This->stateBlock->baseVertexIndex = 0;
5150 This->up_strided = DrawPrimStrideData;
5151 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5152 This->up_strided = NULL;
5156 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5157 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5158 * not callable by the app directly no parameter validation checks are needed here.
5160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5161 WINED3DLOCKED_BOX src;
5162 WINED3DLOCKED_BOX dst;
5164 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5166 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5167 * dirtification to improve loading performance.
5169 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5170 if(FAILED(hr)) return hr;
5171 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5173 IWineD3DVolume_UnlockBox(pSourceVolume);
5177 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5179 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5181 IWineD3DVolume_UnlockBox(pSourceVolume);
5183 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5188 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5189 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5191 HRESULT hr = WINED3D_OK;
5192 WINED3DRESOURCETYPE sourceType;
5193 WINED3DRESOURCETYPE destinationType;
5196 /* TODO: think about moving the code into IWineD3DBaseTexture */
5198 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5200 /* verify that the source and destination textures aren't NULL */
5201 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5202 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5203 This, pSourceTexture, pDestinationTexture);
5204 hr = WINED3DERR_INVALIDCALL;
5207 if (pSourceTexture == pDestinationTexture) {
5208 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5209 This, pSourceTexture, pDestinationTexture);
5210 hr = WINED3DERR_INVALIDCALL;
5212 /* Verify that the source and destination textures are the same type */
5213 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5214 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5216 if (sourceType != destinationType) {
5217 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5219 hr = WINED3DERR_INVALIDCALL;
5222 /* check that both textures have the identical numbers of levels */
5223 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5224 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5225 hr = WINED3DERR_INVALIDCALL;
5228 if (WINED3D_OK == hr) {
5230 /* Make sure that the destination texture is loaded */
5231 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5233 /* Update every surface level of the texture */
5234 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5236 switch (sourceType) {
5237 case WINED3DRTYPE_TEXTURE:
5239 IWineD3DSurface *srcSurface;
5240 IWineD3DSurface *destSurface;
5242 for (i = 0 ; i < levels ; ++i) {
5243 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5244 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5245 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5246 IWineD3DSurface_Release(srcSurface);
5247 IWineD3DSurface_Release(destSurface);
5248 if (WINED3D_OK != hr) {
5249 WARN("(%p) : Call to update surface failed\n", This);
5255 case WINED3DRTYPE_CUBETEXTURE:
5257 IWineD3DSurface *srcSurface;
5258 IWineD3DSurface *destSurface;
5259 WINED3DCUBEMAP_FACES faceType;
5261 for (i = 0 ; i < levels ; ++i) {
5262 /* Update each cube face */
5263 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5264 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5265 if (WINED3D_OK != hr) {
5266 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5268 TRACE("Got srcSurface %p\n", srcSurface);
5270 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5271 if (WINED3D_OK != hr) {
5272 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5274 TRACE("Got desrSurface %p\n", destSurface);
5276 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5277 IWineD3DSurface_Release(srcSurface);
5278 IWineD3DSurface_Release(destSurface);
5279 if (WINED3D_OK != hr) {
5280 WARN("(%p) : Call to update surface failed\n", This);
5288 case WINED3DRTYPE_VOLUMETEXTURE:
5290 IWineD3DVolume *srcVolume = NULL;
5291 IWineD3DVolume *destVolume = NULL;
5293 for (i = 0 ; i < levels ; ++i) {
5294 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5295 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5296 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5297 IWineD3DVolume_Release(srcVolume);
5298 IWineD3DVolume_Release(destVolume);
5299 if (WINED3D_OK != hr) {
5300 WARN("(%p) : Call to update volume failed\n", This);
5308 FIXME("(%p) : Unsupported source and destination type\n", This);
5309 hr = WINED3DERR_INVALIDCALL;
5316 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5317 IWineD3DSwapChain *swapChain;
5319 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5320 if(hr == WINED3D_OK) {
5321 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5322 IWineD3DSwapChain_Release(swapChain);
5327 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5329 /* return a sensible default */
5331 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5332 FIXME("(%p) : stub\n", This);
5336 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5339 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5340 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5341 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5342 return WINED3DERR_INVALIDCALL;
5344 for (j = 0; j < 256; ++j) {
5345 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5346 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5347 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5348 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5350 TRACE("(%p) : returning\n", This);
5354 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5357 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5358 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5359 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5360 return WINED3DERR_INVALIDCALL;
5362 for (j = 0; j < 256; ++j) {
5363 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5364 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5365 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5366 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5368 TRACE("(%p) : returning\n", This);
5372 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5374 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5375 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5376 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5377 return WINED3DERR_INVALIDCALL;
5379 /*TODO: stateblocks */
5380 This->currentPalette = PaletteNumber;
5381 TRACE("(%p) : returning\n", This);
5385 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5387 if (PaletteNumber == NULL) {
5388 WARN("(%p) : returning Invalid Call\n", This);
5389 return WINED3DERR_INVALIDCALL;
5391 /*TODO: stateblocks */
5392 *PaletteNumber = This->currentPalette;
5393 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5397 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5399 static BOOL showFixmes = TRUE;
5401 FIXME("(%p) : stub\n", This);
5405 This->softwareVertexProcessing = bSoftware;
5410 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5411 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5412 static BOOL showFixmes = TRUE;
5414 FIXME("(%p) : stub\n", This);
5417 return This->softwareVertexProcessing;
5421 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5423 IWineD3DSwapChain *swapChain;
5426 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5428 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5429 if(hr == WINED3D_OK){
5430 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5431 IWineD3DSwapChain_Release(swapChain);
5433 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5439 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5441 static BOOL showfixmes = TRUE;
5442 if(nSegments != 0.0f) {
5444 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5451 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5453 static BOOL showfixmes = TRUE;
5455 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5461 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5463 /** TODO: remove casts to IWineD3DSurfaceImpl
5464 * NOTE: move code to surface to accomplish this
5465 ****************************************/
5466 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5467 int srcWidth, srcHeight;
5468 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5469 WINED3DFORMAT destFormat, srcFormat;
5471 int srcLeft, destLeft, destTop;
5472 WINED3DPOOL srcPool, destPool;
5474 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5475 glDescriptor *glDescription = NULL;
5478 CONVERT_TYPES convert = NO_CONVERSION;
5480 WINED3DSURFACE_DESC winedesc;
5482 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5483 memset(&winedesc, 0, sizeof(winedesc));
5484 winedesc.Width = &srcSurfaceWidth;
5485 winedesc.Height = &srcSurfaceHeight;
5486 winedesc.Pool = &srcPool;
5487 winedesc.Format = &srcFormat;
5489 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5491 winedesc.Width = &destSurfaceWidth;
5492 winedesc.Height = &destSurfaceHeight;
5493 winedesc.Pool = &destPool;
5494 winedesc.Format = &destFormat;
5495 winedesc.Size = &destSize;
5497 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5499 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5500 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5501 return WINED3DERR_INVALIDCALL;
5504 /* This call loads the opengl surface directly, instead of copying the surface to the
5505 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5506 * copy in sysmem and use regular surface loading.
5508 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5509 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5510 if(convert != NO_CONVERSION) {
5511 return IWineD3DSurface_BltFast(pDestinationSurface,
5512 pDestPoint ? pDestPoint->x : 0,
5513 pDestPoint ? pDestPoint->y : 0,
5514 pSourceSurface, (RECT *) pSourceRect, 0);
5517 if (destFormat == WINED3DFMT_UNKNOWN) {
5518 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5519 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5521 /* Get the update surface description */
5522 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5525 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5529 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5530 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5531 checkGLcall("glActiveTextureARB");
5534 /* Make sure the surface is loaded and up to date */
5535 IWineD3DSurface_PreLoad(pDestinationSurface);
5537 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5539 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5540 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5541 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5542 srcLeft = pSourceRect ? pSourceRect->left : 0;
5543 destLeft = pDestPoint ? pDestPoint->x : 0;
5544 destTop = pDestPoint ? pDestPoint->y : 0;
5547 /* This function doesn't support compressed textures
5548 the pitch is just bytesPerPixel * width */
5549 if(srcWidth != srcSurfaceWidth || srcLeft ){
5550 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5551 offset += srcLeft * pSrcSurface->bytesPerPixel;
5552 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5554 /* TODO DXT formats */
5556 if(pSourceRect != NULL && pSourceRect->top != 0){
5557 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5559 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5561 ,glDescription->level
5566 ,glDescription->glFormat
5567 ,glDescription->glType
5568 ,IWineD3DSurface_GetData(pSourceSurface)
5572 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5574 /* need to lock the surface to get the data */
5575 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5578 /* TODO: Cube and volume support */
5580 /* not a whole row so we have to do it a line at a time */
5583 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5584 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5586 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5588 glTexSubImage2D(glDescription->target
5589 ,glDescription->level
5594 ,glDescription->glFormat
5595 ,glDescription->glType
5596 ,data /* could be quicker using */
5601 } else { /* Full width, so just write out the whole texture */
5603 if (WINED3DFMT_DXT1 == destFormat ||
5604 WINED3DFMT_DXT2 == destFormat ||
5605 WINED3DFMT_DXT3 == destFormat ||
5606 WINED3DFMT_DXT4 == destFormat ||
5607 WINED3DFMT_DXT5 == destFormat) {
5608 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5609 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5610 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5611 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5612 } if (destFormat != srcFormat) {
5613 FIXME("Updating mixed format compressed texture is not curretly support\n");
5615 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5616 glDescription->level,
5617 glDescription->glFormatInternal,
5622 IWineD3DSurface_GetData(pSourceSurface));
5625 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5630 glTexSubImage2D(glDescription->target
5631 ,glDescription->level
5636 ,glDescription->glFormat
5637 ,glDescription->glType
5638 ,IWineD3DSurface_GetData(pSourceSurface)
5642 checkGLcall("glTexSubImage2D");
5646 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5647 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5652 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5654 struct WineD3DRectPatch *patch;
5658 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5660 if(!(Handle || pRectPatchInfo)) {
5661 /* TODO: Write a test for the return value, thus the FIXME */
5662 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5663 return WINED3DERR_INVALIDCALL;
5667 i = PATCHMAP_HASHFUNC(Handle);
5669 LIST_FOR_EACH(e, &This->patches[i]) {
5670 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5671 if(patch->Handle == Handle) {
5678 TRACE("Patch does not exist. Creating a new one\n");
5679 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5680 patch->Handle = Handle;
5681 list_add_head(&This->patches[i], &patch->entry);
5683 TRACE("Found existing patch %p\n", patch);
5686 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5687 * attributes we have to tesselate, read back, and draw. This needs a patch
5688 * management structure instance. Create one.
5690 * A possible improvement is to check if a vertex shader is used, and if not directly
5693 FIXME("Drawing an uncached patch. This is slow\n");
5694 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5697 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5698 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5699 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5701 TRACE("Tesselation density or patch info changed, retesselating\n");
5703 if(pRectPatchInfo) {
5704 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5706 patch->numSegs[0] = pNumSegs[0];
5707 patch->numSegs[1] = pNumSegs[1];
5708 patch->numSegs[2] = pNumSegs[2];
5709 patch->numSegs[3] = pNumSegs[3];
5711 hr = tesselate_rectpatch(This, patch);
5713 WARN("Patch tesselation failed\n");
5715 /* Do not release the handle to store the params of the patch */
5717 HeapFree(GetProcessHeap(), 0, patch);
5723 This->currentPatch = patch;
5724 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5725 This->currentPatch = NULL;
5727 /* Destroy uncached patches */
5729 HeapFree(GetProcessHeap(), 0, patch->mem);
5730 HeapFree(GetProcessHeap(), 0, patch);
5735 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5736 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5737 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5738 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5739 FIXME("(%p) : Stub\n", This);
5743 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5746 struct WineD3DRectPatch *patch;
5748 TRACE("(%p) Handle(%d)\n", This, Handle);
5750 i = PATCHMAP_HASHFUNC(Handle);
5751 LIST_FOR_EACH(e, &This->patches[i]) {
5752 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5753 if(patch->Handle == Handle) {
5754 TRACE("Deleting patch %p\n", patch);
5755 list_remove(&patch->entry);
5756 HeapFree(GetProcessHeap(), 0, patch->mem);
5757 HeapFree(GetProcessHeap(), 0, patch);
5762 /* TODO: Write a test for the return value */
5763 FIXME("Attempt to destroy nonexistant patch\n");
5764 return WINED3DERR_INVALIDCALL;
5767 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5769 IWineD3DSwapChain *swapchain;
5771 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5772 if (SUCCEEDED(hr)) {
5773 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5780 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5784 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5785 checkGLcall("glGenFramebuffersEXT()");
5787 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5788 checkGLcall("glBindFramebuffer()");
5791 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5792 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5793 IWineD3DBaseTextureImpl *texture_impl;
5794 GLenum texttarget, target;
5797 texttarget = surface_impl->glDescription.target;
5798 if(texttarget == GL_TEXTURE_2D) {
5799 target = GL_TEXTURE_2D;
5800 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5801 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
5802 target = GL_TEXTURE_RECTANGLE_ARB;
5803 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5805 target = GL_TEXTURE_CUBE_MAP_ARB;
5806 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5809 IWineD3DSurface_PreLoad(surface);
5811 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5812 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5813 glBindTexture(target, old_binding);
5815 /* Update base texture states array */
5816 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5817 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5818 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5819 if (texture_impl->baseTexture.bindCount) {
5820 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5823 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5826 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5827 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5829 checkGLcall("attach_surface_fbo");
5832 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5834 IWineD3DSwapChain *swapchain;
5836 swapchain = get_swapchain(surface);
5840 TRACE("Surface %p is onscreen\n", surface);
5842 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5843 buffer = surface_get_gl_buffer(surface, swapchain);
5844 glDrawBuffer(buffer);
5845 checkGLcall("glDrawBuffer()");
5847 TRACE("Surface %p is offscreen\n", surface);
5848 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5849 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5853 glEnable(GL_SCISSOR_TEST);
5855 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5857 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5858 rect->x2 - rect->x1, rect->y2 - rect->y1);
5860 checkGLcall("glScissor");
5862 glDisable(GL_SCISSOR_TEST);
5864 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5866 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5867 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5869 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5870 glClear(GL_COLOR_BUFFER_BIT);
5871 checkGLcall("glClear");
5873 if (This->render_offscreen) {
5874 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5876 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5877 checkGLcall("glBindFramebuffer()");
5880 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5881 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5882 glDrawBuffer(GL_BACK);
5883 checkGLcall("glDrawBuffer()");
5887 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5888 unsigned int r, g, b, a;
5891 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
5892 destfmt == WINED3DFMT_R8G8B8)
5895 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5897 a = (color & 0xff000000) >> 24;
5898 r = (color & 0x00ff0000) >> 16;
5899 g = (color & 0x0000ff00) >> 8;
5900 b = (color & 0x000000ff) >> 0;
5904 case WINED3DFMT_R5G6B5:
5905 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5912 TRACE("Returning %08x\n", ret);
5915 case WINED3DFMT_X1R5G5B5:
5916 case WINED3DFMT_A1R5G5B5:
5925 TRACE("Returning %08x\n", ret);
5929 TRACE("Returning %08x\n", a);
5932 case WINED3DFMT_X4R4G4B4:
5933 case WINED3DFMT_A4R4G4B4:
5942 TRACE("Returning %08x\n", ret);
5945 case WINED3DFMT_R3G3B2:
5952 TRACE("Returning %08x\n", ret);
5955 case WINED3DFMT_X8B8G8R8:
5956 case WINED3DFMT_A8B8G8R8:
5961 TRACE("Returning %08x\n", ret);
5964 case WINED3DFMT_A2R10G10B10:
5966 r = (r * 1024) / 256;
5967 g = (g * 1024) / 256;
5968 b = (b * 1024) / 256;
5973 TRACE("Returning %08x\n", ret);
5976 case WINED3DFMT_A2B10G10R10:
5978 r = (r * 1024) / 256;
5979 g = (g * 1024) / 256;
5980 b = (b * 1024) / 256;
5985 TRACE("Returning %08x\n", ret);
5989 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5994 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5996 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5998 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6000 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6001 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6002 return WINED3DERR_INVALIDCALL;
6005 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6006 color_fill_fbo(iface, pSurface, pRect, color);
6009 /* Just forward this to the DirectDraw blitting engine */
6010 memset(&BltFx, 0, sizeof(BltFx));
6011 BltFx.dwSize = sizeof(BltFx);
6012 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6013 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6017 /* rendertarget and deptth stencil functions */
6018 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6021 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6022 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6023 return WINED3DERR_INVALIDCALL;
6026 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6027 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6028 /* Note inc ref on returned surface */
6029 if(*ppRenderTarget != NULL)
6030 IWineD3DSurface_AddRef(*ppRenderTarget);
6034 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6036 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6037 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6038 IWineD3DSwapChainImpl *Swapchain;
6041 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6043 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6044 if(hr != WINED3D_OK) {
6045 ERR("Can't get the swapchain\n");
6049 /* Make sure to release the swapchain */
6050 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6052 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6053 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6054 return WINED3DERR_INVALIDCALL;
6056 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6057 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6058 return WINED3DERR_INVALIDCALL;
6061 if(Swapchain->frontBuffer != Front) {
6062 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6064 if(Swapchain->frontBuffer)
6065 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6066 Swapchain->frontBuffer = Front;
6068 if(Swapchain->frontBuffer) {
6069 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6073 if(Back && !Swapchain->backBuffer) {
6074 /* We need memory for the back buffer array - only one back buffer this way */
6075 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6076 if(!Swapchain->backBuffer) {
6077 ERR("Out of memory\n");
6078 return E_OUTOFMEMORY;
6082 if(Swapchain->backBuffer[0] != Back) {
6083 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6085 /* What to do about the context here in the case of multithreading? Not sure.
6086 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6089 if(!Swapchain->backBuffer[0]) {
6090 /* GL was told to draw to the front buffer at creation,
6093 glDrawBuffer(GL_BACK);
6094 checkGLcall("glDrawBuffer(GL_BACK)");
6095 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6096 Swapchain->presentParms.BackBufferCount = 1;
6098 /* That makes problems - disable for now */
6099 /* glDrawBuffer(GL_FRONT); */
6100 checkGLcall("glDrawBuffer(GL_FRONT)");
6101 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6102 Swapchain->presentParms.BackBufferCount = 0;
6106 if(Swapchain->backBuffer[0])
6107 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6108 Swapchain->backBuffer[0] = Back;
6110 if(Swapchain->backBuffer[0]) {
6111 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6113 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6114 Swapchain->backBuffer = NULL;
6122 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6124 *ppZStencilSurface = This->stencilBufferTarget;
6125 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6127 if(*ppZStencilSurface != NULL) {
6128 /* Note inc ref on returned surface */
6129 IWineD3DSurface_AddRef(*ppZStencilSurface);
6132 return WINED3DERR_NOTFOUND;
6136 /* TODO: Handle stencil attachments */
6137 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6139 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6141 TRACE("Set depth stencil to %p\n", depth_stencil);
6143 if (depth_stencil_impl) {
6144 if (depth_stencil_impl->current_renderbuffer) {
6145 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6146 checkGLcall("glFramebufferRenderbufferEXT()");
6148 IWineD3DBaseTextureImpl *texture_impl;
6149 GLenum texttarget, target;
6150 GLint old_binding = 0;
6152 texttarget = depth_stencil_impl->glDescription.target;
6153 if(texttarget == GL_TEXTURE_2D) {
6154 target = GL_TEXTURE_2D;
6155 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6156 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6157 target = GL_TEXTURE_RECTANGLE_ARB;
6158 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6160 target = GL_TEXTURE_CUBE_MAP_ARB;
6161 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6164 IWineD3DSurface_PreLoad(depth_stencil);
6166 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6167 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6168 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6169 glBindTexture(target, old_binding);
6171 /* Update base texture states array */
6172 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6173 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6174 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6175 if (texture_impl->baseTexture.bindCount) {
6176 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6179 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6182 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6183 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6184 checkGLcall("glFramebufferTexture2DEXT()");
6187 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6188 checkGLcall("glFramebufferTexture2DEXT()");
6192 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6194 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6196 TRACE("Set render target %u to %p\n", idx, render_target);
6199 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6200 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6202 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6203 checkGLcall("glFramebufferTexture2DEXT()");
6205 This->draw_buffers[idx] = GL_NONE;
6209 static void check_fbo_status(IWineD3DDevice *iface) {
6210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6213 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6214 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6215 TRACE("FBO complete\n");
6217 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6219 /* Dump the FBO attachments */
6220 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
6221 IWineD3DSurfaceImpl *attachment;
6224 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6225 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6227 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6228 attachment->pow2Width, attachment->pow2Height);
6231 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6233 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6234 attachment->pow2Width, attachment->pow2Height);
6240 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6242 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6243 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6245 if (!ds_impl) return FALSE;
6247 if (ds_impl->current_renderbuffer) {
6248 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6249 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6252 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6253 rt_impl->pow2Height != ds_impl->pow2Height);
6256 void apply_fbo_state(IWineD3DDevice *iface) {
6257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6260 if (This->render_offscreen) {
6261 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6263 /* Apply render targets */
6264 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6265 IWineD3DSurface *render_target = This->render_targets[i];
6266 if (This->fbo_color_attachments[i] != render_target) {
6267 set_render_target_fbo(iface, i, render_target);
6268 This->fbo_color_attachments[i] = render_target;
6272 /* Apply depth targets */
6273 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6274 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6275 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6277 if (This->stencilBufferTarget) {
6278 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6280 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6281 This->fbo_depth_attachment = This->stencilBufferTarget;
6284 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6285 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6286 checkGLcall("glDrawBuffers()");
6288 glDrawBuffer(This->draw_buffers[0]);
6289 checkGLcall("glDrawBuffer()");
6292 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6295 check_fbo_status(iface);
6298 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6299 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6301 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6302 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6305 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6306 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6307 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6308 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6311 case WINED3DTEXF_LINEAR:
6312 gl_filter = GL_LINEAR;
6316 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6317 case WINED3DTEXF_NONE:
6318 case WINED3DTEXF_POINT:
6319 gl_filter = GL_NEAREST;
6323 /* Attach src surface to src fbo */
6324 src_swapchain = get_swapchain(src_surface);
6325 if (src_swapchain) {
6328 TRACE("Source surface %p is onscreen\n", src_surface);
6329 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6332 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6333 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6334 glReadBuffer(buffer);
6335 checkGLcall("glReadBuffer()");
6337 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6338 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6340 TRACE("Source surface %p is offscreen\n", src_surface);
6342 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6343 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6344 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6345 checkGLcall("glReadBuffer()");
6349 /* Attach dst surface to dst fbo */
6350 dst_swapchain = get_swapchain(dst_surface);
6351 if (dst_swapchain) {
6354 TRACE("Destination surface %p is onscreen\n", dst_surface);
6355 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6358 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6359 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6360 glDrawBuffer(buffer);
6361 checkGLcall("glDrawBuffer()");
6363 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6364 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6366 TRACE("Destination surface %p is offscreen\n", dst_surface);
6368 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6369 if(!src_swapchain) {
6370 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6374 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6375 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6376 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6377 checkGLcall("glDrawBuffer()");
6379 glDisable(GL_SCISSOR_TEST);
6380 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6383 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6384 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6385 checkGLcall("glBlitFramebuffer()");
6387 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6388 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6389 checkGLcall("glBlitFramebuffer()");
6392 if (This->render_offscreen) {
6393 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6395 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6396 checkGLcall("glBindFramebuffer()");
6399 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6400 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6401 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6402 glDrawBuffer(GL_BACK);
6403 checkGLcall("glDrawBuffer()");
6408 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6409 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6410 WINED3DVIEWPORT viewport;
6412 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6414 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6415 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6416 This, RenderTargetIndex, GL_LIMITS(buffers));
6417 return WINED3DERR_INVALIDCALL;
6420 /* MSDN says that null disables the render target
6421 but a device must always be associated with a render target
6422 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6424 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6427 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6428 FIXME("Trying to set render target 0 to NULL\n");
6429 return WINED3DERR_INVALIDCALL;
6431 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6432 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);
6433 return WINED3DERR_INVALIDCALL;
6436 /* If we are trying to set what we already have, don't bother */
6437 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6438 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6441 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6442 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6443 This->render_targets[RenderTargetIndex] = pRenderTarget;
6445 /* Render target 0 is special */
6446 if(RenderTargetIndex == 0) {
6447 /* Finally, reset the viewport as the MSDN states. */
6448 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6449 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6452 viewport.MaxZ = 1.0f;
6453 viewport.MinZ = 0.0f;
6454 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6455 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6456 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6458 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6460 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6462 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6463 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6465 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6470 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6472 HRESULT hr = WINED3D_OK;
6473 IWineD3DSurface *tmp;
6475 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6477 if (pNewZStencil == This->stencilBufferTarget) {
6478 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6480 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6481 * depending on the renter target implementation being used.
6482 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6483 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6484 * stencil buffer and incure an extra memory overhead
6485 ******************************************************/
6487 tmp = This->stencilBufferTarget;
6488 This->stencilBufferTarget = pNewZStencil;
6489 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6490 /* should we be calling the parent or the wined3d surface? */
6491 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6492 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6495 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6496 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6497 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6498 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6499 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6506 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6507 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6509 /* TODO: the use of Impl is deprecated. */
6510 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6511 WINED3DLOCKED_RECT lockedRect;
6513 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6515 /* some basic validation checks */
6516 if(This->cursorTexture) {
6517 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6519 glDeleteTextures(1, &This->cursorTexture);
6521 This->cursorTexture = 0;
6524 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6525 This->haveHardwareCursor = TRUE;
6527 This->haveHardwareCursor = FALSE;
6530 WINED3DLOCKED_RECT rect;
6532 /* MSDN: Cursor must be A8R8G8B8 */
6533 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6534 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6535 return WINED3DERR_INVALIDCALL;
6538 /* MSDN: Cursor must be smaller than the display mode */
6539 if(pSur->currentDesc.Width > This->ddraw_width ||
6540 pSur->currentDesc.Height > This->ddraw_height) {
6541 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);
6542 return WINED3DERR_INVALIDCALL;
6545 if (!This->haveHardwareCursor) {
6546 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6548 /* Do not store the surface's pointer because the application may
6549 * release it after setting the cursor image. Windows doesn't
6550 * addref the set surface, so we can't do this either without
6551 * creating circular refcount dependencies. Copy out the gl texture
6554 This->cursorWidth = pSur->currentDesc.Width;
6555 This->cursorHeight = pSur->currentDesc.Height;
6556 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6558 const GlPixelFormatDesc *glDesc;
6559 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6560 char *mem, *bits = (char *)rect.pBits;
6561 GLint intfmt = glDesc->glInternal;
6562 GLint format = glDesc->glFormat;
6563 GLint type = glDesc->glType;
6564 INT height = This->cursorHeight;
6565 INT width = This->cursorWidth;
6566 INT bpp = tableEntry->bpp;
6569 /* Reformat the texture memory (pitch and width can be
6571 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6572 for(i = 0; i < height; i++)
6573 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6574 IWineD3DSurface_UnlockRect(pCursorBitmap);
6577 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6578 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6579 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6582 /* Make sure that a proper texture unit is selected */
6583 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6584 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6585 checkGLcall("glActiveTextureARB");
6587 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6588 /* Create a new cursor texture */
6589 glGenTextures(1, &This->cursorTexture);
6590 checkGLcall("glGenTextures");
6591 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6592 checkGLcall("glBindTexture");
6593 /* Copy the bitmap memory into the cursor texture */
6594 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6595 HeapFree(GetProcessHeap(), 0, mem);
6596 checkGLcall("glTexImage2D");
6598 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6599 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6600 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6607 FIXME("A cursor texture was not returned.\n");
6608 This->cursorTexture = 0;
6613 /* Draw a hardware cursor */
6614 ICONINFO cursorInfo;
6616 /* Create and clear maskBits because it is not needed for
6617 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6619 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6620 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6621 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6622 WINED3DLOCK_NO_DIRTY_UPDATE |
6623 WINED3DLOCK_READONLY
6625 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6626 pSur->currentDesc.Height);
6628 cursorInfo.fIcon = FALSE;
6629 cursorInfo.xHotspot = XHotSpot;
6630 cursorInfo.yHotspot = YHotSpot;
6631 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6632 pSur->currentDesc.Height, 1,
6634 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6635 pSur->currentDesc.Height, 1,
6636 32, lockedRect.pBits);
6637 IWineD3DSurface_UnlockRect(pCursorBitmap);
6638 /* Create our cursor and clean up. */
6639 cursor = CreateIconIndirect(&cursorInfo);
6641 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6642 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6643 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6644 This->hardwareCursor = cursor;
6645 HeapFree(GetProcessHeap(), 0, maskBits);
6649 This->xHotSpot = XHotSpot;
6650 This->yHotSpot = YHotSpot;
6654 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6656 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6658 This->xScreenSpace = XScreenSpace;
6659 This->yScreenSpace = YScreenSpace;
6665 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6666 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6667 BOOL oldVisible = This->bCursorVisible;
6670 TRACE("(%p) : visible(%d)\n", This, bShow);
6673 * When ShowCursor is first called it should make the cursor appear at the OS's last
6674 * known cursor position. Because of this, some applications just repetitively call
6675 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6678 This->xScreenSpace = pt.x;
6679 This->yScreenSpace = pt.y;
6681 if (This->haveHardwareCursor) {
6682 This->bCursorVisible = bShow;
6684 SetCursor(This->hardwareCursor);
6690 if (This->cursorTexture)
6691 This->bCursorVisible = bShow;
6697 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6699 IWineD3DResourceImpl *resource;
6700 TRACE("(%p) : state (%u)\n", This, This->state);
6702 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6703 switch (This->state) {
6706 case WINED3DERR_DEVICELOST:
6708 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6709 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6710 return WINED3DERR_DEVICENOTRESET;
6712 return WINED3DERR_DEVICELOST;
6714 case WINED3DERR_DRIVERINTERNALERROR:
6715 return WINED3DERR_DRIVERINTERNALERROR;
6719 return WINED3DERR_DRIVERINTERNALERROR;
6723 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6725 /** FIXME: Resource tracking needs to be done,
6726 * The closes we can do to this is set the priorities of all managed textures low
6727 * and then reset them.
6728 ***********************************************************/
6729 FIXME("(%p) : stub\n", This);
6733 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6734 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6736 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6737 if(surface->Flags & SFLAG_DIBSECTION) {
6738 /* Release the DC */
6739 SelectObject(surface->hDC, surface->dib.holdbitmap);
6740 DeleteDC(surface->hDC);
6741 /* Release the DIB section */
6742 DeleteObject(surface->dib.DIBsection);
6743 surface->dib.bitmap_data = NULL;
6744 surface->resource.allocatedMemory = NULL;
6745 surface->Flags &= ~SFLAG_DIBSECTION;
6747 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6748 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6749 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6750 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6751 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6753 surface->pow2Width = surface->pow2Height = 1;
6754 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6755 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6757 if(surface->glDescription.textureName) {
6758 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6760 glDeleteTextures(1, &surface->glDescription.textureName);
6762 surface->glDescription.textureName = 0;
6763 surface->Flags &= ~SFLAG_CLIENT;
6765 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6766 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6767 surface->Flags |= SFLAG_NONPOW2;
6769 surface->Flags &= ~SFLAG_NONPOW2;
6771 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6772 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6775 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6777 IWineD3DSwapChainImpl *swapchain;
6779 BOOL DisplayModeChanged = FALSE;
6780 WINED3DDISPLAYMODE mode;
6781 TRACE("(%p)\n", This);
6783 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6785 ERR("Failed to get the first implicit swapchain\n");
6789 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6790 * on an existing gl context, so there's no real need for recreation.
6792 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6794 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6796 TRACE("New params:\n");
6797 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6798 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6799 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6800 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6801 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6802 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6803 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6804 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6805 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6806 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6807 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6808 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6809 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6811 /* No special treatment of these parameters. Just store them */
6812 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6813 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6814 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6815 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6817 /* What to do about these? */
6818 if(pPresentationParameters->BackBufferCount != 0 &&
6819 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6820 ERR("Cannot change the back buffer count yet\n");
6822 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6823 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6824 ERR("Cannot change the back buffer format yet\n");
6826 if(pPresentationParameters->hDeviceWindow != NULL &&
6827 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6828 ERR("Cannot change the device window yet\n");
6830 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6831 ERR("What do do about a changed auto depth stencil parameter?\n");
6834 if(pPresentationParameters->Windowed) {
6835 mode.Width = swapchain->orig_width;
6836 mode.Height = swapchain->orig_height;
6837 mode.RefreshRate = 0;
6838 mode.Format = swapchain->presentParms.BackBufferFormat;
6840 mode.Width = pPresentationParameters->BackBufferWidth;
6841 mode.Height = pPresentationParameters->BackBufferHeight;
6842 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6843 mode.Format = swapchain->presentParms.BackBufferFormat;
6846 /* Should Width == 800 && Height == 0 set 800x600? */
6847 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6848 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6849 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6856 vp.Width = pPresentationParameters->BackBufferWidth;
6857 vp.Height = pPresentationParameters->BackBufferHeight;
6861 if(!pPresentationParameters->Windowed) {
6862 DisplayModeChanged = TRUE;
6864 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6865 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6867 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6868 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6869 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6872 /* Now set the new viewport */
6873 IWineD3DDevice_SetViewport(iface, &vp);
6876 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6877 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6878 DisplayModeChanged) {
6880 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6881 if(!pPresentationParameters->Windowed) {
6882 IWineD3DDevice_SetFullscreen(iface, TRUE);
6885 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6887 /* Switching out of fullscreen mode? First set the original res, then change the window */
6888 if(pPresentationParameters->Windowed) {
6889 IWineD3DDevice_SetFullscreen(iface, FALSE);
6891 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6894 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6898 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6900 /** FIXME: always true at the moment **/
6901 if(!bEnableDialogs) {
6902 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6908 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6910 TRACE("(%p) : pParameters %p\n", This, pParameters);
6912 *pParameters = This->createParms;
6916 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6917 IWineD3DSwapChain *swapchain;
6918 HRESULT hrc = WINED3D_OK;
6920 TRACE("Relaying to swapchain\n");
6922 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6923 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6924 IWineD3DSwapChain_Release(swapchain);
6929 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6930 IWineD3DSwapChain *swapchain;
6931 HRESULT hrc = WINED3D_OK;
6933 TRACE("Relaying to swapchain\n");
6935 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6936 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6937 IWineD3DSwapChain_Release(swapchain);
6943 /** ********************************************************
6944 * Notification functions
6945 ** ********************************************************/
6946 /** This function must be called in the release of a resource when ref == 0,
6947 * the contents of resource must still be correct,
6948 * any handels to other resource held by the caller must be closed
6949 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6950 *****************************************************/
6951 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6954 TRACE("(%p) : Adding Resource %p\n", This, resource);
6955 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6958 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6961 TRACE("(%p) : Removing resource %p\n", This, resource);
6963 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6967 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6971 TRACE("(%p) : resource %p\n", This, resource);
6972 switch(IWineD3DResource_GetType(resource)){
6973 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6974 case WINED3DRTYPE_SURFACE: {
6977 /* Cleanup any FBO attachments if d3d is enabled */
6978 if(This->d3d_initialized) {
6979 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
6980 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
6982 TRACE("Last active render target destroyed\n");
6983 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
6984 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
6985 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
6986 * and the lastActiveRenderTarget member shouldn't matter
6989 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
6990 TRACE("Activating primary back buffer\n");
6991 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
6992 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
6993 /* Single buffering environment */
6994 TRACE("Activating primary front buffer\n");
6995 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
6997 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
6998 /* Implicit render target destroyed, that means the device is being destroyed
6999 * whatever we set here, it shouldn't matter
7001 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7004 /* May happen during ddraw uninitialization */
7005 TRACE("Render target set, but swapchain does not exist!\n");
7006 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7010 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7011 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7012 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7013 set_render_target_fbo(iface, i, NULL);
7014 This->fbo_color_attachments[i] = NULL;
7017 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7018 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7019 set_depth_stencil_fbo(iface, NULL);
7020 This->fbo_depth_attachment = NULL;
7026 case WINED3DRTYPE_TEXTURE:
7027 case WINED3DRTYPE_CUBETEXTURE:
7028 case WINED3DRTYPE_VOLUMETEXTURE:
7029 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7030 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7031 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7032 This->stateBlock->textures[counter] = NULL;
7034 if (This->updateStateBlock != This->stateBlock ){
7035 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7036 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7037 This->updateStateBlock->textures[counter] = NULL;
7042 case WINED3DRTYPE_VOLUME:
7043 /* TODO: nothing really? */
7045 case WINED3DRTYPE_VERTEXBUFFER:
7046 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7049 TRACE("Cleaning up stream pointers\n");
7051 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7052 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7053 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7055 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7056 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7057 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7058 This->updateStateBlock->streamSource[streamNumber] = 0;
7059 /* Set changed flag? */
7062 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) */
7063 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7064 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7065 This->stateBlock->streamSource[streamNumber] = 0;
7068 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7069 else { /* This shouldn't happen */
7070 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7077 case WINED3DRTYPE_INDEXBUFFER:
7078 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7079 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7080 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7081 This->updateStateBlock->pIndexData = NULL;
7084 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7085 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7086 This->stateBlock->pIndexData = NULL;
7092 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7097 /* Remove the resoruce from the resourceStore */
7098 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7100 TRACE("Resource released\n");
7104 /**********************************************************
7105 * IWineD3DDevice VTbl follows
7106 **********************************************************/
7108 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7110 /*** IUnknown methods ***/
7111 IWineD3DDeviceImpl_QueryInterface,
7112 IWineD3DDeviceImpl_AddRef,
7113 IWineD3DDeviceImpl_Release,
7114 /*** IWineD3DDevice methods ***/
7115 IWineD3DDeviceImpl_GetParent,
7116 /*** Creation methods**/
7117 IWineD3DDeviceImpl_CreateVertexBuffer,
7118 IWineD3DDeviceImpl_CreateIndexBuffer,
7119 IWineD3DDeviceImpl_CreateStateBlock,
7120 IWineD3DDeviceImpl_CreateSurface,
7121 IWineD3DDeviceImpl_CreateTexture,
7122 IWineD3DDeviceImpl_CreateVolumeTexture,
7123 IWineD3DDeviceImpl_CreateVolume,
7124 IWineD3DDeviceImpl_CreateCubeTexture,
7125 IWineD3DDeviceImpl_CreateQuery,
7126 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7127 IWineD3DDeviceImpl_CreateVertexDeclaration,
7128 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7129 IWineD3DDeviceImpl_CreateVertexShader,
7130 IWineD3DDeviceImpl_CreatePixelShader,
7131 IWineD3DDeviceImpl_CreatePalette,
7132 /*** Odd functions **/
7133 IWineD3DDeviceImpl_Init3D,
7134 IWineD3DDeviceImpl_Uninit3D,
7135 IWineD3DDeviceImpl_SetFullscreen,
7136 IWineD3DDeviceImpl_SetMultithreaded,
7137 IWineD3DDeviceImpl_EvictManagedResources,
7138 IWineD3DDeviceImpl_GetAvailableTextureMem,
7139 IWineD3DDeviceImpl_GetBackBuffer,
7140 IWineD3DDeviceImpl_GetCreationParameters,
7141 IWineD3DDeviceImpl_GetDeviceCaps,
7142 IWineD3DDeviceImpl_GetDirect3D,
7143 IWineD3DDeviceImpl_GetDisplayMode,
7144 IWineD3DDeviceImpl_SetDisplayMode,
7145 IWineD3DDeviceImpl_GetHWND,
7146 IWineD3DDeviceImpl_SetHWND,
7147 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7148 IWineD3DDeviceImpl_GetRasterStatus,
7149 IWineD3DDeviceImpl_GetSwapChain,
7150 IWineD3DDeviceImpl_Reset,
7151 IWineD3DDeviceImpl_SetDialogBoxMode,
7152 IWineD3DDeviceImpl_SetCursorProperties,
7153 IWineD3DDeviceImpl_SetCursorPosition,
7154 IWineD3DDeviceImpl_ShowCursor,
7155 IWineD3DDeviceImpl_TestCooperativeLevel,
7156 /*** Getters and setters **/
7157 IWineD3DDeviceImpl_SetClipPlane,
7158 IWineD3DDeviceImpl_GetClipPlane,
7159 IWineD3DDeviceImpl_SetClipStatus,
7160 IWineD3DDeviceImpl_GetClipStatus,
7161 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7162 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7163 IWineD3DDeviceImpl_SetDepthStencilSurface,
7164 IWineD3DDeviceImpl_GetDepthStencilSurface,
7165 IWineD3DDeviceImpl_SetFVF,
7166 IWineD3DDeviceImpl_GetFVF,
7167 IWineD3DDeviceImpl_SetGammaRamp,
7168 IWineD3DDeviceImpl_GetGammaRamp,
7169 IWineD3DDeviceImpl_SetIndices,
7170 IWineD3DDeviceImpl_GetIndices,
7171 IWineD3DDeviceImpl_SetBaseVertexIndex,
7172 IWineD3DDeviceImpl_GetBaseVertexIndex,
7173 IWineD3DDeviceImpl_SetLight,
7174 IWineD3DDeviceImpl_GetLight,
7175 IWineD3DDeviceImpl_SetLightEnable,
7176 IWineD3DDeviceImpl_GetLightEnable,
7177 IWineD3DDeviceImpl_SetMaterial,
7178 IWineD3DDeviceImpl_GetMaterial,
7179 IWineD3DDeviceImpl_SetNPatchMode,
7180 IWineD3DDeviceImpl_GetNPatchMode,
7181 IWineD3DDeviceImpl_SetPaletteEntries,
7182 IWineD3DDeviceImpl_GetPaletteEntries,
7183 IWineD3DDeviceImpl_SetPixelShader,
7184 IWineD3DDeviceImpl_GetPixelShader,
7185 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7186 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7187 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7188 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7189 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7190 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7191 IWineD3DDeviceImpl_SetRenderState,
7192 IWineD3DDeviceImpl_GetRenderState,
7193 IWineD3DDeviceImpl_SetRenderTarget,
7194 IWineD3DDeviceImpl_GetRenderTarget,
7195 IWineD3DDeviceImpl_SetFrontBackBuffers,
7196 IWineD3DDeviceImpl_SetSamplerState,
7197 IWineD3DDeviceImpl_GetSamplerState,
7198 IWineD3DDeviceImpl_SetScissorRect,
7199 IWineD3DDeviceImpl_GetScissorRect,
7200 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7201 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7202 IWineD3DDeviceImpl_SetStreamSource,
7203 IWineD3DDeviceImpl_GetStreamSource,
7204 IWineD3DDeviceImpl_SetStreamSourceFreq,
7205 IWineD3DDeviceImpl_GetStreamSourceFreq,
7206 IWineD3DDeviceImpl_SetTexture,
7207 IWineD3DDeviceImpl_GetTexture,
7208 IWineD3DDeviceImpl_SetTextureStageState,
7209 IWineD3DDeviceImpl_GetTextureStageState,
7210 IWineD3DDeviceImpl_SetTransform,
7211 IWineD3DDeviceImpl_GetTransform,
7212 IWineD3DDeviceImpl_SetVertexDeclaration,
7213 IWineD3DDeviceImpl_GetVertexDeclaration,
7214 IWineD3DDeviceImpl_SetVertexShader,
7215 IWineD3DDeviceImpl_GetVertexShader,
7216 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7217 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7218 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7219 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7220 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7221 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7222 IWineD3DDeviceImpl_SetViewport,
7223 IWineD3DDeviceImpl_GetViewport,
7224 IWineD3DDeviceImpl_MultiplyTransform,
7225 IWineD3DDeviceImpl_ValidateDevice,
7226 IWineD3DDeviceImpl_ProcessVertices,
7227 /*** State block ***/
7228 IWineD3DDeviceImpl_BeginStateBlock,
7229 IWineD3DDeviceImpl_EndStateBlock,
7230 /*** Scene management ***/
7231 IWineD3DDeviceImpl_BeginScene,
7232 IWineD3DDeviceImpl_EndScene,
7233 IWineD3DDeviceImpl_Present,
7234 IWineD3DDeviceImpl_Clear,
7236 IWineD3DDeviceImpl_DrawPrimitive,
7237 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7238 IWineD3DDeviceImpl_DrawPrimitiveUP,
7239 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7240 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7241 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7242 IWineD3DDeviceImpl_DrawRectPatch,
7243 IWineD3DDeviceImpl_DrawTriPatch,
7244 IWineD3DDeviceImpl_DeletePatch,
7245 IWineD3DDeviceImpl_ColorFill,
7246 IWineD3DDeviceImpl_UpdateTexture,
7247 IWineD3DDeviceImpl_UpdateSurface,
7248 IWineD3DDeviceImpl_GetFrontBufferData,
7249 /*** object tracking ***/
7250 IWineD3DDeviceImpl_ResourceReleased
7254 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7255 WINED3DRS_ALPHABLENDENABLE ,
7256 WINED3DRS_ALPHAFUNC ,
7257 WINED3DRS_ALPHAREF ,
7258 WINED3DRS_ALPHATESTENABLE ,
7260 WINED3DRS_COLORWRITEENABLE ,
7261 WINED3DRS_DESTBLEND ,
7262 WINED3DRS_DITHERENABLE ,
7263 WINED3DRS_FILLMODE ,
7264 WINED3DRS_FOGDENSITY ,
7266 WINED3DRS_FOGSTART ,
7267 WINED3DRS_LASTPIXEL ,
7268 WINED3DRS_SHADEMODE ,
7269 WINED3DRS_SRCBLEND ,
7270 WINED3DRS_STENCILENABLE ,
7271 WINED3DRS_STENCILFAIL ,
7272 WINED3DRS_STENCILFUNC ,
7273 WINED3DRS_STENCILMASK ,
7274 WINED3DRS_STENCILPASS ,
7275 WINED3DRS_STENCILREF ,
7276 WINED3DRS_STENCILWRITEMASK ,
7277 WINED3DRS_STENCILZFAIL ,
7278 WINED3DRS_TEXTUREFACTOR ,
7289 WINED3DRS_ZWRITEENABLE
7292 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7293 WINED3DTSS_ADDRESSW ,
7294 WINED3DTSS_ALPHAARG0 ,
7295 WINED3DTSS_ALPHAARG1 ,
7296 WINED3DTSS_ALPHAARG2 ,
7297 WINED3DTSS_ALPHAOP ,
7298 WINED3DTSS_BUMPENVLOFFSET ,
7299 WINED3DTSS_BUMPENVLSCALE ,
7300 WINED3DTSS_BUMPENVMAT00 ,
7301 WINED3DTSS_BUMPENVMAT01 ,
7302 WINED3DTSS_BUMPENVMAT10 ,
7303 WINED3DTSS_BUMPENVMAT11 ,
7304 WINED3DTSS_COLORARG0 ,
7305 WINED3DTSS_COLORARG1 ,
7306 WINED3DTSS_COLORARG2 ,
7307 WINED3DTSS_COLOROP ,
7308 WINED3DTSS_RESULTARG ,
7309 WINED3DTSS_TEXCOORDINDEX ,
7310 WINED3DTSS_TEXTURETRANSFORMFLAGS
7313 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7314 WINED3DSAMP_ADDRESSU ,
7315 WINED3DSAMP_ADDRESSV ,
7316 WINED3DSAMP_ADDRESSW ,
7317 WINED3DSAMP_BORDERCOLOR ,
7318 WINED3DSAMP_MAGFILTER ,
7319 WINED3DSAMP_MINFILTER ,
7320 WINED3DSAMP_MIPFILTER ,
7321 WINED3DSAMP_MIPMAPLODBIAS ,
7322 WINED3DSAMP_MAXMIPLEVEL ,
7323 WINED3DSAMP_MAXANISOTROPY ,
7324 WINED3DSAMP_SRGBTEXTURE ,
7325 WINED3DSAMP_ELEMENTINDEX
7328 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7330 WINED3DRS_AMBIENTMATERIALSOURCE ,
7331 WINED3DRS_CLIPPING ,
7332 WINED3DRS_CLIPPLANEENABLE ,
7333 WINED3DRS_COLORVERTEX ,
7334 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7335 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7336 WINED3DRS_FOGDENSITY ,
7338 WINED3DRS_FOGSTART ,
7339 WINED3DRS_FOGTABLEMODE ,
7340 WINED3DRS_FOGVERTEXMODE ,
7341 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7342 WINED3DRS_LIGHTING ,
7343 WINED3DRS_LOCALVIEWER ,
7344 WINED3DRS_MULTISAMPLEANTIALIAS ,
7345 WINED3DRS_MULTISAMPLEMASK ,
7346 WINED3DRS_NORMALIZENORMALS ,
7347 WINED3DRS_PATCHEDGESTYLE ,
7348 WINED3DRS_POINTSCALE_A ,
7349 WINED3DRS_POINTSCALE_B ,
7350 WINED3DRS_POINTSCALE_C ,
7351 WINED3DRS_POINTSCALEENABLE ,
7352 WINED3DRS_POINTSIZE ,
7353 WINED3DRS_POINTSIZE_MAX ,
7354 WINED3DRS_POINTSIZE_MIN ,
7355 WINED3DRS_POINTSPRITEENABLE ,
7356 WINED3DRS_RANGEFOGENABLE ,
7357 WINED3DRS_SPECULARMATERIALSOURCE ,
7358 WINED3DRS_TWEENFACTOR ,
7359 WINED3DRS_VERTEXBLEND ,
7360 WINED3DRS_CULLMODE ,
7364 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7365 WINED3DTSS_TEXCOORDINDEX ,
7366 WINED3DTSS_TEXTURETRANSFORMFLAGS
7369 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7370 WINED3DSAMP_DMAPOFFSET
7373 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7374 DWORD rep = StateTable[state].representative;
7378 WineD3DContext *context;
7381 for(i = 0; i < This->numContexts; i++) {
7382 context = This->contexts[i];
7383 if(isStateDirty(context, rep)) continue;
7385 context->dirtyArray[context->numDirtyEntries++] = rep;
7388 context->isStateDirty[idx] |= (1 << shift);
7392 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7393 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7394 /* The drawable size of a pbuffer render target is the current pbuffer size
7396 *width = dev->pbufferWidth;
7397 *height = dev->pbufferHeight;
7400 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7401 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7403 *width = This->pow2Width;
7404 *height = This->pow2Height;
7407 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7408 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7409 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7410 * current context's drawable, which is the size of the back buffer of the swapchain
7411 * the active context belongs to. The back buffer of the swapchain is stored as the
7412 * surface the context belongs to.
7414 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7415 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;