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);
280 object->vbo_size = object->resource.size;
281 object->vbo_usage = glUsage;
287 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
288 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
289 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
291 object->Flags |= VBFLAG_VBOCREATEFAIL;
296 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
297 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
300 IWineD3DVertexBufferImpl *object;
301 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
302 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
306 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
307 *ppVertexBuffer = NULL;
308 return WINED3DERR_INVALIDCALL;
309 } else if(Pool == WINED3DPOOL_SCRATCH) {
310 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
311 * anyway, SCRATCH vertex buffers aren't useable anywhere
313 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
314 *ppVertexBuffer = NULL;
315 return WINED3DERR_INVALIDCALL;
318 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
320 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
321 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
325 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
326 * drawStridedFast (half-life 2).
328 * Basically converting the vertices in the buffer is quite expensive, and observations
329 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
330 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
332 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
333 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
334 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
335 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
337 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
338 * more. In this call we can convert dx7 buffers too.
340 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
341 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
342 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
343 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
344 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
345 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
346 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
347 } else if(dxVersion <= 7 && conv) {
348 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
355 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
356 GLenum error, glUsage;
357 TRACE("Creating VBO for Index Buffer %p\n", object);
359 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
360 * restored on the next draw
362 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
364 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
365 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
370 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
371 error = glGetError();
372 if(error != GL_NO_ERROR || object->vbo == 0) {
373 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
377 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
378 error = glGetError();
379 if(error != GL_NO_ERROR) {
380 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
384 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
385 * copy no readback will be needed
387 glUsage = GL_STATIC_DRAW_ARB;
388 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
389 error = glGetError();
390 if(error != GL_NO_ERROR) {
391 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
395 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
399 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
400 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
405 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
406 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
407 HANDLE *sharedHandle, IUnknown *parent) {
408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
409 IWineD3DIndexBufferImpl *object;
410 TRACE("(%p) Creating index buffer\n", This);
412 /* Allocate the storage for the device */
413 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
415 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
416 CreateIndexBufferVBO(This, object);
419 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
420 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
421 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
426 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
429 IWineD3DStateBlockImpl *object;
433 D3DCREATEOBJECTINSTANCE(object, StateBlock)
434 object->blockType = Type;
436 for(i = 0; i < LIGHTMAP_SIZE; i++) {
437 list_init(&object->lightMap[i]);
440 /* Special case - Used during initialization to produce a placeholder stateblock
441 so other functions called can update a state block */
442 if (Type == WINED3DSBT_INIT) {
443 /* Don't bother increasing the reference count otherwise a device will never
444 be freed due to circular dependencies */
448 temp_result = allocate_shader_constants(object);
449 if (WINED3D_OK != temp_result)
452 /* Otherwise, might as well set the whole state block to the appropriate values */
453 if (This->stateBlock != NULL)
454 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
456 memset(object->streamFreq, 1, sizeof(object->streamFreq));
458 /* Reset the ref and type after kludging it */
459 object->wineD3DDevice = This;
461 object->blockType = Type;
463 TRACE("Updating changed flags appropriate for type %d\n", Type);
465 if (Type == WINED3DSBT_ALL) {
467 TRACE("ALL => Pretend everything has changed\n");
468 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
470 /* Lights are not part of the changed / set structure */
471 for(j = 0; j < LIGHTMAP_SIZE; j++) {
473 LIST_FOR_EACH(e, &object->lightMap[j]) {
474 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
475 light->changed = TRUE;
476 light->enabledChanged = TRUE;
479 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
480 object->contained_render_states[j - 1] = j;
482 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
483 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
484 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
485 object->contained_transform_states[j - 1] = j;
487 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
488 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
489 object->contained_vs_consts_f[j] = j;
491 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
492 for(j = 0; j < MAX_CONST_I; j++) {
493 object->contained_vs_consts_i[j] = j;
495 object->num_contained_vs_consts_i = MAX_CONST_I;
496 for(j = 0; j < MAX_CONST_B; j++) {
497 object->contained_vs_consts_b[j] = j;
499 object->num_contained_vs_consts_b = MAX_CONST_B;
500 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
501 object->contained_ps_consts_f[j] = j;
503 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
504 for(j = 0; j < MAX_CONST_I; j++) {
505 object->contained_ps_consts_i[j] = j;
507 object->num_contained_ps_consts_i = MAX_CONST_I;
508 for(j = 0; j < MAX_CONST_B; j++) {
509 object->contained_ps_consts_b[j] = j;
511 object->num_contained_ps_consts_b = MAX_CONST_B;
512 for(i = 0; i < MAX_TEXTURES; i++) {
513 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
514 object->contained_tss_states[object->num_contained_tss_states].stage = i;
515 object->contained_tss_states[object->num_contained_tss_states].state = j;
516 object->num_contained_tss_states++;
519 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
520 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
521 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
522 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
523 object->num_contained_sampler_states++;
527 for(i = 0; i < MAX_STREAMS; i++) {
528 if(object->streamSource[i]) {
529 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
532 if(object->pIndexData) {
533 IWineD3DIndexBuffer_AddRef(object->pIndexData);
535 if(object->vertexShader) {
536 IWineD3DVertexShader_AddRef(object->vertexShader);
538 if(object->pixelShader) {
539 IWineD3DPixelShader_AddRef(object->pixelShader);
542 } else if (Type == WINED3DSBT_PIXELSTATE) {
544 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
545 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
547 object->changed.pixelShader = TRUE;
549 /* Pixel Shader Constants */
550 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
551 object->contained_ps_consts_f[i] = i;
552 object->changed.pixelShaderConstantsF[i] = TRUE;
554 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
555 for (i = 0; i < MAX_CONST_B; ++i) {
556 object->contained_ps_consts_b[i] = i;
557 object->changed.pixelShaderConstantsB[i] = TRUE;
559 object->num_contained_ps_consts_b = MAX_CONST_B;
560 for (i = 0; i < MAX_CONST_I; ++i) {
561 object->contained_ps_consts_i[i] = i;
562 object->changed.pixelShaderConstantsI[i] = TRUE;
564 object->num_contained_ps_consts_i = MAX_CONST_I;
566 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
567 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
568 object->contained_render_states[i] = SavedPixelStates_R[i];
570 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
571 for (j = 0; j < MAX_TEXTURES; j++) {
572 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
573 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
574 object->contained_tss_states[object->num_contained_tss_states].stage = j;
575 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
576 object->num_contained_tss_states++;
579 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
580 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
581 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
582 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
583 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
584 object->num_contained_sampler_states++;
587 if(object->pixelShader) {
588 IWineD3DPixelShader_AddRef(object->pixelShader);
591 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
592 * on them. This makes releasing the buffer easier
594 for(i = 0; i < MAX_STREAMS; i++) {
595 object->streamSource[i] = NULL;
597 object->pIndexData = NULL;
598 object->vertexShader = NULL;
600 } else if (Type == WINED3DSBT_VERTEXSTATE) {
602 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
603 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
605 object->changed.vertexShader = TRUE;
607 /* Vertex Shader Constants */
608 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
609 object->changed.vertexShaderConstantsF[i] = TRUE;
610 object->contained_vs_consts_f[i] = i;
612 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
613 for (i = 0; i < MAX_CONST_B; ++i) {
614 object->changed.vertexShaderConstantsB[i] = TRUE;
615 object->contained_vs_consts_b[i] = i;
617 object->num_contained_vs_consts_b = MAX_CONST_B;
618 for (i = 0; i < MAX_CONST_I; ++i) {
619 object->changed.vertexShaderConstantsI[i] = TRUE;
620 object->contained_vs_consts_i[i] = i;
622 object->num_contained_vs_consts_i = MAX_CONST_I;
623 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
624 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
625 object->contained_render_states[i] = SavedVertexStates_R[i];
627 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
628 for (j = 0; j < MAX_TEXTURES; j++) {
629 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
630 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
631 object->contained_tss_states[object->num_contained_tss_states].stage = j;
632 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
633 object->num_contained_tss_states++;
636 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
637 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
638 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
639 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
640 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
641 object->num_contained_sampler_states++;
645 for(j = 0; j < LIGHTMAP_SIZE; j++) {
647 LIST_FOR_EACH(e, &object->lightMap[j]) {
648 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
649 light->changed = TRUE;
650 light->enabledChanged = TRUE;
654 for(i = 0; i < MAX_STREAMS; i++) {
655 if(object->streamSource[i]) {
656 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
659 if(object->vertexShader) {
660 IWineD3DVertexShader_AddRef(object->vertexShader);
662 object->pIndexData = NULL;
663 object->pixelShader = NULL;
665 FIXME("Unrecognized state block type %d\n", Type);
668 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
672 /* ************************************
674 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
677 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
679 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.
681 ******************************** */
683 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) {
684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
685 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
686 unsigned int Size = 1;
687 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
688 TRACE("(%p) Create surface\n",This);
690 /** FIXME: Check ranges on the inputs are valid
693 * [in] Quality level. The valid range is between zero and one less than the level
694 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
695 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
696 * values of paired render targets, depth stencil surfaces, and the MultiSample type
698 *******************************/
703 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
705 * If this flag is set, the contents of the depth stencil buffer will be
706 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
707 * with a different depth surface.
709 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
710 ***************************/
712 if(MultisampleQuality > 0) {
713 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
714 MultisampleQuality=0;
717 /** FIXME: Check that the format is supported
719 *******************************/
721 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
722 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
724 *********************************/
725 if (WINED3DFMT_UNKNOWN == Format) {
727 } else if (Format == WINED3DFMT_DXT1) {
728 /* DXT1 is half byte per pixel */
729 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
731 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
732 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
733 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
735 /* The pitch is a multiple of 4 bytes */
736 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
740 /** Create and initialise the surface resource **/
741 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
742 /* "Standalone" surface */
743 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
745 object->currentDesc.Width = Width;
746 object->currentDesc.Height = Height;
747 object->currentDesc.MultiSampleType = MultiSample;
748 object->currentDesc.MultiSampleQuality = MultisampleQuality;
749 object->glDescription.level = Level;
753 object->Flags |= Discard ? SFLAG_DISCARD : 0;
754 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
755 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
758 if (WINED3DFMT_UNKNOWN != Format) {
759 object->bytesPerPixel = tableEntry->bpp;
761 object->bytesPerPixel = 0;
764 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
766 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
768 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
769 * this function is too deep to need to care about things like this.
770 * Levels need to be checked too, and possibly Type since they all affect what can be done.
771 * ****************************************/
773 case WINED3DPOOL_SCRATCH:
775 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
776 "which are mutually exclusive, setting lockable to TRUE\n");
779 case WINED3DPOOL_SYSTEMMEM:
780 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
781 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
782 case WINED3DPOOL_MANAGED:
783 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
784 "Usage of DYNAMIC which are mutually exclusive, not doing "
785 "anything just telling you.\n");
787 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
788 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
789 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
790 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
793 FIXME("(%p) Unknown pool %d\n", This, Pool);
797 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
798 FIXME("Trying to create a render target that isn't in the default pool\n");
801 /* mark the texture as dirty so that it gets loaded first time around*/
802 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
803 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
804 This, Width, Height, Format, debug_d3dformat(Format),
805 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
807 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
808 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
809 This->ddraw_primary = (IWineD3DSurface *) object;
811 /* Look at the implementation and set the correct Vtable */
814 /* Check if a 3D adapter is available when creating gl surfaces */
816 ERR("OpenGL surfaces are not available without opengl\n");
817 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
818 HeapFree(GetProcessHeap(), 0, object);
819 return WINED3DERR_NOTAVAILABLE;
824 object->lpVtbl = &IWineGDISurface_Vtbl;
828 /* To be sure to catch this */
829 ERR("Unknown requested surface implementation %d!\n", Impl);
830 IWineD3DSurface_Release((IWineD3DSurface *) object);
831 return WINED3DERR_INVALIDCALL;
834 list_init(&object->renderbuffers);
836 /* Call the private setup routine */
837 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
841 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
842 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
843 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
844 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
847 IWineD3DTextureImpl *object;
852 unsigned int pow2Width;
853 unsigned int pow2Height;
854 const GlPixelFormatDesc *glDesc;
855 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
858 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
859 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
860 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
862 /* TODO: It should only be possible to create textures for formats
863 that are reported as supported */
864 if (WINED3DFMT_UNKNOWN >= Format) {
865 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
866 return WINED3DERR_INVALIDCALL;
869 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
870 D3DINITIALIZEBASETEXTURE(object->baseTexture);
871 object->width = Width;
872 object->height = Height;
874 /** Non-power2 support **/
875 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
879 /* Find the nearest pow2 match */
880 pow2Width = pow2Height = 1;
881 while (pow2Width < Width) pow2Width <<= 1;
882 while (pow2Height < Height) pow2Height <<= 1;
884 if(pow2Width != Width || pow2Height != Height) {
886 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
887 HeapFree(GetProcessHeap(), 0, object);
889 return WINED3DERR_INVALIDCALL;
896 /** FIXME: add support for real non-power-two if it's provided by the video card **/
897 /* Precalculated scaling for 'faked' non power of two texture coords */
898 if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
899 (Width != pow2Width || Height != pow2Height)) {
900 object->baseTexture.pow2Matrix[0] = (float)Width;
901 object->baseTexture.pow2Matrix[5] = (float)Height;
902 object->baseTexture.pow2Matrix[10] = 1.0;
903 object->baseTexture.pow2Matrix[15] = 1.0;
904 object->target = GL_TEXTURE_RECTANGLE_ARB;
906 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
907 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
908 object->baseTexture.pow2Matrix[10] = 1.0;
909 object->baseTexture.pow2Matrix[15] = 1.0;
910 object->target = GL_TEXTURE_2D;
912 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
914 /* Calculate levels for mip mapping */
915 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
916 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
917 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
918 return WINED3DERR_INVALIDCALL;
921 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
922 return WINED3DERR_INVALIDCALL;
924 object->baseTexture.levels = 1;
925 } else if (Levels == 0) {
926 TRACE("calculating levels %d\n", object->baseTexture.levels);
927 object->baseTexture.levels++;
930 while (tmpW > 1 || tmpH > 1) {
931 tmpW = max(1, tmpW >> 1);
932 tmpH = max(1, tmpH >> 1);
933 object->baseTexture.levels++;
935 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
938 /* Generate all the surfaces */
941 for (i = 0; i < object->baseTexture.levels; i++)
943 /* use the callback to create the texture surface */
944 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
945 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
946 FIXME("Failed to create surface %p\n", object);
948 object->surfaces[i] = NULL;
949 IWineD3DTexture_Release((IWineD3DTexture *)object);
955 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
956 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
957 /* calculate the next mipmap level */
958 tmpW = max(1, tmpW >> 1);
959 tmpH = max(1, tmpH >> 1);
961 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
963 TRACE("(%p) : Created texture %p\n", This, object);
967 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
968 UINT Width, UINT Height, UINT Depth,
969 UINT Levels, DWORD Usage,
970 WINED3DFORMAT Format, WINED3DPOOL Pool,
971 IWineD3DVolumeTexture **ppVolumeTexture,
972 HANDLE *pSharedHandle, IUnknown *parent,
973 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
976 IWineD3DVolumeTextureImpl *object;
981 const GlPixelFormatDesc *glDesc;
983 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
985 /* TODO: It should only be possible to create textures for formats
986 that are reported as supported */
987 if (WINED3DFMT_UNKNOWN >= Format) {
988 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
989 return WINED3DERR_INVALIDCALL;
991 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
992 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
993 return WINED3DERR_INVALIDCALL;
996 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
997 D3DINITIALIZEBASETEXTURE(object->baseTexture);
999 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1000 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1002 object->width = Width;
1003 object->height = Height;
1004 object->depth = Depth;
1006 /* Is NP2 support for volumes needed? */
1007 object->baseTexture.pow2Matrix[ 0] = 1.0;
1008 object->baseTexture.pow2Matrix[ 5] = 1.0;
1009 object->baseTexture.pow2Matrix[10] = 1.0;
1010 object->baseTexture.pow2Matrix[15] = 1.0;
1012 /* Calculate levels for mip mapping */
1013 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1014 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1015 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1016 return WINED3DERR_INVALIDCALL;
1019 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1020 return WINED3DERR_INVALIDCALL;
1023 } else if (Levels == 0) {
1024 object->baseTexture.levels++;
1028 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1029 tmpW = max(1, tmpW >> 1);
1030 tmpH = max(1, tmpH >> 1);
1031 tmpD = max(1, tmpD >> 1);
1032 object->baseTexture.levels++;
1034 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1037 /* Generate all the surfaces */
1042 for (i = 0; i < object->baseTexture.levels; i++)
1045 /* Create the volume */
1046 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
1047 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1050 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1051 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1052 *ppVolumeTexture = NULL;
1056 /* Set its container to this object */
1057 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1059 /* calculate the next mipmap level */
1060 tmpW = max(1, tmpW >> 1);
1061 tmpH = max(1, tmpH >> 1);
1062 tmpD = max(1, tmpD >> 1);
1064 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1066 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1067 TRACE("(%p) : Created volume texture %p\n", This, object);
1071 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1072 UINT Width, UINT Height, UINT Depth,
1074 WINED3DFORMAT Format, WINED3DPOOL Pool,
1075 IWineD3DVolume** ppVolume,
1076 HANDLE* pSharedHandle, IUnknown *parent) {
1078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1079 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1080 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1082 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1083 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1084 return WINED3DERR_INVALIDCALL;
1087 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1089 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1090 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1092 object->currentDesc.Width = Width;
1093 object->currentDesc.Height = Height;
1094 object->currentDesc.Depth = Depth;
1095 object->bytesPerPixel = formatDesc->bpp;
1097 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1098 object->lockable = TRUE;
1099 object->locked = FALSE;
1100 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1101 object->dirty = TRUE;
1103 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1106 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1107 UINT Levels, DWORD Usage,
1108 WINED3DFORMAT Format, WINED3DPOOL Pool,
1109 IWineD3DCubeTexture **ppCubeTexture,
1110 HANDLE *pSharedHandle, IUnknown *parent,
1111 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1114 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1118 unsigned int pow2EdgeLength = EdgeLength;
1119 const GlPixelFormatDesc *glDesc;
1120 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1122 /* TODO: It should only be possible to create textures for formats
1123 that are reported as supported */
1124 if (WINED3DFMT_UNKNOWN >= Format) {
1125 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1126 return WINED3DERR_INVALIDCALL;
1129 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1130 WARN("(%p) : Tried to create not supported cube texture\n", This);
1131 return WINED3DERR_INVALIDCALL;
1134 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1135 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1137 TRACE("(%p) Create Cube Texture\n", This);
1139 /** Non-power2 support **/
1141 /* Find the nearest pow2 match */
1143 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1145 object->edgeLength = EdgeLength;
1146 /* TODO: support for native non-power 2 */
1147 /* Precalculated scaling for 'faked' non power of two texture coords */
1148 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1149 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1150 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1151 object->baseTexture.pow2Matrix[15] = 1.0;
1153 /* Calculate levels for mip mapping */
1154 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1155 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1156 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1157 HeapFree(GetProcessHeap(), 0, object);
1158 *ppCubeTexture = NULL;
1160 return WINED3DERR_INVALIDCALL;
1163 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1164 HeapFree(GetProcessHeap(), 0, object);
1165 *ppCubeTexture = NULL;
1167 return WINED3DERR_INVALIDCALL;
1170 } else if (Levels == 0) {
1171 object->baseTexture.levels++;
1174 tmpW = max(1, tmpW >> 1);
1175 object->baseTexture.levels++;
1177 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1180 /* Generate all the surfaces */
1182 for (i = 0; i < object->baseTexture.levels; i++) {
1184 /* Create the 6 faces */
1185 for (j = 0; j < 6; j++) {
1187 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1188 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1190 if(hr!= WINED3D_OK) {
1194 for (l = 0; l < j; l++) {
1195 IWineD3DSurface_Release(object->surfaces[l][i]);
1197 for (k = 0; k < i; k++) {
1198 for (l = 0; l < 6; l++) {
1199 IWineD3DSurface_Release(object->surfaces[l][k]);
1203 FIXME("(%p) Failed to create surface\n",object);
1204 HeapFree(GetProcessHeap(),0,object);
1205 *ppCubeTexture = NULL;
1208 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1209 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1211 tmpW = max(1, tmpW >> 1);
1213 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1215 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1216 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1220 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1222 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1223 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1225 /* Just a check to see if we support this type of query */
1227 case WINED3DQUERYTYPE_OCCLUSION:
1228 TRACE("(%p) occlusion query\n", This);
1229 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1232 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1235 case WINED3DQUERYTYPE_EVENT:
1236 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1237 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1238 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1240 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1245 case WINED3DQUERYTYPE_VCACHE:
1246 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1247 case WINED3DQUERYTYPE_VERTEXSTATS:
1248 case WINED3DQUERYTYPE_TIMESTAMP:
1249 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1250 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1251 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1252 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1253 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1254 case WINED3DQUERYTYPE_PIXELTIMINGS:
1255 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1256 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1258 FIXME("(%p) Unhandled query type %d\n", This, Type);
1260 if(NULL == ppQuery || hr != WINED3D_OK) {
1264 D3DCREATEOBJECTINSTANCE(object, Query)
1265 object->type = Type;
1266 object->state = QUERY_CREATED;
1267 /* allocated the 'extended' data based on the type of query requested */
1269 case WINED3DQUERYTYPE_OCCLUSION:
1270 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1271 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1273 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1274 TRACE("(%p) Allocating data for an occlusion query\n", This);
1275 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1278 case WINED3DQUERYTYPE_EVENT:
1279 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1280 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1282 if(GL_SUPPORT(APPLE_FENCE)) {
1283 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1284 checkGLcall("glGenFencesAPPLE");
1285 } else if(GL_SUPPORT(NV_FENCE)) {
1286 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1287 checkGLcall("glGenFencesNV");
1291 case WINED3DQUERYTYPE_VCACHE:
1292 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1293 case WINED3DQUERYTYPE_VERTEXSTATS:
1294 case WINED3DQUERYTYPE_TIMESTAMP:
1295 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1296 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1297 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1298 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1299 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1300 case WINED3DQUERYTYPE_PIXELTIMINGS:
1301 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1302 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1304 object->extendedData = 0;
1305 FIXME("(%p) Unhandled query type %d\n",This , Type);
1307 TRACE("(%p) : Created Query %p\n", This, object);
1311 /*****************************************************************************
1312 * IWineD3DDeviceImpl_SetupFullscreenWindow
1314 * Helper function that modifies a HWND's Style and ExStyle for proper
1318 * iface: Pointer to the IWineD3DDevice interface
1319 * window: Window to setup
1321 *****************************************************************************/
1322 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1325 LONG style, exStyle;
1326 /* Don't do anything if an original style is stored.
1327 * That shouldn't happen
1329 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1330 if (This->style || This->exStyle) {
1331 ERR("(%p): Want to change the window parameters of HWND %p, but "
1332 "another style is stored for restoration afterwards\n", This, window);
1335 /* Get the parameters and save them */
1336 style = GetWindowLongW(window, GWL_STYLE);
1337 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1338 This->style = style;
1339 This->exStyle = exStyle;
1341 /* Filter out window decorations */
1342 style &= ~WS_CAPTION;
1343 style &= ~WS_THICKFRAME;
1344 exStyle &= ~WS_EX_WINDOWEDGE;
1345 exStyle &= ~WS_EX_CLIENTEDGE;
1347 /* Make sure the window is managed, otherwise we won't get keyboard input */
1348 style |= WS_POPUP | WS_SYSMENU;
1350 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1351 This->style, This->exStyle, style, exStyle);
1353 SetWindowLongW(window, GWL_STYLE, style);
1354 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1356 /* Inform the window about the update. */
1357 SetWindowPos(window, HWND_TOP, 0, 0,
1358 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1359 ShowWindow(window, SW_NORMAL);
1362 /*****************************************************************************
1363 * IWineD3DDeviceImpl_RestoreWindow
1365 * Helper function that restores a windows' properties when taking it out
1366 * of fullscreen mode
1369 * iface: Pointer to the IWineD3DDevice interface
1370 * window: Window to setup
1372 *****************************************************************************/
1373 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1376 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1377 * switch, do nothing
1379 if (!This->style && !This->exStyle) return;
1381 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1382 This, window, This->style, This->exStyle);
1384 SetWindowLongW(window, GWL_STYLE, This->style);
1385 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1387 /* Delete the old values */
1391 /* Inform the window about the update */
1392 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1393 0, 0, 0, 0, /* Pos, Size, ignored */
1394 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1397 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1398 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1400 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1401 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1405 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1406 HRESULT hr = WINED3D_OK;
1407 IUnknown *bufferParent;
1408 BOOL displaymode_set = FALSE;
1409 WINED3DDISPLAYMODE Mode;
1410 const StaticPixelFormatDesc *formatDesc;
1412 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1414 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1415 * does a device hold a reference to a swap chain giving them a lifetime of the device
1416 * or does the swap chain notify the device of its destruction.
1417 *******************************/
1419 /* Check the params */
1420 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1421 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1422 return WINED3DERR_INVALIDCALL;
1423 } else if (pPresentationParameters->BackBufferCount > 1) {
1424 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");
1427 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1429 /*********************
1430 * Lookup the window Handle and the relating X window handle
1431 ********************/
1433 /* Setup hwnd we are using, plus which display this equates to */
1434 object->win_handle = pPresentationParameters->hDeviceWindow;
1435 if (!object->win_handle) {
1436 object->win_handle = This->createParms.hFocusWindow;
1438 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1440 hDc = GetDC(object->win_handle);
1441 TRACE("Using hDc %p\n", hDc);
1444 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1445 return WINED3DERR_NOTAVAILABLE;
1448 /* Get info on the current display setup */
1449 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1450 object->orig_width = Mode.Width;
1451 object->orig_height = Mode.Height;
1452 object->orig_fmt = Mode.Format;
1453 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1455 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1456 * then the corresponding dimension of the client area of the hDeviceWindow
1457 * (or the focus window, if hDeviceWindow is NULL) is taken.
1458 **********************/
1460 if (pPresentationParameters->Windowed &&
1461 ((pPresentationParameters->BackBufferWidth == 0) ||
1462 (pPresentationParameters->BackBufferHeight == 0) ||
1463 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1466 GetClientRect(object->win_handle, &Rect);
1468 if (pPresentationParameters->BackBufferWidth == 0) {
1469 pPresentationParameters->BackBufferWidth = Rect.right;
1470 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1472 if (pPresentationParameters->BackBufferHeight == 0) {
1473 pPresentationParameters->BackBufferHeight = Rect.bottom;
1474 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1476 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1477 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1478 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1482 /* Put the correct figures in the presentation parameters */
1483 TRACE("Copying across presentation parameters\n");
1484 object->presentParms = *pPresentationParameters;
1486 TRACE("calling rendertarget CB\n");
1487 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1489 object->presentParms.BackBufferWidth,
1490 object->presentParms.BackBufferHeight,
1491 object->presentParms.BackBufferFormat,
1492 object->presentParms.MultiSampleType,
1493 object->presentParms.MultiSampleQuality,
1494 TRUE /* Lockable */,
1495 &object->frontBuffer,
1496 NULL /* pShared (always null)*/);
1497 if (object->frontBuffer != NULL) {
1498 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1499 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1501 ERR("Failed to create the front buffer\n");
1505 /*********************
1506 * Windowed / Fullscreen
1507 *******************/
1510 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1511 * so we should really check to see if there is a fullscreen swapchain already
1512 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1513 **************************************/
1515 if (!pPresentationParameters->Windowed) {
1516 WINED3DDISPLAYMODE mode;
1519 /* Change the display settings */
1520 mode.Width = pPresentationParameters->BackBufferWidth;
1521 mode.Height = pPresentationParameters->BackBufferHeight;
1522 mode.Format = pPresentationParameters->BackBufferFormat;
1523 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1525 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1526 displaymode_set = TRUE;
1527 IWineD3DDevice_SetFullscreen(iface, TRUE);
1531 * Create an opengl context for the display visual
1532 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1533 * use different properties after that point in time. FIXME: How to handle when requested format
1534 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1535 * it chooses is identical to the one already being used!
1536 **********************************/
1537 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1539 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1540 if(!object->context)
1541 return E_OUTOFMEMORY;
1542 object->num_contexts = 1;
1544 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1545 if (!object->context[0]) {
1546 ERR("Failed to create a new context\n");
1547 hr = WINED3DERR_NOTAVAILABLE;
1550 TRACE("Context created (HWND=%p, glContext=%p)\n",
1551 object->win_handle, object->context[0]->glCtx);
1554 /*********************
1555 * Create the back, front and stencil buffers
1556 *******************/
1557 if(object->presentParms.BackBufferCount > 0) {
1560 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1561 if(!object->backBuffer) {
1562 ERR("Out of memory\n");
1567 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1568 TRACE("calling rendertarget CB\n");
1569 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1571 object->presentParms.BackBufferWidth,
1572 object->presentParms.BackBufferHeight,
1573 object->presentParms.BackBufferFormat,
1574 object->presentParms.MultiSampleType,
1575 object->presentParms.MultiSampleQuality,
1576 TRUE /* Lockable */,
1577 &object->backBuffer[i],
1578 NULL /* pShared (always null)*/);
1579 if(hr == WINED3D_OK && object->backBuffer[i]) {
1580 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1582 ERR("Cannot create new back buffer\n");
1586 glDrawBuffer(GL_BACK);
1587 checkGLcall("glDrawBuffer(GL_BACK)");
1591 object->backBuffer = NULL;
1593 /* Single buffering - draw to front buffer */
1595 glDrawBuffer(GL_FRONT);
1596 checkGLcall("glDrawBuffer(GL_FRONT)");
1600 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1601 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1602 TRACE("Creating depth stencil buffer\n");
1603 if (This->auto_depth_stencil_buffer == NULL ) {
1604 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1606 object->presentParms.BackBufferWidth,
1607 object->presentParms.BackBufferHeight,
1608 object->presentParms.AutoDepthStencilFormat,
1609 object->presentParms.MultiSampleType,
1610 object->presentParms.MultiSampleQuality,
1611 FALSE /* FIXME: Discard */,
1612 &This->auto_depth_stencil_buffer,
1613 NULL /* pShared (always null)*/ );
1614 if (This->auto_depth_stencil_buffer != NULL)
1615 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1618 /** TODO: A check on width, height and multisample types
1619 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1620 ****************************/
1621 object->wantsDepthStencilBuffer = TRUE;
1623 object->wantsDepthStencilBuffer = FALSE;
1626 TRACE("Created swapchain %p\n", object);
1627 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1631 if (displaymode_set) {
1635 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1638 /* Change the display settings */
1639 memset(&devmode, 0, sizeof(devmode));
1640 devmode.dmSize = sizeof(devmode);
1641 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1642 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1643 devmode.dmPelsWidth = object->orig_width;
1644 devmode.dmPelsHeight = object->orig_height;
1645 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1648 if (object->backBuffer) {
1650 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1651 if(object->backBuffer[i]) {
1652 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1653 IUnknown_Release(bufferParent); /* once for the get parent */
1654 if (IUnknown_Release(bufferParent) > 0) {
1655 FIXME("(%p) Something's still holding the back buffer\n",This);
1659 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1660 object->backBuffer = NULL;
1662 if(object->context[0])
1663 DestroyContext(This, object->context[0]);
1664 if(object->frontBuffer) {
1665 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1666 IUnknown_Release(bufferParent); /* once for the get parent */
1667 if (IUnknown_Release(bufferParent) > 0) {
1668 FIXME("(%p) Something's still holding the front buffer\n",This);
1671 HeapFree(GetProcessHeap(), 0, object);
1675 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1676 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1678 TRACE("(%p)\n", This);
1680 return This->NumberOfSwapChains;
1683 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1685 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1687 if(iSwapChain < This->NumberOfSwapChains) {
1688 *pSwapChain = This->swapchains[iSwapChain];
1689 IWineD3DSwapChain_AddRef(*pSwapChain);
1690 TRACE("(%p) returning %p\n", This, *pSwapChain);
1693 TRACE("Swapchain out of range\n");
1695 return WINED3DERR_INVALIDCALL;
1700 * Vertex Declaration
1702 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1703 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1705 IWineD3DVertexDeclarationImpl *object = NULL;
1706 HRESULT hr = WINED3D_OK;
1708 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1709 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1711 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1713 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1715 *ppVertexDeclaration = NULL;
1716 HeapFree(GetProcessHeap(), 0, object);
1722 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1723 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1725 unsigned int idx, idx2;
1726 unsigned int offset;
1727 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1728 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1729 BOOL has_blend_idx = has_blend &&
1730 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1731 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1732 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1733 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1734 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1735 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1736 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1738 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1739 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1741 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1742 WINED3DVERTEXELEMENT *elements = NULL;
1745 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1746 if (has_blend_idx) num_blends--;
1748 /* Compute declaration size */
1749 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1750 has_psize + has_diffuse + has_specular + num_textures + 1;
1752 /* convert the declaration */
1753 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1757 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1760 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1761 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1762 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1765 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1766 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1768 elements[idx].UsageIndex = 0;
1771 if (has_blend && (num_blends > 0)) {
1772 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1773 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1775 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1776 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1777 elements[idx].UsageIndex = 0;
1780 if (has_blend_idx) {
1781 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1782 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1783 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1784 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1785 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1787 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1788 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1789 elements[idx].UsageIndex = 0;
1793 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1794 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1795 elements[idx].UsageIndex = 0;
1799 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1800 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1801 elements[idx].UsageIndex = 0;
1805 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1806 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1807 elements[idx].UsageIndex = 0;
1811 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1812 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1813 elements[idx].UsageIndex = 1;
1816 for (idx2 = 0; idx2 < num_textures; idx2++) {
1817 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1818 switch (numcoords) {
1819 case WINED3DFVF_TEXTUREFORMAT1:
1820 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1822 case WINED3DFVF_TEXTUREFORMAT2:
1823 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1825 case WINED3DFVF_TEXTUREFORMAT3:
1826 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1828 case WINED3DFVF_TEXTUREFORMAT4:
1829 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1832 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1833 elements[idx].UsageIndex = idx2;
1837 /* Now compute offsets, and initialize the rest of the fields */
1838 for (idx = 0, offset = 0; idx < size-1; idx++) {
1839 elements[idx].Stream = 0;
1840 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1841 elements[idx].Offset = offset;
1842 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1845 *ppVertexElements = elements;
1849 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1850 WINED3DVERTEXELEMENT* elements = NULL;
1851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1855 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1856 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1858 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1859 HeapFree(GetProcessHeap(), 0, elements);
1860 if (hr != S_OK) return hr;
1865 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1866 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1868 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1869 HRESULT hr = WINED3D_OK;
1870 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1871 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1873 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1875 if (vertex_declaration) {
1876 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1879 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1881 if (WINED3D_OK != hr) {
1882 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1883 IWineD3DVertexShader_Release(*ppVertexShader);
1884 return WINED3DERR_INVALIDCALL;
1886 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1891 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1893 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1894 HRESULT hr = WINED3D_OK;
1896 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1897 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1898 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1899 if (WINED3D_OK == hr) {
1900 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1901 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1903 WARN("(%p) : Failed to create pixel shader\n", This);
1909 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1911 IWineD3DPaletteImpl *object;
1913 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1915 /* Create the new object */
1916 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1918 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1919 return E_OUTOFMEMORY;
1922 object->lpVtbl = &IWineD3DPalette_Vtbl;
1924 object->Flags = Flags;
1925 object->parent = Parent;
1926 object->wineD3DDevice = This;
1927 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1929 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1932 HeapFree( GetProcessHeap(), 0, object);
1933 return E_OUTOFMEMORY;
1936 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1938 IWineD3DPalette_Release((IWineD3DPalette *) object);
1942 *Palette = (IWineD3DPalette *) object;
1947 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1951 HDC dcb = NULL, dcs = NULL;
1952 WINEDDCOLORKEY colorkey;
1954 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1957 GetObjectA(hbm, sizeof(BITMAP), &bm);
1958 dcb = CreateCompatibleDC(NULL);
1960 SelectObject(dcb, hbm);
1964 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1965 * couldn't be loaded
1967 memset(&bm, 0, sizeof(bm));
1972 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1973 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1974 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1976 ERR("Wine logo requested, but failed to create surface\n");
1981 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1982 if(FAILED(hr)) goto out;
1983 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1984 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1986 colorkey.dwColorSpaceLowValue = 0;
1987 colorkey.dwColorSpaceHighValue = 0;
1988 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1990 /* Fill the surface with a white color to show that wined3d is there */
1991 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2004 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2006 IWineD3DSwapChainImpl *swapchain;
2010 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2011 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2013 /* TODO: Test if OpenGL is compiled in and loaded */
2015 TRACE("(%p) : Creating stateblock\n", This);
2016 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2017 hr = IWineD3DDevice_CreateStateBlock(iface,
2019 (IWineD3DStateBlock **)&This->stateBlock,
2021 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2022 WARN("Failed to create stateblock\n");
2025 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2026 This->updateStateBlock = This->stateBlock;
2027 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2029 hr = allocate_shader_constants(This->updateStateBlock);
2030 if (WINED3D_OK != hr) {
2034 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2035 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2036 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2038 /* Initialize the texture unit mapping to a 1:1 mapping */
2039 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2040 if (state < GL_LIMITS(fragment_samplers)) {
2041 This->texUnitMap[state] = state;
2042 This->rev_tex_unit_map[state] = state;
2044 This->texUnitMap[state] = -1;
2045 This->rev_tex_unit_map[state] = -1;
2049 /* Setup the implicit swapchain */
2050 TRACE("Creating implicit swapchain\n");
2051 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2052 if (FAILED(hr) || !swapchain) {
2053 WARN("Failed to create implicit swapchain\n");
2057 This->NumberOfSwapChains = 1;
2058 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2059 if(!This->swapchains) {
2060 ERR("Out of memory!\n");
2063 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2065 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2066 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2067 This->render_targets[0] = swapchain->backBuffer[0];
2068 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2071 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2072 This->render_targets[0] = swapchain->frontBuffer;
2073 This->lastActiveRenderTarget = swapchain->frontBuffer;
2075 IWineD3DSurface_AddRef(This->render_targets[0]);
2076 This->activeContext = swapchain->context[0];
2077 This->lastThread = GetCurrentThreadId();
2079 /* Depth Stencil support */
2080 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2081 if (NULL != This->stencilBufferTarget) {
2082 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2085 /* Set up some starting GL setup */
2088 /* Setup all the devices defaults */
2089 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2091 IWineD3DImpl_CheckGraphicsMemory();
2094 { /* Set a default viewport */
2098 vp.Width = pPresentationParameters->BackBufferWidth;
2099 vp.Height = pPresentationParameters->BackBufferHeight;
2102 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2105 /* Initialize the current view state */
2106 This->view_ident = 1;
2107 This->contexts[0]->last_was_rhw = 0;
2108 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2109 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2111 switch(wined3d_settings.offscreen_rendering_mode) {
2114 This->offscreenBuffer = GL_BACK;
2117 case ORM_BACKBUFFER:
2119 if(GL_LIMITS(aux_buffers) > 0) {
2120 TRACE("Using auxilliary buffer for offscreen rendering\n");
2121 This->offscreenBuffer = GL_AUX0;
2123 TRACE("Using back buffer for offscreen rendering\n");
2124 This->offscreenBuffer = GL_BACK;
2129 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2132 /* Clear the screen */
2133 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2134 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2137 This->d3d_initialized = TRUE;
2139 if(wined3d_settings.logo) {
2140 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2145 HeapFree(GetProcessHeap(), 0, This->render_targets);
2146 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2147 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2148 HeapFree(GetProcessHeap(), 0, This->swapchains);
2149 This->NumberOfSwapChains = 0;
2151 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2153 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2154 if(This->stateBlock) {
2155 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2156 This->stateBlock = NULL;
2161 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2165 TRACE("(%p)\n", This);
2167 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2169 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2170 * it was created. Thus make sure a context is active for the glDelete* calls
2172 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2174 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2176 TRACE("Deleting high order patches\n");
2177 for(i = 0; i < PATCHMAP_SIZE; i++) {
2178 struct list *e1, *e2;
2179 struct WineD3DRectPatch *patch;
2180 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2181 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2182 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2186 /* Delete the palette conversion shader if it is around */
2187 if(This->paletteConversionShader) {
2188 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2189 This->paletteConversionShader = 0;
2192 /* Delete the pbuffer context if there is any */
2193 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2195 /* Delete the mouse cursor texture */
2196 if(This->cursorTexture) {
2198 glDeleteTextures(1, &This->cursorTexture);
2200 This->cursorTexture = 0;
2203 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2204 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2206 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2207 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2210 /* Release the update stateblock */
2211 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2212 if(This->updateStateBlock != This->stateBlock)
2213 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2215 This->updateStateBlock = NULL;
2217 { /* because were not doing proper internal refcounts releasing the primary state block
2218 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2219 to set this->stateBlock = NULL; first */
2220 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2221 This->stateBlock = NULL;
2223 /* Release the stateblock */
2224 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2225 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2229 /* Release the buffers (with sanity checks)*/
2230 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2231 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2232 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2233 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2235 This->stencilBufferTarget = NULL;
2237 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2238 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2239 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2241 TRACE("Setting rendertarget to NULL\n");
2242 This->render_targets[0] = NULL;
2244 if (This->auto_depth_stencil_buffer) {
2245 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2246 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2248 This->auto_depth_stencil_buffer = NULL;
2251 for(i=0; i < This->NumberOfSwapChains; i++) {
2252 TRACE("Releasing the implicit swapchain %d\n", i);
2253 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2254 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2258 HeapFree(GetProcessHeap(), 0, This->swapchains);
2259 This->swapchains = NULL;
2260 This->NumberOfSwapChains = 0;
2262 HeapFree(GetProcessHeap(), 0, This->render_targets);
2263 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2264 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2265 This->render_targets = NULL;
2266 This->fbo_color_attachments = NULL;
2267 This->draw_buffers = NULL;
2270 This->d3d_initialized = FALSE;
2274 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2276 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2278 /* Setup the window for fullscreen mode */
2279 if(fullscreen && !This->ddraw_fullscreen) {
2280 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2281 } else if(!fullscreen && This->ddraw_fullscreen) {
2282 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2285 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2286 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2287 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2290 This->ddraw_fullscreen = fullscreen;
2293 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2294 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2295 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2297 * There is no way to deactivate thread safety once it is enabled.
2299 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2302 /*For now just store the flag(needed in case of ddraw) */
2303 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2308 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2310 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2312 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2315 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2317 /* Resize the screen even without a window:
2318 * The app could have unset it with SetCooperativeLevel, but not called
2319 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2320 * but we don't have any hwnd
2323 memset(&devmode, 0, sizeof(devmode));
2324 devmode.dmSize = sizeof(devmode);
2325 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2326 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2327 devmode.dmPelsWidth = pMode->Width;
2328 devmode.dmPelsHeight = pMode->Height;
2330 devmode.dmDisplayFrequency = pMode->RefreshRate;
2331 if (pMode->RefreshRate != 0) {
2332 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2335 /* Only change the mode if necessary */
2336 if( (This->ddraw_width == pMode->Width) &&
2337 (This->ddraw_height == pMode->Height) &&
2338 (This->ddraw_format == pMode->Format) &&
2339 (pMode->RefreshRate == 0) ) {
2343 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2344 if (ret != DISP_CHANGE_SUCCESSFUL) {
2345 if(devmode.dmDisplayFrequency != 0) {
2346 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2347 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2348 devmode.dmDisplayFrequency = 0;
2349 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2351 if(ret != DISP_CHANGE_SUCCESSFUL) {
2352 return WINED3DERR_NOTAVAILABLE;
2356 /* Store the new values */
2357 This->ddraw_width = pMode->Width;
2358 This->ddraw_height = pMode->Height;
2359 This->ddraw_format = pMode->Format;
2361 /* Only do this with a window of course */
2362 if(This->ddraw_window)
2363 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2365 /* And finally clip mouse to our screen */
2366 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2367 ClipCursor(&clip_rc);
2372 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2374 *ppD3D= This->wineD3D;
2375 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2376 IWineD3D_AddRef(*ppD3D);
2380 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2383 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2384 (This->adapter->TextureRam/(1024*1024)),
2385 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2386 /* return simulated texture memory left */
2387 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2395 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2398 /* Update the current state block */
2399 This->updateStateBlock->changed.fvf = TRUE;
2401 if(This->updateStateBlock->fvf == fvf) {
2402 TRACE("Application is setting the old fvf over, nothing to do\n");
2406 This->updateStateBlock->fvf = fvf;
2407 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2408 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2413 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2414 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2415 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2416 *pfvf = This->stateBlock->fvf;
2421 * Get / Set Stream Source
2423 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2425 IWineD3DVertexBuffer *oldSrc;
2427 if (StreamNumber >= MAX_STREAMS) {
2428 WARN("Stream out of range %d\n", StreamNumber);
2429 return WINED3DERR_INVALIDCALL;
2430 } else if(OffsetInBytes & 0x3) {
2431 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2432 return WINED3DERR_INVALIDCALL;
2435 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2436 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2438 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2440 if(oldSrc == pStreamData &&
2441 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2442 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2443 TRACE("Application is setting the old values over, nothing to do\n");
2447 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2449 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2450 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2453 /* Handle recording of state blocks */
2454 if (This->isRecordingState) {
2455 TRACE("Recording... not performing anything\n");
2456 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2457 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2461 /* Need to do a getParent and pass the references up */
2462 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2463 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2464 so for now, just count internally */
2465 if (pStreamData != NULL) {
2466 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2467 InterlockedIncrement(&vbImpl->bindCount);
2468 IWineD3DVertexBuffer_AddRef(pStreamData);
2470 if (oldSrc != NULL) {
2471 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2472 IWineD3DVertexBuffer_Release(oldSrc);
2475 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2480 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2483 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2484 This->stateBlock->streamSource[StreamNumber],
2485 This->stateBlock->streamOffset[StreamNumber],
2486 This->stateBlock->streamStride[StreamNumber]);
2488 if (StreamNumber >= MAX_STREAMS) {
2489 WARN("Stream out of range %d\n", StreamNumber);
2490 return WINED3DERR_INVALIDCALL;
2492 *pStream = This->stateBlock->streamSource[StreamNumber];
2493 *pStride = This->stateBlock->streamStride[StreamNumber];
2495 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2498 if (*pStream != NULL) {
2499 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2504 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2506 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2507 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2509 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2510 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2512 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2513 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2515 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2516 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2523 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2526 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2527 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2529 TRACE("(%p) : returning %d\n", This, *Divider);
2535 * Get / Set & Multiply Transform
2537 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2540 /* Most of this routine, comments included copied from ddraw tree initially: */
2541 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2543 /* Handle recording of state blocks */
2544 if (This->isRecordingState) {
2545 TRACE("Recording... not performing anything\n");
2546 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2547 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2552 * If the new matrix is the same as the current one,
2553 * we cut off any further processing. this seems to be a reasonable
2554 * optimization because as was noticed, some apps (warcraft3 for example)
2555 * tend towards setting the same matrix repeatedly for some reason.
2557 * From here on we assume that the new matrix is different, wherever it matters.
2559 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2560 TRACE("The app is setting the same matrix over again\n");
2563 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2567 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2568 where ViewMat = Camera space, WorldMat = world space.
2570 In OpenGL, camera and world space is combined into GL_MODELVIEW
2571 matrix. The Projection matrix stay projection matrix.
2574 /* Capture the times we can just ignore the change for now */
2575 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2576 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2577 /* Handled by the state manager */
2580 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2584 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2586 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2587 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2591 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2592 WINED3DMATRIX *mat = NULL;
2595 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2596 * below means it will be recorded in a state block change, but it
2597 * works regardless where it is recorded.
2598 * If this is found to be wrong, change to StateBlock.
2600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2601 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2603 if (State < HIGHEST_TRANSFORMSTATE)
2605 mat = &This->updateStateBlock->transforms[State];
2607 FIXME("Unhandled transform state!!\n");
2610 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2612 /* Apply change via set transform - will reapply to eg. lights this way */
2613 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2619 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2620 you can reference any indexes you want as long as that number max are enabled at any
2621 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2622 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2623 but when recording, just build a chain pretty much of commands to be replayed. */
2625 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2627 PLIGHTINFOEL *object = NULL;
2628 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2632 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2634 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2638 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2639 return WINED3DERR_INVALIDCALL;
2642 switch(pLight->Type) {
2643 case WINED3DLIGHT_POINT:
2644 case WINED3DLIGHT_SPOT:
2645 case WINED3DLIGHT_PARALLELPOINT:
2646 case WINED3DLIGHT_GLSPOT:
2647 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2650 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2651 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2652 return WINED3DERR_INVALIDCALL;
2656 case WINED3DLIGHT_DIRECTIONAL:
2657 /* Ignores attenuation */
2661 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2662 return WINED3DERR_INVALIDCALL;
2665 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2666 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2667 if(object->OriginalIndex == Index) break;
2672 TRACE("Adding new light\n");
2673 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2675 ERR("Out of memory error when allocating a light\n");
2676 return E_OUTOFMEMORY;
2678 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2679 object->glIndex = -1;
2680 object->OriginalIndex = Index;
2681 object->changed = TRUE;
2684 /* Initialize the object */
2685 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,
2686 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2687 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2688 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2689 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2690 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2691 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2693 /* Save away the information */
2694 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2696 switch (pLight->Type) {
2697 case WINED3DLIGHT_POINT:
2699 object->lightPosn[0] = pLight->Position.x;
2700 object->lightPosn[1] = pLight->Position.y;
2701 object->lightPosn[2] = pLight->Position.z;
2702 object->lightPosn[3] = 1.0f;
2703 object->cutoff = 180.0f;
2707 case WINED3DLIGHT_DIRECTIONAL:
2709 object->lightPosn[0] = -pLight->Direction.x;
2710 object->lightPosn[1] = -pLight->Direction.y;
2711 object->lightPosn[2] = -pLight->Direction.z;
2712 object->lightPosn[3] = 0.0;
2713 object->exponent = 0.0f;
2714 object->cutoff = 180.0f;
2717 case WINED3DLIGHT_SPOT:
2719 object->lightPosn[0] = pLight->Position.x;
2720 object->lightPosn[1] = pLight->Position.y;
2721 object->lightPosn[2] = pLight->Position.z;
2722 object->lightPosn[3] = 1.0;
2725 object->lightDirn[0] = pLight->Direction.x;
2726 object->lightDirn[1] = pLight->Direction.y;
2727 object->lightDirn[2] = pLight->Direction.z;
2728 object->lightDirn[3] = 1.0;
2731 * opengl-ish and d3d-ish spot lights use too different models for the
2732 * light "intensity" as a function of the angle towards the main light direction,
2733 * so we only can approximate very roughly.
2734 * however spot lights are rather rarely used in games (if ever used at all).
2735 * furthermore if still used, probably nobody pays attention to such details.
2737 if (pLight->Falloff == 0) {
2738 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2739 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2740 * will always be 1.0 for both of them, and we don't have to care for the
2741 * rest of the rather complex calculation
2743 object->exponent = 0;
2745 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2746 if (rho < 0.0001) rho = 0.0001f;
2747 object->exponent = -0.3/log(cos(rho/2));
2749 if (object->exponent > 128.0) {
2750 object->exponent = 128.0;
2752 object->cutoff = pLight->Phi*90/M_PI;
2758 FIXME("Unrecognized light type %d\n", pLight->Type);
2761 /* Update the live definitions if the light is currently assigned a glIndex */
2762 if (object->glIndex != -1 && !This->isRecordingState) {
2763 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2768 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2769 PLIGHTINFOEL *lightInfo = NULL;
2770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2771 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2773 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2775 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2776 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2777 if(lightInfo->OriginalIndex == Index) break;
2781 if (lightInfo == NULL) {
2782 TRACE("Light information requested but light not defined\n");
2783 return WINED3DERR_INVALIDCALL;
2786 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2791 * Get / Set Light Enable
2792 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2794 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2795 PLIGHTINFOEL *lightInfo = NULL;
2796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2797 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2799 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2801 /* Tests show true = 128...not clear why */
2802 Enable = Enable? 128: 0;
2804 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2805 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2806 if(lightInfo->OriginalIndex == Index) break;
2809 TRACE("Found light: %p\n", lightInfo);
2811 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2812 if (lightInfo == NULL) {
2814 TRACE("Light enabled requested but light not defined, so defining one!\n");
2815 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2817 /* Search for it again! Should be fairly quick as near head of list */
2818 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2819 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2820 if(lightInfo->OriginalIndex == Index) break;
2823 if (lightInfo == NULL) {
2824 FIXME("Adding default lights has failed dismally\n");
2825 return WINED3DERR_INVALIDCALL;
2829 lightInfo->enabledChanged = TRUE;
2831 if(lightInfo->glIndex != -1) {
2832 if(!This->isRecordingState) {
2833 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2836 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2837 lightInfo->glIndex = -1;
2839 TRACE("Light already disabled, nothing to do\n");
2841 lightInfo->enabled = FALSE;
2843 lightInfo->enabled = TRUE;
2844 if (lightInfo->glIndex != -1) {
2846 TRACE("Nothing to do as light was enabled\n");
2849 /* Find a free gl light */
2850 for(i = 0; i < This->maxConcurrentLights; i++) {
2851 if(This->stateBlock->activeLights[i] == NULL) {
2852 This->stateBlock->activeLights[i] = lightInfo;
2853 lightInfo->glIndex = i;
2857 if(lightInfo->glIndex == -1) {
2858 /* Our tests show that Windows returns D3D_OK in this situation, even with
2859 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2860 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2861 * as well for those lights.
2863 * TODO: Test how this affects rendering
2865 FIXME("Too many concurrently active lights\n");
2869 /* i == lightInfo->glIndex */
2870 if(!This->isRecordingState) {
2871 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2879 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2881 PLIGHTINFOEL *lightInfo = NULL;
2882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2884 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2885 TRACE("(%p) : for idx(%d)\n", This, Index);
2887 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2888 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2889 if(lightInfo->OriginalIndex == Index) break;
2893 if (lightInfo == NULL) {
2894 TRACE("Light enabled state requested but light not defined\n");
2895 return WINED3DERR_INVALIDCALL;
2897 /* true is 128 according to SetLightEnable */
2898 *pEnable = lightInfo->enabled ? 128 : 0;
2903 * Get / Set Clip Planes
2905 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2907 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2909 /* Validate Index */
2910 if (Index >= GL_LIMITS(clipplanes)) {
2911 TRACE("Application has requested clipplane this device doesn't support\n");
2912 return WINED3DERR_INVALIDCALL;
2915 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2917 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2918 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2919 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2920 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2921 TRACE("Application is setting old values over, nothing to do\n");
2925 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2926 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2927 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2928 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2930 /* Handle recording of state blocks */
2931 if (This->isRecordingState) {
2932 TRACE("Recording... not performing anything\n");
2936 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2941 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2943 TRACE("(%p) : for idx %d\n", This, Index);
2945 /* Validate Index */
2946 if (Index >= GL_LIMITS(clipplanes)) {
2947 TRACE("Application has requested clipplane this device doesn't support\n");
2948 return WINED3DERR_INVALIDCALL;
2951 pPlane[0] = This->stateBlock->clipplane[Index][0];
2952 pPlane[1] = This->stateBlock->clipplane[Index][1];
2953 pPlane[2] = This->stateBlock->clipplane[Index][2];
2954 pPlane[3] = This->stateBlock->clipplane[Index][3];
2959 * Get / Set Clip Plane Status
2960 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2962 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2964 FIXME("(%p) : stub\n", This);
2965 if (NULL == pClipStatus) {
2966 return WINED3DERR_INVALIDCALL;
2968 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2969 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2973 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2975 FIXME("(%p) : stub\n", This);
2976 if (NULL == pClipStatus) {
2977 return WINED3DERR_INVALIDCALL;
2979 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2980 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2985 * Get / Set Material
2987 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2990 This->updateStateBlock->changed.material = TRUE;
2991 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2993 /* Handle recording of state blocks */
2994 if (This->isRecordingState) {
2995 TRACE("Recording... not performing anything\n");
2999 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3003 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3005 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3006 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3007 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3008 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3009 pMaterial->Ambient.b, pMaterial->Ambient.a);
3010 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3011 pMaterial->Specular.b, pMaterial->Specular.a);
3012 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3013 pMaterial->Emissive.b, pMaterial->Emissive.a);
3014 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3022 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3024 IWineD3DIndexBuffer *oldIdxs;
3026 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3027 oldIdxs = This->updateStateBlock->pIndexData;
3029 This->updateStateBlock->changed.indices = TRUE;
3030 This->updateStateBlock->pIndexData = pIndexData;
3032 /* Handle recording of state blocks */
3033 if (This->isRecordingState) {
3034 TRACE("Recording... not performing anything\n");
3035 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3036 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3040 if(oldIdxs != pIndexData) {
3041 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3042 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3043 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3048 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3051 *ppIndexData = This->stateBlock->pIndexData;
3053 /* up ref count on ppindexdata */
3055 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3056 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3058 TRACE("(%p) No index data set\n", This);
3060 TRACE("Returning %p\n", *ppIndexData);
3065 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3066 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3068 TRACE("(%p)->(%d)\n", This, BaseIndex);
3070 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3071 TRACE("Application is setting the old value over, nothing to do\n");
3075 This->updateStateBlock->baseVertexIndex = BaseIndex;
3077 if (This->isRecordingState) {
3078 TRACE("Recording... not performing anything\n");
3081 /* The base vertex index affects the stream sources */
3082 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3086 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3088 TRACE("(%p) : base_index %p\n", This, base_index);
3090 *base_index = This->stateBlock->baseVertexIndex;
3092 TRACE("Returning %u\n", *base_index);
3098 * Get / Set Viewports
3100 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3103 TRACE("(%p)\n", This);
3104 This->updateStateBlock->changed.viewport = TRUE;
3105 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3107 /* Handle recording of state blocks */
3108 if (This->isRecordingState) {
3109 TRACE("Recording... not performing anything\n");
3113 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3114 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3116 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3121 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3123 TRACE("(%p)\n", This);
3124 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3129 * Get / Set Render States
3130 * TODO: Verify against dx9 definitions
3132 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3135 DWORD oldValue = This->stateBlock->renderState[State];
3137 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3139 This->updateStateBlock->changed.renderState[State] = TRUE;
3140 This->updateStateBlock->renderState[State] = Value;
3142 /* Handle recording of state blocks */
3143 if (This->isRecordingState) {
3144 TRACE("Recording... not performing anything\n");
3148 /* Compared here and not before the assignment to allow proper stateblock recording */
3149 if(Value == oldValue) {
3150 TRACE("Application is setting the old value over, nothing to do\n");
3152 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3158 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3160 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3161 *pValue = This->stateBlock->renderState[State];
3166 * Get / Set Sampler States
3167 * TODO: Verify against dx9 definitions
3170 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3174 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3175 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3177 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3178 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3181 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3182 ERR("Current Sampler overflows sampleState0 array (sampler %d vs size %d)\n", Sampler,
3183 sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])
3185 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3188 * SetSampler is designed to allow for more than the standard up to 8 textures
3189 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3190 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3192 * http://developer.nvidia.com/object/General_FAQ.html#t6
3194 * There are two new settings for GForce
3196 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3197 * and the texture one:
3198 * GL_MAX_TEXTURE_COORDS_ARB.
3199 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3202 oldValue = This->stateBlock->samplerState[Sampler][Type];
3203 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3204 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3206 /* Handle recording of state blocks */
3207 if (This->isRecordingState) {
3208 TRACE("Recording... not performing anything\n");
3212 if(oldValue == Value) {
3213 TRACE("Application is setting the old value over, nothing to do\n");
3217 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3222 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3225 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3226 This, Sampler, debug_d3dsamplerstate(Type), Type);
3228 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3229 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3232 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3233 ERR("Current Sampler overflows sampleState0 array (sampler %d vs size %d)\n", Sampler,
3234 sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])
3236 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3238 *Value = This->stateBlock->samplerState[Sampler][Type];
3239 TRACE("(%p) : Returning %#x\n", This, *Value);
3244 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3247 This->updateStateBlock->changed.scissorRect = TRUE;
3248 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3249 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3252 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3254 if(This->isRecordingState) {
3255 TRACE("Recording... not performing anything\n");
3259 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3264 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3265 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3267 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3268 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3272 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3274 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3276 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3278 This->updateStateBlock->vertexDecl = pDecl;
3279 This->updateStateBlock->changed.vertexDecl = TRUE;
3281 if (This->isRecordingState) {
3282 TRACE("Recording... not performing anything\n");
3284 } else if(pDecl == oldDecl) {
3285 /* Checked after the assignment to allow proper stateblock recording */
3286 TRACE("Application is setting the old declaration over, nothing to do\n");
3290 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3294 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3297 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3299 *ppDecl = This->stateBlock->vertexDecl;
3300 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3304 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3306 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3308 This->updateStateBlock->vertexShader = pShader;
3309 This->updateStateBlock->changed.vertexShader = TRUE;
3311 if (This->isRecordingState) {
3312 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3313 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3314 TRACE("Recording... not performing anything\n");
3316 } else if(oldShader == pShader) {
3317 /* Checked here to allow proper stateblock recording */
3318 TRACE("App is setting the old shader over, nothing to do\n");
3322 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3323 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3324 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3326 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3331 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3334 if (NULL == ppShader) {
3335 return WINED3DERR_INVALIDCALL;
3337 *ppShader = This->stateBlock->vertexShader;
3338 if( NULL != *ppShader)
3339 IWineD3DVertexShader_AddRef(*ppShader);
3341 TRACE("(%p) : returning %p\n", This, *ppShader);
3345 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3346 IWineD3DDevice *iface,
3348 CONST BOOL *srcData,
3351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3352 int i, cnt = min(count, MAX_CONST_B - start);
3354 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3355 iface, srcData, start, count);
3357 if (srcData == NULL || cnt < 0)
3358 return WINED3DERR_INVALIDCALL;
3360 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3361 for (i = 0; i < cnt; i++)
3362 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3364 for (i = start; i < cnt + start; ++i) {
3365 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3368 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3373 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3374 IWineD3DDevice *iface,
3379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3380 int cnt = min(count, MAX_CONST_B - start);
3382 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3383 iface, dstData, start, count);
3385 if (dstData == NULL || cnt < 0)
3386 return WINED3DERR_INVALIDCALL;
3388 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3392 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3393 IWineD3DDevice *iface,
3398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3399 int i, cnt = min(count, MAX_CONST_I - start);
3401 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3402 iface, srcData, start, count);
3404 if (srcData == NULL || cnt < 0)
3405 return WINED3DERR_INVALIDCALL;
3407 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3408 for (i = 0; i < cnt; i++)
3409 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3410 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3412 for (i = start; i < cnt + start; ++i) {
3413 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3416 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3421 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3422 IWineD3DDevice *iface,
3427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3428 int cnt = min(count, MAX_CONST_I - start);
3430 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3431 iface, dstData, start, count);
3433 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3434 return WINED3DERR_INVALIDCALL;
3436 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3440 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3441 IWineD3DDevice *iface,
3443 CONST float *srcData,
3446 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3449 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3450 iface, srcData, start, count);
3452 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3453 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3454 return WINED3DERR_INVALIDCALL;
3456 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3458 for (i = 0; i < count; i++)
3459 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3460 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3463 for (i = start; i < count + start; ++i) {
3464 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3465 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3466 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3467 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3468 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3470 ptr->idx[ptr->count++] = i;
3471 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3475 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3480 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3481 IWineD3DDevice *iface,
3486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3487 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3489 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3490 iface, dstData, start, count);
3492 if (dstData == NULL || cnt < 0)
3493 return WINED3DERR_INVALIDCALL;
3495 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3499 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3501 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3502 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3506 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3507 int i = This->rev_tex_unit_map[unit];
3508 int j = This->texUnitMap[stage];
3510 This->texUnitMap[stage] = unit;
3511 if (i != -1 && i != stage) {
3512 This->texUnitMap[i] = -1;
3515 This->rev_tex_unit_map[unit] = stage;
3516 if (j != -1 && j != unit) {
3517 This->rev_tex_unit_map[j] = -1;
3521 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3524 for (i = 0; i < MAX_TEXTURES; ++i) {
3525 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3526 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3527 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3528 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3529 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3530 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3531 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3532 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3534 if (color_op == WINED3DTOP_DISABLE) {
3535 /* Not used, and disable higher stages */
3536 while (i < MAX_TEXTURES) {
3537 This->fixed_function_usage_map[i] = FALSE;
3543 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3544 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3545 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3546 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3547 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3548 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3549 This->fixed_function_usage_map[i] = TRUE;
3551 This->fixed_function_usage_map[i] = FALSE;
3554 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3555 This->fixed_function_usage_map[i+1] = TRUE;
3560 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3563 device_update_fixed_function_usage_map(This);
3565 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3566 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3567 if (!This->fixed_function_usage_map[i]) continue;
3569 if (This->texUnitMap[i] != i) {
3570 device_map_stage(This, i, i);
3571 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3572 markTextureStagesDirty(This, i);
3578 /* Now work out the mapping */
3580 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3581 if (!This->fixed_function_usage_map[i]) continue;
3583 if (This->texUnitMap[i] != tex) {
3584 device_map_stage(This, i, tex);
3585 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3586 markTextureStagesDirty(This, i);
3593 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3594 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3597 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3598 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3599 device_map_stage(This, i, i);
3600 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3601 if (i < MAX_TEXTURES) {
3602 markTextureStagesDirty(This, i);
3608 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3609 int current_mapping = This->rev_tex_unit_map[unit];
3611 if (current_mapping == -1) {
3612 /* Not currently used */
3616 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3617 /* Used by a fragment sampler */
3619 if (!pshader_sampler_tokens) {
3620 /* No pixel shader, check fixed function */
3621 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3624 /* Pixel shader, check the shader's sampler map */
3625 return !pshader_sampler_tokens[current_mapping];
3628 /* Used by a vertex sampler */
3629 return !vshader_sampler_tokens[current_mapping];
3632 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3633 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3634 DWORD *pshader_sampler_tokens = NULL;
3635 int start = GL_LIMITS(combined_samplers) - 1;
3639 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3641 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3642 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3643 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3646 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3647 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3648 if (vshader_sampler_tokens[i]) {
3649 if (This->texUnitMap[vsampler_idx] != -1) {
3650 /* Already mapped somewhere */
3654 while (start >= 0) {
3655 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3656 device_map_stage(This, vsampler_idx, start);
3657 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3669 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3670 BOOL vs = use_vs(This);
3671 BOOL ps = use_ps(This);
3674 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3675 * that would be really messy and require shader recompilation
3676 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3677 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3680 device_map_psamplers(This);
3682 device_map_fixed_function_samplers(This);
3686 device_map_vsamplers(This, ps);
3690 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3692 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3693 This->updateStateBlock->pixelShader = pShader;
3694 This->updateStateBlock->changed.pixelShader = TRUE;
3696 /* Handle recording of state blocks */
3697 if (This->isRecordingState) {
3698 TRACE("Recording... not performing anything\n");
3701 if (This->isRecordingState) {
3702 TRACE("Recording... not performing anything\n");
3703 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3704 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3708 if(pShader == oldShader) {
3709 TRACE("App is setting the old pixel shader over, nothing to do\n");
3713 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3714 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3716 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3722 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3725 if (NULL == ppShader) {
3726 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3727 return WINED3DERR_INVALIDCALL;
3730 *ppShader = This->stateBlock->pixelShader;
3731 if (NULL != *ppShader) {
3732 IWineD3DPixelShader_AddRef(*ppShader);
3734 TRACE("(%p) : returning %p\n", This, *ppShader);
3738 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3739 IWineD3DDevice *iface,
3741 CONST BOOL *srcData,
3744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3745 int i, cnt = min(count, MAX_CONST_B - start);
3747 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3748 iface, srcData, start, count);
3750 if (srcData == NULL || cnt < 0)
3751 return WINED3DERR_INVALIDCALL;
3753 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3754 for (i = 0; i < cnt; i++)
3755 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3757 for (i = start; i < cnt + start; ++i) {
3758 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3761 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3766 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3767 IWineD3DDevice *iface,
3772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3773 int cnt = min(count, MAX_CONST_B - start);
3775 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3776 iface, dstData, start, count);
3778 if (dstData == NULL || cnt < 0)
3779 return WINED3DERR_INVALIDCALL;
3781 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3785 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3786 IWineD3DDevice *iface,
3791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3792 int i, cnt = min(count, MAX_CONST_I - start);
3794 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3795 iface, srcData, start, count);
3797 if (srcData == NULL || cnt < 0)
3798 return WINED3DERR_INVALIDCALL;
3800 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3801 for (i = 0; i < cnt; i++)
3802 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3803 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3805 for (i = start; i < cnt + start; ++i) {
3806 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3809 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3814 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3815 IWineD3DDevice *iface,
3820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3821 int cnt = min(count, MAX_CONST_I - start);
3823 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3824 iface, dstData, start, count);
3826 if (dstData == NULL || cnt < 0)
3827 return WINED3DERR_INVALIDCALL;
3829 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3833 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3834 IWineD3DDevice *iface,
3836 CONST float *srcData,
3839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3842 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3843 iface, srcData, start, count);
3845 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3846 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3847 return WINED3DERR_INVALIDCALL;
3849 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3851 for (i = 0; i < count; i++)
3852 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3853 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3856 for (i = start; i < count + start; ++i) {
3857 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3858 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3859 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3860 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3861 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3863 ptr->idx[ptr->count++] = i;
3864 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3868 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3873 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3874 IWineD3DDevice *iface,
3879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3880 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3882 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3883 iface, dstData, start, count);
3885 if (dstData == NULL || cnt < 0)
3886 return WINED3DERR_INVALIDCALL;
3888 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3892 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3894 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3895 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3897 DWORD DestFVF = dest->fvf;
3899 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3903 if (lpStrideData->u.s.normal.lpData) {
3904 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3907 if (lpStrideData->u.s.position.lpData == NULL) {
3908 ERR("Source has no position mask\n");
3909 return WINED3DERR_INVALIDCALL;
3912 /* We might access VBOs from this code, so hold the lock */
3915 if (dest->resource.allocatedMemory == NULL) {
3916 /* This may happen if we do direct locking into a vbo. Unlikely,
3917 * but theoretically possible(ddraw processvertices test)
3919 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3920 if(!dest->resource.allocatedMemory) {
3922 ERR("Out of memory\n");
3923 return E_OUTOFMEMORY;
3927 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3928 checkGLcall("glBindBufferARB");
3929 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3931 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3933 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3934 checkGLcall("glUnmapBufferARB");
3938 /* Get a pointer into the destination vbo(create one if none exists) and
3939 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3941 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3946 unsigned char extrabytes = 0;
3947 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3948 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3949 * this may write 4 extra bytes beyond the area that should be written
3951 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3952 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3953 if(!dest_conv_addr) {
3954 ERR("Out of memory\n");
3955 /* Continue without storing converted vertices */
3957 dest_conv = dest_conv_addr;
3961 * a) WINED3DRS_CLIPPING is enabled
3962 * b) WINED3DVOP_CLIP is passed
3964 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3965 static BOOL warned = FALSE;
3967 * The clipping code is not quite correct. Some things need
3968 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3969 * so disable clipping for now.
3970 * (The graphics in Half-Life are broken, and my processvertices
3971 * test crashes with IDirect3DDevice3)
3977 FIXME("Clipping is broken and disabled for now\n");
3979 } else doClip = FALSE;
3980 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3982 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3985 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3986 WINED3DTS_PROJECTION,
3988 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3989 WINED3DTS_WORLDMATRIX(0),
3992 TRACE("View mat:\n");
3993 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);
3994 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);
3995 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);
3996 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);
3998 TRACE("Proj mat:\n");
3999 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);
4000 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);
4001 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);
4002 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);
4004 TRACE("World mat:\n");
4005 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);
4006 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);
4007 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);
4008 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);
4010 /* Get the viewport */
4011 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4012 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4013 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4015 multiply_matrix(&mat,&view_mat,&world_mat);
4016 multiply_matrix(&mat,&proj_mat,&mat);
4018 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4020 for (i = 0; i < dwCount; i+= 1) {
4021 unsigned int tex_index;
4023 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4024 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4025 /* The position first */
4027 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4029 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4031 /* Multiplication with world, view and projection matrix */
4032 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);
4033 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);
4034 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);
4035 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);
4037 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4039 /* WARNING: The following things are taken from d3d7 and were not yet checked
4040 * against d3d8 or d3d9!
4043 /* Clipping conditions: From
4044 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
4046 * A vertex is clipped if it does not match the following requirements
4050 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4052 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4053 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4058 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4059 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4062 /* "Normal" viewport transformation (not clipped)
4063 * 1) The values are divided by rhw
4064 * 2) The y axis is negative, so multiply it with -1
4065 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4066 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4067 * 4) Multiply x with Width/2 and add Width/2
4068 * 5) The same for the height
4069 * 6) Add the viewpoint X and Y to the 2D coordinates and
4070 * The minimum Z value to z
4071 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4073 * Well, basically it's simply a linear transformation into viewport
4085 z *= vp.MaxZ - vp.MinZ;
4087 x += vp.Width / 2 + vp.X;
4088 y += vp.Height / 2 + vp.Y;
4093 /* That vertex got clipped
4094 * Contrary to OpenGL it is not dropped completely, it just
4095 * undergoes a different calculation.
4097 TRACE("Vertex got clipped\n");
4104 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4105 * outside of the main vertex buffer memory. That needs some more
4110 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4113 ( (float *) dest_ptr)[0] = x;
4114 ( (float *) dest_ptr)[1] = y;
4115 ( (float *) dest_ptr)[2] = z;
4116 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4118 dest_ptr += 3 * sizeof(float);
4120 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4121 dest_ptr += sizeof(float);
4126 ( (float *) dest_conv)[0] = x * w;
4127 ( (float *) dest_conv)[1] = y * w;
4128 ( (float *) dest_conv)[2] = z * w;
4129 ( (float *) dest_conv)[3] = w;
4131 dest_conv += 3 * sizeof(float);
4133 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4134 dest_conv += sizeof(float);
4138 if (DestFVF & WINED3DFVF_PSIZE) {
4139 dest_ptr += sizeof(DWORD);
4140 if(dest_conv) dest_conv += sizeof(DWORD);
4142 if (DestFVF & WINED3DFVF_NORMAL) {
4144 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4145 /* AFAIK this should go into the lighting information */
4146 FIXME("Didn't expect the destination to have a normal\n");
4147 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4149 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4153 if (DestFVF & WINED3DFVF_DIFFUSE) {
4155 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4157 static BOOL warned = FALSE;
4160 ERR("No diffuse color in source, but destination has one\n");
4164 *( (DWORD *) dest_ptr) = 0xffffffff;
4165 dest_ptr += sizeof(DWORD);
4168 *( (DWORD *) dest_conv) = 0xffffffff;
4169 dest_conv += sizeof(DWORD);
4173 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4175 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4176 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4177 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4178 dest_conv += sizeof(DWORD);
4183 if (DestFVF & WINED3DFVF_SPECULAR) {
4184 /* What's the color value in the feedback buffer? */
4186 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4188 static BOOL warned = FALSE;
4191 ERR("No specular color in source, but destination has one\n");
4195 *( (DWORD *) dest_ptr) = 0xFF000000;
4196 dest_ptr += sizeof(DWORD);
4199 *( (DWORD *) dest_conv) = 0xFF000000;
4200 dest_conv += sizeof(DWORD);
4204 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4206 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4207 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4208 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4209 dest_conv += sizeof(DWORD);
4214 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4216 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4217 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4219 ERR("No source texture, but destination requests one\n");
4220 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4221 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4224 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4226 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4233 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4234 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4235 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4236 dwCount * get_flexible_vertex_size(DestFVF),
4238 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4239 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4246 #undef copy_and_next
4248 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4250 WineDirect3DVertexStridedData strided;
4251 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4252 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4255 ERR("Output vertex declaration not implemented yet\n");
4258 /* Need any context to write to the vbo. */
4259 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4261 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4262 * control the streamIsUP flag, thus restore it afterwards.
4264 This->stateBlock->streamIsUP = FALSE;
4265 memset(&strided, 0, sizeof(strided));
4266 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4267 This->stateBlock->streamIsUP = streamWasUP;
4269 if(vbo || SrcStartIndex) {
4271 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4272 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4274 * Also get the start index in, but only loop over all elements if there's something to add at all.
4276 #define FIXSRC(type) \
4277 if(strided.u.s.type.VBO) { \
4278 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4279 strided.u.s.type.VBO = 0; \
4280 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4282 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4286 if(strided.u.s.type.lpData) { \
4287 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4290 FIXSRC(blendWeights);
4291 FIXSRC(blendMatrixIndices);
4296 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4297 FIXSRC(texCoords[i]);
4310 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4314 * Get / Set Texture Stage States
4315 * TODO: Verify against dx9 definitions
4317 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4319 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4321 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4323 if (Stage >= MAX_TEXTURES) {
4324 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4328 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4329 This->updateStateBlock->textureState[Stage][Type] = Value;
4331 if (This->isRecordingState) {
4332 TRACE("Recording... not performing anything\n");
4336 /* Checked after the assignments to allow proper stateblock recording */
4337 if(oldValue == Value) {
4338 TRACE("App is setting the old value over, nothing to do\n");
4342 if(Stage > This->stateBlock->lowest_disabled_stage &&
4343 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4344 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4345 * Changes in other states are important on disabled stages too
4350 if(Type == WINED3DTSS_COLOROP) {
4353 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4354 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4355 * they have to be disabled
4357 * The current stage is dirtified below.
4359 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4360 TRACE("Additionally dirtifying stage %d\n", i);
4361 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4363 This->stateBlock->lowest_disabled_stage = Stage;
4364 TRACE("New lowest disabled: %d\n", Stage);
4365 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4366 /* Previously disabled stage enabled. Stages above it may need enabling
4367 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4368 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4370 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4373 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4374 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4377 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4380 This->stateBlock->lowest_disabled_stage = i;
4381 TRACE("New lowest disabled: %d\n", i);
4383 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4384 /* TODO: Built a stage -> texture unit mapping for register combiners */
4388 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4393 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4395 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4396 *pValue = This->updateStateBlock->textureState[Stage][Type];
4403 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4405 IWineD3DBaseTexture *oldTexture;
4407 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4409 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4410 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4413 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4414 ERR("Current stage overflows textures array (stage %d vs size %d)\n", Stage,
4415 sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])
4417 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4420 oldTexture = This->updateStateBlock->textures[Stage];
4422 if(pTexture != NULL) {
4423 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4425 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4426 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4427 return WINED3DERR_INVALIDCALL;
4429 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4432 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4433 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4435 This->updateStateBlock->changed.textures[Stage] = TRUE;
4436 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4437 This->updateStateBlock->textures[Stage] = pTexture;
4439 /* Handle recording of state blocks */
4440 if (This->isRecordingState) {
4441 TRACE("Recording... not performing anything\n");
4445 if(oldTexture == pTexture) {
4446 TRACE("App is setting the same texture again, nothing to do\n");
4450 /** NOTE: MSDN says that setTexture increases the reference count,
4451 * and that the application must set the texture back to null (or have a leaky application),
4452 * This means we should pass the refcount up to the parent
4453 *******************************/
4454 if (NULL != This->updateStateBlock->textures[Stage]) {
4455 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4456 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4458 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4459 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4460 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4461 * so the COLOROP and ALPHAOP have to be dirtified.
4463 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4464 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4466 if(bindCount == 1) {
4467 new->baseTexture.sampler = Stage;
4469 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4473 if (NULL != oldTexture) {
4474 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4475 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4477 IWineD3DBaseTexture_Release(oldTexture);
4478 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4479 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4480 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4483 if(bindCount && old->baseTexture.sampler == Stage) {
4485 /* Have to do a search for the other sampler(s) where the texture is bound to
4486 * Shouldn't happen as long as apps bind a texture only to one stage
4488 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4489 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4490 if(This->updateStateBlock->textures[i] == oldTexture) {
4491 old->baseTexture.sampler = i;
4498 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4503 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4506 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4508 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4509 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4512 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4513 ERR("Current stage overflows textures array (stage %d vs size %d)\n", Stage,
4514 sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])
4516 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4519 *ppTexture=This->stateBlock->textures[Stage];
4521 IWineD3DBaseTexture_AddRef(*ppTexture);
4523 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4531 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4532 IWineD3DSurface **ppBackBuffer) {
4533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4534 IWineD3DSwapChain *swapChain;
4537 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4539 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4540 if (hr == WINED3D_OK) {
4541 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4542 IWineD3DSwapChain_Release(swapChain);
4544 *ppBackBuffer = NULL;
4549 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4551 WARN("(%p) : stub, calling idirect3d for now\n", This);
4552 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4555 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4557 IWineD3DSwapChain *swapChain;
4560 if(iSwapChain > 0) {
4561 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4562 if (hr == WINED3D_OK) {
4563 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4564 IWineD3DSwapChain_Release(swapChain);
4566 FIXME("(%p) Error getting display mode\n", This);
4569 /* Don't read the real display mode,
4570 but return the stored mode instead. X11 can't change the color
4571 depth, and some apps are pretty angry if they SetDisplayMode from
4572 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4574 Also don't relay to the swapchain because with ddraw it's possible
4575 that there isn't a swapchain at all */
4576 pMode->Width = This->ddraw_width;
4577 pMode->Height = This->ddraw_height;
4578 pMode->Format = This->ddraw_format;
4579 pMode->RefreshRate = 0;
4586 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4588 TRACE("(%p)->(%p)\n", This, hWnd);
4590 if(This->ddraw_fullscreen) {
4591 if(This->ddraw_window && This->ddraw_window != hWnd) {
4592 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4594 if(hWnd && This->ddraw_window != hWnd) {
4595 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4599 This->ddraw_window = hWnd;
4603 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4605 TRACE("(%p)->(%p)\n", This, hWnd);
4607 *hWnd = This->ddraw_window;
4612 * Stateblock related functions
4615 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4617 IWineD3DStateBlockImpl *object;
4618 HRESULT temp_result;
4621 TRACE("(%p)\n", This);
4623 if (This->isRecordingState) {
4624 return WINED3DERR_INVALIDCALL;
4627 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4628 if (NULL == object ) {
4629 FIXME("(%p)Error allocating memory for stateblock\n", This);
4630 return E_OUTOFMEMORY;
4632 TRACE("(%p) created object %p\n", This, object);
4633 object->wineD3DDevice= This;
4634 /** FIXME: object->parent = parent; **/
4635 object->parent = NULL;
4636 object->blockType = WINED3DSBT_RECORDED;
4638 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4640 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4641 list_init(&object->lightMap[i]);
4644 temp_result = allocate_shader_constants(object);
4645 if (WINED3D_OK != temp_result)
4648 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4649 This->updateStateBlock = object;
4650 This->isRecordingState = TRUE;
4652 TRACE("(%p) recording stateblock %p\n",This , object);
4656 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4659 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4661 if (!This->isRecordingState) {
4662 FIXME("(%p) not recording! returning error\n", This);
4663 *ppStateBlock = NULL;
4664 return WINED3DERR_INVALIDCALL;
4667 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4668 if(object->changed.renderState[i]) {
4669 object->contained_render_states[object->num_contained_render_states] = i;
4670 object->num_contained_render_states++;
4673 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4674 if(object->changed.transform[i]) {
4675 object->contained_transform_states[object->num_contained_transform_states] = i;
4676 object->num_contained_transform_states++;
4679 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4680 if(object->changed.vertexShaderConstantsF[i]) {
4681 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4682 object->num_contained_vs_consts_f++;
4685 for(i = 0; i < MAX_CONST_I; i++) {
4686 if(object->changed.vertexShaderConstantsI[i]) {
4687 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4688 object->num_contained_vs_consts_i++;
4691 for(i = 0; i < MAX_CONST_B; i++) {
4692 if(object->changed.vertexShaderConstantsB[i]) {
4693 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4694 object->num_contained_vs_consts_b++;
4697 for(i = 0; i < MAX_CONST_I; i++) {
4698 if(object->changed.pixelShaderConstantsI[i]) {
4699 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4700 object->num_contained_ps_consts_i++;
4703 for(i = 0; i < MAX_CONST_B; i++) {
4704 if(object->changed.pixelShaderConstantsB[i]) {
4705 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4706 object->num_contained_ps_consts_b++;
4709 for(i = 0; i < MAX_TEXTURES; i++) {
4710 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4711 if(object->changed.textureState[i][j]) {
4712 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4713 object->contained_tss_states[object->num_contained_tss_states].state = j;
4714 object->num_contained_tss_states++;
4718 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4719 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4720 if(object->changed.samplerState[i][j]) {
4721 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4722 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4723 object->num_contained_sampler_states++;
4728 *ppStateBlock = (IWineD3DStateBlock*) object;
4729 This->isRecordingState = FALSE;
4730 This->updateStateBlock = This->stateBlock;
4731 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4732 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4733 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4738 * Scene related functions
4740 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4741 /* At the moment we have no need for any functionality at the beginning
4743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4744 TRACE("(%p)\n", This);
4747 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4748 return WINED3DERR_INVALIDCALL;
4750 This->inScene = TRUE;
4754 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4756 TRACE("(%p)\n", This);
4758 if(!This->inScene) {
4759 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4760 return WINED3DERR_INVALIDCALL;
4763 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4764 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4767 checkGLcall("glFlush");
4770 This->inScene = FALSE;
4774 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4775 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4776 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4778 IWineD3DSwapChain *swapChain = NULL;
4780 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4782 TRACE("(%p) Presenting the frame\n", This);
4784 for(i = 0 ; i < swapchains ; i ++) {
4786 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4787 TRACE("presentinng chain %d, %p\n", i, swapChain);
4788 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4789 IWineD3DSwapChain_Release(swapChain);
4795 /* Not called from the VTable (internal subroutine) */
4796 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4797 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4798 float Z, DWORD Stencil) {
4799 GLbitfield glMask = 0;
4801 WINED3DRECT curRect;
4803 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4804 UINT drawable_width, drawable_height;
4806 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4807 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4808 * for the cleared parts, and the untouched parts.
4810 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4811 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4812 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4813 * checking all this if the dest surface is in the drawable anyway.
4815 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4817 if(vp->X != 0 || vp->Y != 0 ||
4818 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4819 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4822 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4823 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4824 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4825 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4826 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4829 if(Count > 0 && pRects && (
4830 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4831 pRects[0].x2 < target->currentDesc.Width ||
4832 pRects[0].y2 < target->currentDesc.Height)) {
4833 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4840 target->get_drawable_size(target, &drawable_width, &drawable_height);
4842 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4845 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4846 apply_fbo_state((IWineD3DDevice *) This);
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;
4957 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4958 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4960 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4962 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4963 Count, pRects, Flags, Color, Z, Stencil);
4965 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4966 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4967 /* TODO: What about depth stencil buffers without stencil bits? */
4968 return WINED3DERR_INVALIDCALL;
4971 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4977 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4978 UINT PrimitiveCount) {
4980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4982 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4983 debug_d3dprimitivetype(PrimitiveType),
4984 StartVertex, PrimitiveCount);
4986 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4987 if(This->stateBlock->streamIsUP) {
4988 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4989 This->stateBlock->streamIsUP = FALSE;
4992 if(This->stateBlock->loadBaseVertexIndex != 0) {
4993 This->stateBlock->loadBaseVertexIndex = 0;
4994 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4996 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4997 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4998 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5002 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5003 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5004 WINED3DPRIMITIVETYPE PrimitiveType,
5005 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5009 IWineD3DIndexBuffer *pIB;
5010 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5013 pIB = This->stateBlock->pIndexData;
5015 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5016 * without an index buffer set. (The first time at least...)
5017 * D3D8 simply dies, but I doubt it can do much harm to return
5018 * D3DERR_INVALIDCALL there as well. */
5019 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5020 return WINED3DERR_INVALIDCALL;
5023 if(This->stateBlock->streamIsUP) {
5024 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5025 This->stateBlock->streamIsUP = FALSE;
5027 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5029 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5030 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5031 minIndex, NumVertices, startIndex, primCount);
5033 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5034 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5040 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5041 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5042 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5045 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5046 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5051 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5052 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5053 UINT VertexStreamZeroStride) {
5054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5055 IWineD3DVertexBuffer *vb;
5057 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5058 debug_d3dprimitivetype(PrimitiveType),
5059 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5061 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5062 vb = This->stateBlock->streamSource[0];
5063 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5064 if(vb) IWineD3DVertexBuffer_Release(vb);
5065 This->stateBlock->streamOffset[0] = 0;
5066 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5067 This->stateBlock->streamIsUP = TRUE;
5068 This->stateBlock->loadBaseVertexIndex = 0;
5070 /* TODO: Only mark dirty if drawing from a different UP address */
5071 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5073 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5074 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5076 /* MSDN specifies stream zero settings must be set to NULL */
5077 This->stateBlock->streamStride[0] = 0;
5078 This->stateBlock->streamSource[0] = NULL;
5080 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5081 * the new stream sources or use UP drawing again
5086 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5087 UINT MinVertexIndex, UINT NumVertices,
5088 UINT PrimitiveCount, CONST void* pIndexData,
5089 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5090 UINT VertexStreamZeroStride) {
5092 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5093 IWineD3DVertexBuffer *vb;
5094 IWineD3DIndexBuffer *ib;
5096 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5097 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5098 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5099 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5101 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5107 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5108 vb = This->stateBlock->streamSource[0];
5109 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5110 if(vb) IWineD3DVertexBuffer_Release(vb);
5111 This->stateBlock->streamIsUP = TRUE;
5112 This->stateBlock->streamOffset[0] = 0;
5113 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5115 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5116 This->stateBlock->baseVertexIndex = 0;
5117 This->stateBlock->loadBaseVertexIndex = 0;
5118 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5119 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5120 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5122 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5124 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5125 This->stateBlock->streamSource[0] = NULL;
5126 This->stateBlock->streamStride[0] = 0;
5127 ib = This->stateBlock->pIndexData;
5129 IWineD3DIndexBuffer_Release(ib);
5130 This->stateBlock->pIndexData = NULL;
5132 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5133 * SetStreamSource to specify a vertex buffer
5139 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
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->baseVertexIndex = 0;
5149 This->up_strided = DrawPrimStrideData;
5150 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5151 This->up_strided = NULL;
5155 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5157 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5159 /* Mark the state dirty until we have nicer tracking
5160 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5163 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5164 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5165 This->stateBlock->streamIsUP = TRUE;
5166 This->stateBlock->baseVertexIndex = 0;
5167 This->up_strided = DrawPrimStrideData;
5168 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5169 This->up_strided = NULL;
5173 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5174 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5175 * not callable by the app directly no parameter validation checks are needed here.
5177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5178 WINED3DLOCKED_BOX src;
5179 WINED3DLOCKED_BOX dst;
5181 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5183 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5184 * dirtification to improve loading performance.
5186 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5187 if(FAILED(hr)) return hr;
5188 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5190 IWineD3DVolume_UnlockBox(pSourceVolume);
5194 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5196 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5198 IWineD3DVolume_UnlockBox(pSourceVolume);
5200 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5205 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5206 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5208 HRESULT hr = WINED3D_OK;
5209 WINED3DRESOURCETYPE sourceType;
5210 WINED3DRESOURCETYPE destinationType;
5213 /* TODO: think about moving the code into IWineD3DBaseTexture */
5215 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5217 /* verify that the source and destination textures aren't NULL */
5218 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5219 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5220 This, pSourceTexture, pDestinationTexture);
5221 hr = WINED3DERR_INVALIDCALL;
5224 if (pSourceTexture == pDestinationTexture) {
5225 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5226 This, pSourceTexture, pDestinationTexture);
5227 hr = WINED3DERR_INVALIDCALL;
5229 /* Verify that the source and destination textures are the same type */
5230 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5231 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5233 if (sourceType != destinationType) {
5234 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5236 hr = WINED3DERR_INVALIDCALL;
5239 /* check that both textures have the identical numbers of levels */
5240 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5241 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5242 hr = WINED3DERR_INVALIDCALL;
5245 if (WINED3D_OK == hr) {
5247 /* Make sure that the destination texture is loaded */
5248 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5250 /* Update every surface level of the texture */
5251 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5253 switch (sourceType) {
5254 case WINED3DRTYPE_TEXTURE:
5256 IWineD3DSurface *srcSurface;
5257 IWineD3DSurface *destSurface;
5259 for (i = 0 ; i < levels ; ++i) {
5260 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5261 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5262 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5263 IWineD3DSurface_Release(srcSurface);
5264 IWineD3DSurface_Release(destSurface);
5265 if (WINED3D_OK != hr) {
5266 WARN("(%p) : Call to update surface failed\n", This);
5272 case WINED3DRTYPE_CUBETEXTURE:
5274 IWineD3DSurface *srcSurface;
5275 IWineD3DSurface *destSurface;
5276 WINED3DCUBEMAP_FACES faceType;
5278 for (i = 0 ; i < levels ; ++i) {
5279 /* Update each cube face */
5280 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5281 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5282 if (WINED3D_OK != hr) {
5283 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5285 TRACE("Got srcSurface %p\n", srcSurface);
5287 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5288 if (WINED3D_OK != hr) {
5289 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5291 TRACE("Got desrSurface %p\n", destSurface);
5293 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5294 IWineD3DSurface_Release(srcSurface);
5295 IWineD3DSurface_Release(destSurface);
5296 if (WINED3D_OK != hr) {
5297 WARN("(%p) : Call to update surface failed\n", This);
5305 case WINED3DRTYPE_VOLUMETEXTURE:
5307 IWineD3DVolume *srcVolume = NULL;
5308 IWineD3DVolume *destVolume = NULL;
5310 for (i = 0 ; i < levels ; ++i) {
5311 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5312 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5313 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5314 IWineD3DVolume_Release(srcVolume);
5315 IWineD3DVolume_Release(destVolume);
5316 if (WINED3D_OK != hr) {
5317 WARN("(%p) : Call to update volume failed\n", This);
5325 FIXME("(%p) : Unsupported source and destination type\n", This);
5326 hr = WINED3DERR_INVALIDCALL;
5333 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5334 IWineD3DSwapChain *swapChain;
5336 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5337 if(hr == WINED3D_OK) {
5338 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5339 IWineD3DSwapChain_Release(swapChain);
5344 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5346 /* return a sensible default */
5348 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5349 FIXME("(%p) : stub\n", This);
5353 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5356 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5357 if (PaletteNumber >= MAX_PALETTES) {
5358 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5359 return WINED3DERR_INVALIDCALL;
5361 for (j = 0; j < 256; ++j) {
5362 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5363 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5364 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5365 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5367 TRACE("(%p) : returning\n", This);
5371 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5374 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5375 if (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 for (j = 0; j < 256; ++j) {
5380 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5381 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5382 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5383 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5385 TRACE("(%p) : returning\n", This);
5389 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5391 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5392 if (PaletteNumber >= MAX_PALETTES) {
5393 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5394 return WINED3DERR_INVALIDCALL;
5396 /*TODO: stateblocks */
5397 This->currentPalette = PaletteNumber;
5398 TRACE("(%p) : returning\n", This);
5402 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5404 if (PaletteNumber == NULL) {
5405 WARN("(%p) : returning Invalid Call\n", This);
5406 return WINED3DERR_INVALIDCALL;
5408 /*TODO: stateblocks */
5409 *PaletteNumber = This->currentPalette;
5410 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5414 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5416 static BOOL showFixmes = TRUE;
5418 FIXME("(%p) : stub\n", This);
5422 This->softwareVertexProcessing = bSoftware;
5427 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5429 static BOOL showFixmes = TRUE;
5431 FIXME("(%p) : stub\n", This);
5434 return This->softwareVertexProcessing;
5438 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5440 IWineD3DSwapChain *swapChain;
5443 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5445 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5446 if(hr == WINED3D_OK){
5447 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5448 IWineD3DSwapChain_Release(swapChain);
5450 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5456 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5458 static BOOL showfixmes = TRUE;
5459 if(nSegments != 0.0f) {
5461 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5468 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5470 static BOOL showfixmes = TRUE;
5472 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5478 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5480 /** TODO: remove casts to IWineD3DSurfaceImpl
5481 * NOTE: move code to surface to accomplish this
5482 ****************************************/
5483 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5484 int srcWidth, srcHeight;
5485 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5486 WINED3DFORMAT destFormat, srcFormat;
5488 int srcLeft, destLeft, destTop;
5489 WINED3DPOOL srcPool, destPool;
5491 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5492 glDescriptor *glDescription = NULL;
5495 CONVERT_TYPES convert = NO_CONVERSION;
5497 WINED3DSURFACE_DESC winedesc;
5499 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5500 memset(&winedesc, 0, sizeof(winedesc));
5501 winedesc.Width = &srcSurfaceWidth;
5502 winedesc.Height = &srcSurfaceHeight;
5503 winedesc.Pool = &srcPool;
5504 winedesc.Format = &srcFormat;
5506 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5508 winedesc.Width = &destSurfaceWidth;
5509 winedesc.Height = &destSurfaceHeight;
5510 winedesc.Pool = &destPool;
5511 winedesc.Format = &destFormat;
5512 winedesc.Size = &destSize;
5514 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5516 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5517 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5518 return WINED3DERR_INVALIDCALL;
5521 /* This call loads the opengl surface directly, instead of copying the surface to the
5522 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5523 * copy in sysmem and use regular surface loading.
5525 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5526 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5527 if(convert != NO_CONVERSION) {
5528 return IWineD3DSurface_BltFast(pDestinationSurface,
5529 pDestPoint ? pDestPoint->x : 0,
5530 pDestPoint ? pDestPoint->y : 0,
5531 pSourceSurface, (RECT *) pSourceRect, 0);
5534 if (destFormat == WINED3DFMT_UNKNOWN) {
5535 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5536 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5538 /* Get the update surface description */
5539 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5542 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5546 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5547 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5548 checkGLcall("glActiveTextureARB");
5551 /* Make sure the surface is loaded and up to date */
5552 IWineD3DSurface_PreLoad(pDestinationSurface);
5554 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5556 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5557 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5558 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5559 srcLeft = pSourceRect ? pSourceRect->left : 0;
5560 destLeft = pDestPoint ? pDestPoint->x : 0;
5561 destTop = pDestPoint ? pDestPoint->y : 0;
5564 /* This function doesn't support compressed textures
5565 the pitch is just bytesPerPixel * width */
5566 if(srcWidth != srcSurfaceWidth || srcLeft ){
5567 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5568 offset += srcLeft * pSrcSurface->bytesPerPixel;
5569 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5571 /* TODO DXT formats */
5573 if(pSourceRect != NULL && pSourceRect->top != 0){
5574 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5576 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5578 ,glDescription->level
5583 ,glDescription->glFormat
5584 ,glDescription->glType
5585 ,IWineD3DSurface_GetData(pSourceSurface)
5589 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5591 /* need to lock the surface to get the data */
5592 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5595 /* TODO: Cube and volume support */
5597 /* not a whole row so we have to do it a line at a time */
5600 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5601 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5603 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5605 glTexSubImage2D(glDescription->target
5606 ,glDescription->level
5611 ,glDescription->glFormat
5612 ,glDescription->glType
5613 ,data /* could be quicker using */
5618 } else { /* Full width, so just write out the whole texture */
5620 if (WINED3DFMT_DXT1 == destFormat ||
5621 WINED3DFMT_DXT2 == destFormat ||
5622 WINED3DFMT_DXT3 == destFormat ||
5623 WINED3DFMT_DXT4 == destFormat ||
5624 WINED3DFMT_DXT5 == destFormat) {
5625 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5626 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5627 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5628 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5629 } if (destFormat != srcFormat) {
5630 FIXME("Updating mixed format compressed texture is not curretly support\n");
5632 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5633 glDescription->level,
5634 glDescription->glFormatInternal,
5639 IWineD3DSurface_GetData(pSourceSurface));
5642 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5647 glTexSubImage2D(glDescription->target
5648 ,glDescription->level
5653 ,glDescription->glFormat
5654 ,glDescription->glType
5655 ,IWineD3DSurface_GetData(pSourceSurface)
5659 checkGLcall("glTexSubImage2D");
5663 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5664 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5669 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5670 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5671 struct WineD3DRectPatch *patch;
5675 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5677 if(!(Handle || pRectPatchInfo)) {
5678 /* TODO: Write a test for the return value, thus the FIXME */
5679 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5680 return WINED3DERR_INVALIDCALL;
5684 i = PATCHMAP_HASHFUNC(Handle);
5686 LIST_FOR_EACH(e, &This->patches[i]) {
5687 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5688 if(patch->Handle == Handle) {
5695 TRACE("Patch does not exist. Creating a new one\n");
5696 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5697 patch->Handle = Handle;
5698 list_add_head(&This->patches[i], &patch->entry);
5700 TRACE("Found existing patch %p\n", patch);
5703 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5704 * attributes we have to tesselate, read back, and draw. This needs a patch
5705 * management structure instance. Create one.
5707 * A possible improvement is to check if a vertex shader is used, and if not directly
5710 FIXME("Drawing an uncached patch. This is slow\n");
5711 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5714 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5715 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5716 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5718 TRACE("Tesselation density or patch info changed, retesselating\n");
5720 if(pRectPatchInfo) {
5721 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5723 patch->numSegs[0] = pNumSegs[0];
5724 patch->numSegs[1] = pNumSegs[1];
5725 patch->numSegs[2] = pNumSegs[2];
5726 patch->numSegs[3] = pNumSegs[3];
5728 hr = tesselate_rectpatch(This, patch);
5730 WARN("Patch tesselation failed\n");
5732 /* Do not release the handle to store the params of the patch */
5734 HeapFree(GetProcessHeap(), 0, patch);
5740 This->currentPatch = patch;
5741 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5742 This->currentPatch = NULL;
5744 /* Destroy uncached patches */
5746 HeapFree(GetProcessHeap(), 0, patch->mem);
5747 HeapFree(GetProcessHeap(), 0, patch);
5752 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5753 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5755 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5756 FIXME("(%p) : Stub\n", This);
5760 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5763 struct WineD3DRectPatch *patch;
5765 TRACE("(%p) Handle(%d)\n", This, Handle);
5767 i = PATCHMAP_HASHFUNC(Handle);
5768 LIST_FOR_EACH(e, &This->patches[i]) {
5769 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5770 if(patch->Handle == Handle) {
5771 TRACE("Deleting patch %p\n", patch);
5772 list_remove(&patch->entry);
5773 HeapFree(GetProcessHeap(), 0, patch->mem);
5774 HeapFree(GetProcessHeap(), 0, patch);
5779 /* TODO: Write a test for the return value */
5780 FIXME("Attempt to destroy nonexistent patch\n");
5781 return WINED3DERR_INVALIDCALL;
5784 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5786 IWineD3DSwapChain *swapchain;
5788 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5789 if (SUCCEEDED(hr)) {
5790 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5797 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5801 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5802 checkGLcall("glGenFramebuffersEXT()");
5804 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5805 checkGLcall("glBindFramebuffer()");
5808 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5809 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5810 IWineD3DBaseTextureImpl *texture_impl;
5811 GLenum texttarget, target;
5814 texttarget = surface_impl->glDescription.target;
5815 if(texttarget == GL_TEXTURE_2D) {
5816 target = GL_TEXTURE_2D;
5817 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5818 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
5819 target = GL_TEXTURE_RECTANGLE_ARB;
5820 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5822 target = GL_TEXTURE_CUBE_MAP_ARB;
5823 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5826 IWineD3DSurface_PreLoad(surface);
5828 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5829 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5830 glBindTexture(target, old_binding);
5832 /* Update base texture states array */
5833 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5834 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5835 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5836 if (texture_impl->baseTexture.bindCount) {
5837 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5840 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5843 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5844 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5846 checkGLcall("attach_surface_fbo");
5849 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5851 IWineD3DSwapChain *swapchain;
5853 swapchain = get_swapchain(surface);
5857 TRACE("Surface %p is onscreen\n", surface);
5859 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5860 buffer = surface_get_gl_buffer(surface, swapchain);
5861 glDrawBuffer(buffer);
5862 checkGLcall("glDrawBuffer()");
5864 TRACE("Surface %p is offscreen\n", surface);
5865 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5866 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5870 glEnable(GL_SCISSOR_TEST);
5872 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5874 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5875 rect->x2 - rect->x1, rect->y2 - rect->y1);
5877 checkGLcall("glScissor");
5879 glDisable(GL_SCISSOR_TEST);
5881 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5883 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5884 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5886 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5887 glClear(GL_COLOR_BUFFER_BIT);
5888 checkGLcall("glClear");
5890 if (This->render_offscreen) {
5891 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5893 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5894 checkGLcall("glBindFramebuffer()");
5897 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5898 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5899 glDrawBuffer(GL_BACK);
5900 checkGLcall("glDrawBuffer()");
5904 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5905 unsigned int r, g, b, a;
5908 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
5909 destfmt == WINED3DFMT_R8G8B8)
5912 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5914 a = (color & 0xff000000) >> 24;
5915 r = (color & 0x00ff0000) >> 16;
5916 g = (color & 0x0000ff00) >> 8;
5917 b = (color & 0x000000ff) >> 0;
5921 case WINED3DFMT_R5G6B5:
5922 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5929 TRACE("Returning %08x\n", ret);
5932 case WINED3DFMT_X1R5G5B5:
5933 case WINED3DFMT_A1R5G5B5:
5942 TRACE("Returning %08x\n", ret);
5946 TRACE("Returning %08x\n", a);
5949 case WINED3DFMT_X4R4G4B4:
5950 case WINED3DFMT_A4R4G4B4:
5959 TRACE("Returning %08x\n", ret);
5962 case WINED3DFMT_R3G3B2:
5969 TRACE("Returning %08x\n", ret);
5972 case WINED3DFMT_X8B8G8R8:
5973 case WINED3DFMT_A8B8G8R8:
5978 TRACE("Returning %08x\n", ret);
5981 case WINED3DFMT_A2R10G10B10:
5983 r = (r * 1024) / 256;
5984 g = (g * 1024) / 256;
5985 b = (b * 1024) / 256;
5990 TRACE("Returning %08x\n", ret);
5993 case WINED3DFMT_A2B10G10R10:
5995 r = (r * 1024) / 256;
5996 g = (g * 1024) / 256;
5997 b = (b * 1024) / 256;
6002 TRACE("Returning %08x\n", ret);
6006 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6011 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6013 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6015 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6017 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6018 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6019 return WINED3DERR_INVALIDCALL;
6022 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6023 color_fill_fbo(iface, pSurface, pRect, color);
6026 /* Just forward this to the DirectDraw blitting engine */
6027 memset(&BltFx, 0, sizeof(BltFx));
6028 BltFx.dwSize = sizeof(BltFx);
6029 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6030 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6034 /* rendertarget and depth stencil functions */
6035 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6038 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6039 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6040 return WINED3DERR_INVALIDCALL;
6043 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6044 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6045 /* Note inc ref on returned surface */
6046 if(*ppRenderTarget != NULL)
6047 IWineD3DSurface_AddRef(*ppRenderTarget);
6051 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6053 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6054 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6055 IWineD3DSwapChainImpl *Swapchain;
6058 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6060 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6061 if(hr != WINED3D_OK) {
6062 ERR("Can't get the swapchain\n");
6066 /* Make sure to release the swapchain */
6067 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6069 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6070 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6071 return WINED3DERR_INVALIDCALL;
6073 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6074 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6075 return WINED3DERR_INVALIDCALL;
6078 if(Swapchain->frontBuffer != Front) {
6079 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6081 if(Swapchain->frontBuffer)
6082 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6083 Swapchain->frontBuffer = Front;
6085 if(Swapchain->frontBuffer) {
6086 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6090 if(Back && !Swapchain->backBuffer) {
6091 /* We need memory for the back buffer array - only one back buffer this way */
6092 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6093 if(!Swapchain->backBuffer) {
6094 ERR("Out of memory\n");
6095 return E_OUTOFMEMORY;
6099 if(Swapchain->backBuffer[0] != Back) {
6100 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6102 /* What to do about the context here in the case of multithreading? Not sure.
6103 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6106 if(!Swapchain->backBuffer[0]) {
6107 /* GL was told to draw to the front buffer at creation,
6110 glDrawBuffer(GL_BACK);
6111 checkGLcall("glDrawBuffer(GL_BACK)");
6112 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6113 Swapchain->presentParms.BackBufferCount = 1;
6115 /* That makes problems - disable for now */
6116 /* glDrawBuffer(GL_FRONT); */
6117 checkGLcall("glDrawBuffer(GL_FRONT)");
6118 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6119 Swapchain->presentParms.BackBufferCount = 0;
6123 if(Swapchain->backBuffer[0])
6124 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6125 Swapchain->backBuffer[0] = Back;
6127 if(Swapchain->backBuffer[0]) {
6128 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6130 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6131 Swapchain->backBuffer = NULL;
6139 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6141 *ppZStencilSurface = This->stencilBufferTarget;
6142 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6144 if(*ppZStencilSurface != NULL) {
6145 /* Note inc ref on returned surface */
6146 IWineD3DSurface_AddRef(*ppZStencilSurface);
6149 return WINED3DERR_NOTFOUND;
6153 /* TODO: Handle stencil attachments */
6154 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6156 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6158 TRACE("Set depth stencil to %p\n", depth_stencil);
6160 if (depth_stencil_impl) {
6161 if (depth_stencil_impl->current_renderbuffer) {
6162 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6163 checkGLcall("glFramebufferRenderbufferEXT()");
6165 IWineD3DBaseTextureImpl *texture_impl;
6166 GLenum texttarget, target;
6167 GLint old_binding = 0;
6169 texttarget = depth_stencil_impl->glDescription.target;
6170 if(texttarget == GL_TEXTURE_2D) {
6171 target = GL_TEXTURE_2D;
6172 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6173 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6174 target = GL_TEXTURE_RECTANGLE_ARB;
6175 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6177 target = GL_TEXTURE_CUBE_MAP_ARB;
6178 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6181 IWineD3DSurface_PreLoad(depth_stencil);
6183 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6184 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6185 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6186 glBindTexture(target, old_binding);
6188 /* Update base texture states array */
6189 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6190 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6191 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6192 if (texture_impl->baseTexture.bindCount) {
6193 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6196 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6199 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6200 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6201 checkGLcall("glFramebufferTexture2DEXT()");
6204 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6205 checkGLcall("glFramebufferTexture2DEXT()");
6209 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6211 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6213 TRACE("Set render target %u to %p\n", idx, render_target);
6216 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6217 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6219 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6220 checkGLcall("glFramebufferTexture2DEXT()");
6222 This->draw_buffers[idx] = GL_NONE;
6226 static void check_fbo_status(IWineD3DDevice *iface) {
6227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6230 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6231 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6232 TRACE("FBO complete\n");
6234 IWineD3DSurfaceImpl *attachment;
6236 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6238 /* Dump the FBO attachments */
6239 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6240 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6242 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6243 attachment->pow2Width, attachment->pow2Height);
6246 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6248 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6249 attachment->pow2Width, attachment->pow2Height);
6254 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6256 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6257 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6259 if (!ds_impl) return FALSE;
6261 if (ds_impl->current_renderbuffer) {
6262 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6263 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6266 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6267 rt_impl->pow2Height != ds_impl->pow2Height);
6270 void apply_fbo_state(IWineD3DDevice *iface) {
6271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6274 if (This->render_offscreen) {
6275 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6277 /* Apply render targets */
6278 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6279 IWineD3DSurface *render_target = This->render_targets[i];
6280 if (This->fbo_color_attachments[i] != render_target) {
6281 set_render_target_fbo(iface, i, render_target);
6282 This->fbo_color_attachments[i] = render_target;
6286 /* Apply depth targets */
6287 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6288 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6289 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6291 if (This->stencilBufferTarget) {
6292 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6294 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6295 This->fbo_depth_attachment = This->stencilBufferTarget;
6298 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6299 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6300 checkGLcall("glDrawBuffers()");
6302 glDrawBuffer(This->draw_buffers[0]);
6303 checkGLcall("glDrawBuffer()");
6306 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6309 check_fbo_status(iface);
6312 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6313 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6315 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6316 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6319 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6320 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6321 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6322 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6325 case WINED3DTEXF_LINEAR:
6326 gl_filter = GL_LINEAR;
6330 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6331 case WINED3DTEXF_NONE:
6332 case WINED3DTEXF_POINT:
6333 gl_filter = GL_NEAREST;
6337 /* Attach src surface to src fbo */
6338 src_swapchain = get_swapchain(src_surface);
6339 if (src_swapchain) {
6342 TRACE("Source surface %p is onscreen\n", src_surface);
6343 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6344 /* Make sure the drawable is up to date. In the offscreen case
6345 * attach_surface_fbo() implicitly takes care of this. */
6346 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6349 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6350 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6351 glReadBuffer(buffer);
6352 checkGLcall("glReadBuffer()");
6354 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6355 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6357 TRACE("Source surface %p is offscreen\n", src_surface);
6359 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6360 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6361 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6362 checkGLcall("glReadBuffer()");
6366 /* Attach dst surface to dst fbo */
6367 dst_swapchain = get_swapchain(dst_surface);
6368 if (dst_swapchain) {
6371 TRACE("Destination surface %p is onscreen\n", dst_surface);
6372 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6373 /* Make sure the drawable is up to date. In the offscreen case
6374 * attach_surface_fbo() implicitly takes care of this. */
6375 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6378 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6379 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6380 glDrawBuffer(buffer);
6381 checkGLcall("glDrawBuffer()");
6383 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6384 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6386 TRACE("Destination surface %p is offscreen\n", dst_surface);
6388 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6389 if(!src_swapchain) {
6390 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6394 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6395 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6396 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6397 checkGLcall("glDrawBuffer()");
6399 glDisable(GL_SCISSOR_TEST);
6400 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6403 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6404 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6405 checkGLcall("glBlitFramebuffer()");
6407 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6408 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6409 checkGLcall("glBlitFramebuffer()");
6412 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6414 if (This->render_offscreen) {
6415 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6417 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6418 checkGLcall("glBindFramebuffer()");
6421 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6422 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6423 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6424 glDrawBuffer(GL_BACK);
6425 checkGLcall("glDrawBuffer()");
6430 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6432 WINED3DVIEWPORT viewport;
6434 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6436 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6437 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6438 This, RenderTargetIndex, GL_LIMITS(buffers));
6439 return WINED3DERR_INVALIDCALL;
6442 /* MSDN says that null disables the render target
6443 but a device must always be associated with a render target
6444 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6446 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6449 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6450 FIXME("Trying to set render target 0 to NULL\n");
6451 return WINED3DERR_INVALIDCALL;
6453 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6454 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);
6455 return WINED3DERR_INVALIDCALL;
6458 /* If we are trying to set what we already have, don't bother */
6459 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6460 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6463 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6464 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6465 This->render_targets[RenderTargetIndex] = pRenderTarget;
6467 /* Render target 0 is special */
6468 if(RenderTargetIndex == 0) {
6469 /* Finally, reset the viewport as the MSDN states. */
6470 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6471 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6474 viewport.MaxZ = 1.0f;
6475 viewport.MinZ = 0.0f;
6476 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6477 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6478 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6480 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6482 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6484 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6485 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6487 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6492 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6494 HRESULT hr = WINED3D_OK;
6495 IWineD3DSurface *tmp;
6497 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6499 if (pNewZStencil == This->stencilBufferTarget) {
6500 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6502 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6503 * depending on the renter target implementation being used.
6504 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6505 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6506 * stencil buffer and incur an extra memory overhead
6507 ******************************************************/
6509 tmp = This->stencilBufferTarget;
6510 This->stencilBufferTarget = pNewZStencil;
6511 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6512 /* should we be calling the parent or the wined3d surface? */
6513 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6514 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6517 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6518 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6519 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6520 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6521 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6528 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6529 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6531 /* TODO: the use of Impl is deprecated. */
6532 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6533 WINED3DLOCKED_RECT lockedRect;
6535 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6537 /* some basic validation checks */
6538 if(This->cursorTexture) {
6539 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6541 glDeleteTextures(1, &This->cursorTexture);
6543 This->cursorTexture = 0;
6546 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6547 This->haveHardwareCursor = TRUE;
6549 This->haveHardwareCursor = FALSE;
6552 WINED3DLOCKED_RECT rect;
6554 /* MSDN: Cursor must be A8R8G8B8 */
6555 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6556 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6557 return WINED3DERR_INVALIDCALL;
6560 /* MSDN: Cursor must be smaller than the display mode */
6561 if(pSur->currentDesc.Width > This->ddraw_width ||
6562 pSur->currentDesc.Height > This->ddraw_height) {
6563 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);
6564 return WINED3DERR_INVALIDCALL;
6567 if (!This->haveHardwareCursor) {
6568 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6570 /* Do not store the surface's pointer because the application may
6571 * release it after setting the cursor image. Windows doesn't
6572 * addref the set surface, so we can't do this either without
6573 * creating circular refcount dependencies. Copy out the gl texture
6576 This->cursorWidth = pSur->currentDesc.Width;
6577 This->cursorHeight = pSur->currentDesc.Height;
6578 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6580 const GlPixelFormatDesc *glDesc;
6581 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6582 char *mem, *bits = (char *)rect.pBits;
6583 GLint intfmt = glDesc->glInternal;
6584 GLint format = glDesc->glFormat;
6585 GLint type = glDesc->glType;
6586 INT height = This->cursorHeight;
6587 INT width = This->cursorWidth;
6588 INT bpp = tableEntry->bpp;
6591 /* Reformat the texture memory (pitch and width can be
6593 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6594 for(i = 0; i < height; i++)
6595 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6596 IWineD3DSurface_UnlockRect(pCursorBitmap);
6599 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6600 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6601 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6604 /* Make sure that a proper texture unit is selected */
6605 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6606 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6607 checkGLcall("glActiveTextureARB");
6609 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6610 /* Create a new cursor texture */
6611 glGenTextures(1, &This->cursorTexture);
6612 checkGLcall("glGenTextures");
6613 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6614 checkGLcall("glBindTexture");
6615 /* Copy the bitmap memory into the cursor texture */
6616 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6617 HeapFree(GetProcessHeap(), 0, mem);
6618 checkGLcall("glTexImage2D");
6620 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6621 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6622 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6629 FIXME("A cursor texture was not returned.\n");
6630 This->cursorTexture = 0;
6635 /* Draw a hardware cursor */
6636 ICONINFO cursorInfo;
6638 /* Create and clear maskBits because it is not needed for
6639 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6641 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6642 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6643 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6644 WINED3DLOCK_NO_DIRTY_UPDATE |
6645 WINED3DLOCK_READONLY
6647 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6648 pSur->currentDesc.Height);
6650 cursorInfo.fIcon = FALSE;
6651 cursorInfo.xHotspot = XHotSpot;
6652 cursorInfo.yHotspot = YHotSpot;
6653 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6654 pSur->currentDesc.Height, 1,
6656 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6657 pSur->currentDesc.Height, 1,
6658 32, lockedRect.pBits);
6659 IWineD3DSurface_UnlockRect(pCursorBitmap);
6660 /* Create our cursor and clean up. */
6661 cursor = CreateIconIndirect(&cursorInfo);
6663 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6664 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6665 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6666 This->hardwareCursor = cursor;
6667 HeapFree(GetProcessHeap(), 0, maskBits);
6671 This->xHotSpot = XHotSpot;
6672 This->yHotSpot = YHotSpot;
6676 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6678 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6680 This->xScreenSpace = XScreenSpace;
6681 This->yScreenSpace = YScreenSpace;
6687 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6689 BOOL oldVisible = This->bCursorVisible;
6692 TRACE("(%p) : visible(%d)\n", This, bShow);
6695 * When ShowCursor is first called it should make the cursor appear at the OS's last
6696 * known cursor position. Because of this, some applications just repetitively call
6697 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6700 This->xScreenSpace = pt.x;
6701 This->yScreenSpace = pt.y;
6703 if (This->haveHardwareCursor) {
6704 This->bCursorVisible = bShow;
6706 SetCursor(This->hardwareCursor);
6712 if (This->cursorTexture)
6713 This->bCursorVisible = bShow;
6719 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6721 IWineD3DResourceImpl *resource;
6722 TRACE("(%p) : state (%u)\n", This, This->state);
6724 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6725 switch (This->state) {
6728 case WINED3DERR_DEVICELOST:
6730 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6731 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6732 return WINED3DERR_DEVICENOTRESET;
6734 return WINED3DERR_DEVICELOST;
6736 case WINED3DERR_DRIVERINTERNALERROR:
6737 return WINED3DERR_DRIVERINTERNALERROR;
6741 return WINED3DERR_DRIVERINTERNALERROR;
6745 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6747 /** FIXME: Resource tracking needs to be done,
6748 * The closes we can do to this is set the priorities of all managed textures low
6749 * and then reset them.
6750 ***********************************************************/
6751 FIXME("(%p) : stub\n", This);
6755 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6756 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6758 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6759 if(surface->Flags & SFLAG_DIBSECTION) {
6760 /* Release the DC */
6761 SelectObject(surface->hDC, surface->dib.holdbitmap);
6762 DeleteDC(surface->hDC);
6763 /* Release the DIB section */
6764 DeleteObject(surface->dib.DIBsection);
6765 surface->dib.bitmap_data = NULL;
6766 surface->resource.allocatedMemory = NULL;
6767 surface->Flags &= ~SFLAG_DIBSECTION;
6769 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6770 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6771 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6772 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6773 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6775 surface->pow2Width = surface->pow2Height = 1;
6776 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6777 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6779 if(surface->glDescription.textureName) {
6780 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6782 glDeleteTextures(1, &surface->glDescription.textureName);
6784 surface->glDescription.textureName = 0;
6785 surface->Flags &= ~SFLAG_CLIENT;
6787 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6788 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6789 surface->Flags |= SFLAG_NONPOW2;
6791 surface->Flags &= ~SFLAG_NONPOW2;
6793 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6794 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6797 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6798 TRACE("Unloading resource %p\n", resource);
6799 IWineD3DResource_UnLoad(resource);
6800 IWineD3DResource_Release(resource);
6804 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6806 IWineD3DSwapChainImpl *swapchain;
6808 BOOL DisplayModeChanged = FALSE;
6809 WINED3DDISPLAYMODE mode;
6810 IWineD3DBaseShaderImpl *shader;
6811 TRACE("(%p)\n", This);
6813 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6815 ERR("Failed to get the first implicit swapchain\n");
6819 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6820 * on an existing gl context, so there's no real need for recreation.
6822 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6824 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6826 TRACE("New params:\n");
6827 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6828 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6829 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6830 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6831 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6832 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6833 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6834 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6835 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6836 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6837 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6838 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6839 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6841 /* No special treatment of these parameters. Just store them */
6842 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6843 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6844 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6845 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6847 /* What to do about these? */
6848 if(pPresentationParameters->BackBufferCount != 0 &&
6849 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6850 ERR("Cannot change the back buffer count yet\n");
6852 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6853 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6854 ERR("Cannot change the back buffer format yet\n");
6856 if(pPresentationParameters->hDeviceWindow != NULL &&
6857 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6858 ERR("Cannot change the device window yet\n");
6860 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6861 ERR("What do do about a changed auto depth stencil parameter?\n");
6864 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6865 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6866 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6869 if(pPresentationParameters->Windowed) {
6870 mode.Width = swapchain->orig_width;
6871 mode.Height = swapchain->orig_height;
6872 mode.RefreshRate = 0;
6873 mode.Format = swapchain->presentParms.BackBufferFormat;
6875 mode.Width = pPresentationParameters->BackBufferWidth;
6876 mode.Height = pPresentationParameters->BackBufferHeight;
6877 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6878 mode.Format = swapchain->presentParms.BackBufferFormat;
6881 /* Should Width == 800 && Height == 0 set 800x600? */
6882 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6883 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6884 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6891 vp.Width = pPresentationParameters->BackBufferWidth;
6892 vp.Height = pPresentationParameters->BackBufferHeight;
6896 if(!pPresentationParameters->Windowed) {
6897 DisplayModeChanged = TRUE;
6899 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6900 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6902 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6903 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6904 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6907 /* Now set the new viewport */
6908 IWineD3DDevice_SetViewport(iface, &vp);
6911 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6912 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6913 DisplayModeChanged) {
6915 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6916 if(!pPresentationParameters->Windowed) {
6917 IWineD3DDevice_SetFullscreen(iface, TRUE);
6920 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6922 /* Switching out of fullscreen mode? First set the original res, then change the window */
6923 if(pPresentationParameters->Windowed) {
6924 IWineD3DDevice_SetFullscreen(iface, FALSE);
6926 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6929 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6933 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6935 /** FIXME: always true at the moment **/
6936 if(!bEnableDialogs) {
6937 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6943 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6945 TRACE("(%p) : pParameters %p\n", This, pParameters);
6947 *pParameters = This->createParms;
6951 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6952 IWineD3DSwapChain *swapchain;
6953 HRESULT hrc = WINED3D_OK;
6955 TRACE("Relaying to swapchain\n");
6957 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6958 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6959 IWineD3DSwapChain_Release(swapchain);
6964 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6965 IWineD3DSwapChain *swapchain;
6966 HRESULT hrc = WINED3D_OK;
6968 TRACE("Relaying to swapchain\n");
6970 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6971 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6972 IWineD3DSwapChain_Release(swapchain);
6978 /** ********************************************************
6979 * Notification functions
6980 ** ********************************************************/
6981 /** This function must be called in the release of a resource when ref == 0,
6982 * the contents of resource must still be correct,
6983 * any handles to other resource held by the caller must be closed
6984 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6985 *****************************************************/
6986 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6989 TRACE("(%p) : Adding Resource %p\n", This, resource);
6990 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6993 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6996 TRACE("(%p) : Removing resource %p\n", This, resource);
6998 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7002 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7006 TRACE("(%p) : resource %p\n", This, resource);
7007 switch(IWineD3DResource_GetType(resource)){
7008 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7009 case WINED3DRTYPE_SURFACE: {
7012 /* Cleanup any FBO attachments if d3d is enabled */
7013 if(This->d3d_initialized) {
7014 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7015 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7017 TRACE("Last active render target destroyed\n");
7018 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7019 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7020 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7021 * and the lastActiveRenderTarget member shouldn't matter
7024 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7025 TRACE("Activating primary back buffer\n");
7026 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7027 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7028 /* Single buffering environment */
7029 TRACE("Activating primary front buffer\n");
7030 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7032 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7033 /* Implicit render target destroyed, that means the device is being destroyed
7034 * whatever we set here, it shouldn't matter
7036 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7039 /* May happen during ddraw uninitialization */
7040 TRACE("Render target set, but swapchain does not exist!\n");
7041 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7045 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7046 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7047 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7048 set_render_target_fbo(iface, i, NULL);
7049 This->fbo_color_attachments[i] = NULL;
7052 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7053 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7054 set_depth_stencil_fbo(iface, NULL);
7055 This->fbo_depth_attachment = NULL;
7061 case WINED3DRTYPE_TEXTURE:
7062 case WINED3DRTYPE_CUBETEXTURE:
7063 case WINED3DRTYPE_VOLUMETEXTURE:
7064 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7065 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7066 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7067 This->stateBlock->textures[counter] = NULL;
7069 if (This->updateStateBlock != This->stateBlock ){
7070 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7071 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7072 This->updateStateBlock->textures[counter] = NULL;
7077 case WINED3DRTYPE_VOLUME:
7078 /* TODO: nothing really? */
7080 case WINED3DRTYPE_VERTEXBUFFER:
7081 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7084 TRACE("Cleaning up stream pointers\n");
7086 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7087 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7088 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7090 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7091 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7092 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7093 This->updateStateBlock->streamSource[streamNumber] = 0;
7094 /* Set changed flag? */
7097 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) */
7098 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7099 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7100 This->stateBlock->streamSource[streamNumber] = 0;
7103 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7104 else { /* This shouldn't happen */
7105 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7112 case WINED3DRTYPE_INDEXBUFFER:
7113 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7114 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7115 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7116 This->updateStateBlock->pIndexData = NULL;
7119 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7120 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7121 This->stateBlock->pIndexData = NULL;
7127 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7132 /* Remove the resource from the resourceStore */
7133 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7135 TRACE("Resource released\n");
7139 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7141 IWineD3DResourceImpl *resource, *cursor;
7143 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7145 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7146 TRACE("enumerating resource %p\n", resource);
7147 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7148 ret = pCallback((IWineD3DResource *) resource, pData);
7149 if(ret == S_FALSE) {
7150 TRACE("Canceling enumeration\n");
7157 /**********************************************************
7158 * IWineD3DDevice VTbl follows
7159 **********************************************************/
7161 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7163 /*** IUnknown methods ***/
7164 IWineD3DDeviceImpl_QueryInterface,
7165 IWineD3DDeviceImpl_AddRef,
7166 IWineD3DDeviceImpl_Release,
7167 /*** IWineD3DDevice methods ***/
7168 IWineD3DDeviceImpl_GetParent,
7169 /*** Creation methods**/
7170 IWineD3DDeviceImpl_CreateVertexBuffer,
7171 IWineD3DDeviceImpl_CreateIndexBuffer,
7172 IWineD3DDeviceImpl_CreateStateBlock,
7173 IWineD3DDeviceImpl_CreateSurface,
7174 IWineD3DDeviceImpl_CreateTexture,
7175 IWineD3DDeviceImpl_CreateVolumeTexture,
7176 IWineD3DDeviceImpl_CreateVolume,
7177 IWineD3DDeviceImpl_CreateCubeTexture,
7178 IWineD3DDeviceImpl_CreateQuery,
7179 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7180 IWineD3DDeviceImpl_CreateVertexDeclaration,
7181 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7182 IWineD3DDeviceImpl_CreateVertexShader,
7183 IWineD3DDeviceImpl_CreatePixelShader,
7184 IWineD3DDeviceImpl_CreatePalette,
7185 /*** Odd functions **/
7186 IWineD3DDeviceImpl_Init3D,
7187 IWineD3DDeviceImpl_Uninit3D,
7188 IWineD3DDeviceImpl_SetFullscreen,
7189 IWineD3DDeviceImpl_SetMultithreaded,
7190 IWineD3DDeviceImpl_EvictManagedResources,
7191 IWineD3DDeviceImpl_GetAvailableTextureMem,
7192 IWineD3DDeviceImpl_GetBackBuffer,
7193 IWineD3DDeviceImpl_GetCreationParameters,
7194 IWineD3DDeviceImpl_GetDeviceCaps,
7195 IWineD3DDeviceImpl_GetDirect3D,
7196 IWineD3DDeviceImpl_GetDisplayMode,
7197 IWineD3DDeviceImpl_SetDisplayMode,
7198 IWineD3DDeviceImpl_GetHWND,
7199 IWineD3DDeviceImpl_SetHWND,
7200 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7201 IWineD3DDeviceImpl_GetRasterStatus,
7202 IWineD3DDeviceImpl_GetSwapChain,
7203 IWineD3DDeviceImpl_Reset,
7204 IWineD3DDeviceImpl_SetDialogBoxMode,
7205 IWineD3DDeviceImpl_SetCursorProperties,
7206 IWineD3DDeviceImpl_SetCursorPosition,
7207 IWineD3DDeviceImpl_ShowCursor,
7208 IWineD3DDeviceImpl_TestCooperativeLevel,
7209 /*** Getters and setters **/
7210 IWineD3DDeviceImpl_SetClipPlane,
7211 IWineD3DDeviceImpl_GetClipPlane,
7212 IWineD3DDeviceImpl_SetClipStatus,
7213 IWineD3DDeviceImpl_GetClipStatus,
7214 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7215 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7216 IWineD3DDeviceImpl_SetDepthStencilSurface,
7217 IWineD3DDeviceImpl_GetDepthStencilSurface,
7218 IWineD3DDeviceImpl_SetFVF,
7219 IWineD3DDeviceImpl_GetFVF,
7220 IWineD3DDeviceImpl_SetGammaRamp,
7221 IWineD3DDeviceImpl_GetGammaRamp,
7222 IWineD3DDeviceImpl_SetIndices,
7223 IWineD3DDeviceImpl_GetIndices,
7224 IWineD3DDeviceImpl_SetBaseVertexIndex,
7225 IWineD3DDeviceImpl_GetBaseVertexIndex,
7226 IWineD3DDeviceImpl_SetLight,
7227 IWineD3DDeviceImpl_GetLight,
7228 IWineD3DDeviceImpl_SetLightEnable,
7229 IWineD3DDeviceImpl_GetLightEnable,
7230 IWineD3DDeviceImpl_SetMaterial,
7231 IWineD3DDeviceImpl_GetMaterial,
7232 IWineD3DDeviceImpl_SetNPatchMode,
7233 IWineD3DDeviceImpl_GetNPatchMode,
7234 IWineD3DDeviceImpl_SetPaletteEntries,
7235 IWineD3DDeviceImpl_GetPaletteEntries,
7236 IWineD3DDeviceImpl_SetPixelShader,
7237 IWineD3DDeviceImpl_GetPixelShader,
7238 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7239 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7240 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7241 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7242 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7243 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7244 IWineD3DDeviceImpl_SetRenderState,
7245 IWineD3DDeviceImpl_GetRenderState,
7246 IWineD3DDeviceImpl_SetRenderTarget,
7247 IWineD3DDeviceImpl_GetRenderTarget,
7248 IWineD3DDeviceImpl_SetFrontBackBuffers,
7249 IWineD3DDeviceImpl_SetSamplerState,
7250 IWineD3DDeviceImpl_GetSamplerState,
7251 IWineD3DDeviceImpl_SetScissorRect,
7252 IWineD3DDeviceImpl_GetScissorRect,
7253 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7254 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7255 IWineD3DDeviceImpl_SetStreamSource,
7256 IWineD3DDeviceImpl_GetStreamSource,
7257 IWineD3DDeviceImpl_SetStreamSourceFreq,
7258 IWineD3DDeviceImpl_GetStreamSourceFreq,
7259 IWineD3DDeviceImpl_SetTexture,
7260 IWineD3DDeviceImpl_GetTexture,
7261 IWineD3DDeviceImpl_SetTextureStageState,
7262 IWineD3DDeviceImpl_GetTextureStageState,
7263 IWineD3DDeviceImpl_SetTransform,
7264 IWineD3DDeviceImpl_GetTransform,
7265 IWineD3DDeviceImpl_SetVertexDeclaration,
7266 IWineD3DDeviceImpl_GetVertexDeclaration,
7267 IWineD3DDeviceImpl_SetVertexShader,
7268 IWineD3DDeviceImpl_GetVertexShader,
7269 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7270 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7271 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7272 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7273 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7274 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7275 IWineD3DDeviceImpl_SetViewport,
7276 IWineD3DDeviceImpl_GetViewport,
7277 IWineD3DDeviceImpl_MultiplyTransform,
7278 IWineD3DDeviceImpl_ValidateDevice,
7279 IWineD3DDeviceImpl_ProcessVertices,
7280 /*** State block ***/
7281 IWineD3DDeviceImpl_BeginStateBlock,
7282 IWineD3DDeviceImpl_EndStateBlock,
7283 /*** Scene management ***/
7284 IWineD3DDeviceImpl_BeginScene,
7285 IWineD3DDeviceImpl_EndScene,
7286 IWineD3DDeviceImpl_Present,
7287 IWineD3DDeviceImpl_Clear,
7289 IWineD3DDeviceImpl_DrawPrimitive,
7290 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7291 IWineD3DDeviceImpl_DrawPrimitiveUP,
7292 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7293 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7294 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7295 IWineD3DDeviceImpl_DrawRectPatch,
7296 IWineD3DDeviceImpl_DrawTriPatch,
7297 IWineD3DDeviceImpl_DeletePatch,
7298 IWineD3DDeviceImpl_ColorFill,
7299 IWineD3DDeviceImpl_UpdateTexture,
7300 IWineD3DDeviceImpl_UpdateSurface,
7301 IWineD3DDeviceImpl_GetFrontBufferData,
7302 /*** object tracking ***/
7303 IWineD3DDeviceImpl_ResourceReleased,
7304 IWineD3DDeviceImpl_EnumResources
7308 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7309 WINED3DRS_ALPHABLENDENABLE ,
7310 WINED3DRS_ALPHAFUNC ,
7311 WINED3DRS_ALPHAREF ,
7312 WINED3DRS_ALPHATESTENABLE ,
7314 WINED3DRS_COLORWRITEENABLE ,
7315 WINED3DRS_DESTBLEND ,
7316 WINED3DRS_DITHERENABLE ,
7317 WINED3DRS_FILLMODE ,
7318 WINED3DRS_FOGDENSITY ,
7320 WINED3DRS_FOGSTART ,
7321 WINED3DRS_LASTPIXEL ,
7322 WINED3DRS_SHADEMODE ,
7323 WINED3DRS_SRCBLEND ,
7324 WINED3DRS_STENCILENABLE ,
7325 WINED3DRS_STENCILFAIL ,
7326 WINED3DRS_STENCILFUNC ,
7327 WINED3DRS_STENCILMASK ,
7328 WINED3DRS_STENCILPASS ,
7329 WINED3DRS_STENCILREF ,
7330 WINED3DRS_STENCILWRITEMASK ,
7331 WINED3DRS_STENCILZFAIL ,
7332 WINED3DRS_TEXTUREFACTOR ,
7343 WINED3DRS_ZWRITEENABLE
7346 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7347 WINED3DTSS_ADDRESSW ,
7348 WINED3DTSS_ALPHAARG0 ,
7349 WINED3DTSS_ALPHAARG1 ,
7350 WINED3DTSS_ALPHAARG2 ,
7351 WINED3DTSS_ALPHAOP ,
7352 WINED3DTSS_BUMPENVLOFFSET ,
7353 WINED3DTSS_BUMPENVLSCALE ,
7354 WINED3DTSS_BUMPENVMAT00 ,
7355 WINED3DTSS_BUMPENVMAT01 ,
7356 WINED3DTSS_BUMPENVMAT10 ,
7357 WINED3DTSS_BUMPENVMAT11 ,
7358 WINED3DTSS_COLORARG0 ,
7359 WINED3DTSS_COLORARG1 ,
7360 WINED3DTSS_COLORARG2 ,
7361 WINED3DTSS_COLOROP ,
7362 WINED3DTSS_RESULTARG ,
7363 WINED3DTSS_TEXCOORDINDEX ,
7364 WINED3DTSS_TEXTURETRANSFORMFLAGS
7367 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7368 WINED3DSAMP_ADDRESSU ,
7369 WINED3DSAMP_ADDRESSV ,
7370 WINED3DSAMP_ADDRESSW ,
7371 WINED3DSAMP_BORDERCOLOR ,
7372 WINED3DSAMP_MAGFILTER ,
7373 WINED3DSAMP_MINFILTER ,
7374 WINED3DSAMP_MIPFILTER ,
7375 WINED3DSAMP_MIPMAPLODBIAS ,
7376 WINED3DSAMP_MAXMIPLEVEL ,
7377 WINED3DSAMP_MAXANISOTROPY ,
7378 WINED3DSAMP_SRGBTEXTURE ,
7379 WINED3DSAMP_ELEMENTINDEX
7382 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7384 WINED3DRS_AMBIENTMATERIALSOURCE ,
7385 WINED3DRS_CLIPPING ,
7386 WINED3DRS_CLIPPLANEENABLE ,
7387 WINED3DRS_COLORVERTEX ,
7388 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7389 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7390 WINED3DRS_FOGDENSITY ,
7392 WINED3DRS_FOGSTART ,
7393 WINED3DRS_FOGTABLEMODE ,
7394 WINED3DRS_FOGVERTEXMODE ,
7395 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7396 WINED3DRS_LIGHTING ,
7397 WINED3DRS_LOCALVIEWER ,
7398 WINED3DRS_MULTISAMPLEANTIALIAS ,
7399 WINED3DRS_MULTISAMPLEMASK ,
7400 WINED3DRS_NORMALIZENORMALS ,
7401 WINED3DRS_PATCHEDGESTYLE ,
7402 WINED3DRS_POINTSCALE_A ,
7403 WINED3DRS_POINTSCALE_B ,
7404 WINED3DRS_POINTSCALE_C ,
7405 WINED3DRS_POINTSCALEENABLE ,
7406 WINED3DRS_POINTSIZE ,
7407 WINED3DRS_POINTSIZE_MAX ,
7408 WINED3DRS_POINTSIZE_MIN ,
7409 WINED3DRS_POINTSPRITEENABLE ,
7410 WINED3DRS_RANGEFOGENABLE ,
7411 WINED3DRS_SPECULARMATERIALSOURCE ,
7412 WINED3DRS_TWEENFACTOR ,
7413 WINED3DRS_VERTEXBLEND ,
7414 WINED3DRS_CULLMODE ,
7418 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7419 WINED3DTSS_TEXCOORDINDEX ,
7420 WINED3DTSS_TEXTURETRANSFORMFLAGS
7423 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7424 WINED3DSAMP_DMAPOFFSET
7427 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7428 DWORD rep = StateTable[state].representative;
7432 WineD3DContext *context;
7435 for(i = 0; i < This->numContexts; i++) {
7436 context = This->contexts[i];
7437 if(isStateDirty(context, rep)) continue;
7439 context->dirtyArray[context->numDirtyEntries++] = rep;
7442 context->isStateDirty[idx] |= (1 << shift);
7446 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7447 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7448 /* The drawable size of a pbuffer render target is the current pbuffer size
7450 *width = dev->pbufferWidth;
7451 *height = dev->pbufferHeight;
7454 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7455 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7457 *width = This->pow2Width;
7458 *height = This->pow2Height;
7461 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7462 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7463 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7464 * current context's drawable, which is the size of the back buffer of the swapchain
7465 * the active context belongs to. The back buffer of the swapchain is stored as the
7466 * surface the context belongs to.
7468 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7469 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;