2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 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 /**********************************************************
55 * Global variable / Constants follow
56 **********************************************************/
57 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
59 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
60 * actually have the same values in GL and D3D. */
61 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
63 switch(primitive_type)
65 case WINED3DPT_POINTLIST:
68 case WINED3DPT_LINELIST:
71 case WINED3DPT_LINESTRIP:
74 case WINED3DPT_TRIANGLELIST:
77 case WINED3DPT_TRIANGLESTRIP:
78 return GL_TRIANGLE_STRIP;
80 case WINED3DPT_TRIANGLEFAN:
81 return GL_TRIANGLE_FAN;
83 case WINED3DPT_LINELIST_ADJ:
84 return GL_LINES_ADJACENCY_ARB;
86 case WINED3DPT_LINESTRIP_ADJ:
87 return GL_LINE_STRIP_ADJACENCY_ARB;
89 case WINED3DPT_TRIANGLELIST_ADJ:
90 return GL_TRIANGLES_ADJACENCY_ARB;
92 case WINED3DPT_TRIANGLESTRIP_ADJ:
93 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
96 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
101 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
103 switch(primitive_type)
106 return WINED3DPT_POINTLIST;
109 return WINED3DPT_LINELIST;
112 return WINED3DPT_LINESTRIP;
115 return WINED3DPT_TRIANGLELIST;
117 case GL_TRIANGLE_STRIP:
118 return WINED3DPT_TRIANGLESTRIP;
120 case GL_TRIANGLE_FAN:
121 return WINED3DPT_TRIANGLEFAN;
123 case GL_LINES_ADJACENCY_ARB:
124 return WINED3DPT_LINELIST_ADJ;
126 case GL_LINE_STRIP_ADJACENCY_ARB:
127 return WINED3DPT_LINESTRIP_ADJ;
129 case GL_TRIANGLES_ADJACENCY_ARB:
130 return WINED3DPT_TRIANGLELIST_ADJ;
132 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
133 return WINED3DPT_TRIANGLESTRIP_ADJ;
136 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
137 return WINED3DPT_UNDEFINED;
141 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
143 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
144 *regnum = WINED3D_FFP_POSITION;
145 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
146 *regnum = WINED3D_FFP_BLENDWEIGHT;
147 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
148 *regnum = WINED3D_FFP_BLENDINDICES;
149 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
150 *regnum = WINED3D_FFP_NORMAL;
151 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
152 *regnum = WINED3D_FFP_PSIZE;
153 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
154 *regnum = WINED3D_FFP_DIFFUSE;
155 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
156 *regnum = WINED3D_FFP_SPECULAR;
157 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
158 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
161 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
169 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
170 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
172 /* We need to deal with frequency data! */
173 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
174 UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
175 const DWORD *streams = declaration->streams;
178 memset(stream_info, 0, sizeof(*stream_info));
180 /* Check for transformed vertices, disable vertex shader if present. */
181 stream_info->position_transformed = declaration->position_transformed;
182 if (declaration->position_transformed) use_vshader = FALSE;
184 /* Translate the declaration into strided data. */
185 for (i = 0; i < declaration->element_count; ++i)
187 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
188 GLuint buffer_object = 0;
189 const BYTE *data = NULL;
194 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
195 element, i + 1, declaration->element_count);
197 if (!This->stateBlock->streamSource[element->input_slot]) continue;
199 stride = This->stateBlock->streamStride[element->input_slot];
200 if (This->stateBlock->streamIsUP)
202 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
204 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
208 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
209 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
211 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
212 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
213 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
214 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
215 * not, drawStridedSlow is needed, including a vertex buffer path. */
216 if (This->stateBlock->loadBaseVertexIndex < 0)
218 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
220 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
221 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
223 FIXME("System memory vertex data load offset is negative!\n");
229 if (buffer_object) *fixup = TRUE;
230 else if (*fixup && !use_vshader
231 && (element->usage == WINED3DDECLUSAGE_COLOR
232 || element->usage == WINED3DDECLUSAGE_POSITIONT))
234 static BOOL warned = FALSE;
237 /* This may be bad with the fixed function pipeline. */
238 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
244 data += element->offset;
246 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
250 if (element->output_slot == ~0U)
252 /* TODO: Assuming vertexdeclarations are usually used with the
253 * same or a similar shader, it might be worth it to store the
254 * last used output slot and try that one first. */
255 stride_used = vshader_get_input(This->stateBlock->vertexShader,
256 element->usage, element->usage_idx, &idx);
260 idx = element->output_slot;
266 if (!element->ffp_valid)
268 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
269 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
274 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
280 TRACE("Load %s array %u [usage %s, usage_idx %u, "
281 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
282 use_vshader ? "shader": "fixed function", idx,
283 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
284 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
286 stream_info->elements[idx].format_desc = element->format_desc;
287 stream_info->elements[idx].stride = stride;
288 stream_info->elements[idx].data = data;
289 stream_info->elements[idx].stream_idx = element->input_slot;
290 stream_info->elements[idx].buffer_object = buffer_object;
292 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && element->format_desc->format == WINED3DFMT_A8R8G8B8)
294 stream_info->swizzle_map |= 1 << idx;
296 stream_info->use_map |= 1 << idx;
300 /* Now call PreLoad on all the vertex buffers. In the very rare case
301 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
302 * The vertex buffer can now use the strided structure in the device instead of finding its
305 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
307 for (i = 0; i < stream_count; ++i)
309 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
310 if (vb) IWineD3DBuffer_PreLoad(vb);
314 static void stream_info_element_from_strided(IWineD3DDeviceImpl *This,
315 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
317 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, &This->adapter->gl_info);
318 e->format_desc = format_desc;
319 e->stride = strided->dwStride;
320 e->data = strided->lpData;
322 e->buffer_object = 0;
325 void device_stream_info_from_strided(IWineD3DDeviceImpl *This,
326 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
330 memset(stream_info, 0, sizeof(*stream_info));
332 if (strided->position.lpData)
333 stream_info_element_from_strided(This, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
334 if (strided->normal.lpData)
335 stream_info_element_from_strided(This, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
336 if (strided->diffuse.lpData)
337 stream_info_element_from_strided(This, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
338 if (strided->specular.lpData)
339 stream_info_element_from_strided(This, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
341 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
343 if (strided->texCoords[i].lpData)
344 stream_info_element_from_strided(This, &strided->texCoords[i],
345 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
348 stream_info->position_transformed = strided->position_transformed;
350 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
352 if (!stream_info->elements[i].format_desc) continue;
354 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && stream_info->elements[i].format_desc->format == WINED3DFMT_A8R8G8B8)
356 stream_info->swizzle_map |= 1 << i;
358 stream_info->use_map |= 1 << i;
362 /**********************************************************
363 * IUnknown parts follows
364 **********************************************************/
366 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
368 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
370 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
371 if (IsEqualGUID(riid, &IID_IUnknown)
372 || IsEqualGUID(riid, &IID_IWineD3DBase)
373 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
374 IUnknown_AddRef(iface);
379 return E_NOINTERFACE;
382 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
384 ULONG refCount = InterlockedIncrement(&This->ref);
386 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
390 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
392 ULONG refCount = InterlockedDecrement(&This->ref);
394 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
399 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
400 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
401 This->multistate_funcs[i] = NULL;
404 /* TODO: Clean up all the surfaces and textures! */
405 /* NOTE: You must release the parent if the object was created via a callback
406 ** ***************************/
408 if (!list_empty(&This->resources)) {
409 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
410 dumpResources(&This->resources);
413 if(This->contexts) ERR("Context array not freed!\n");
414 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
415 This->haveHardwareCursor = FALSE;
417 IWineD3D_Release(This->wineD3D);
418 This->wineD3D = NULL;
419 HeapFree(GetProcessHeap(), 0, This);
420 TRACE("Freed device %p\n", This);
426 /**********************************************************
427 * IWineD3DDevice implementation follows
428 **********************************************************/
429 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
431 *pParent = This->parent;
432 IUnknown_AddRef(This->parent);
436 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface,
437 struct wined3d_buffer_desc *desc, const void *data, IUnknown *parent, IWineD3DBuffer **buffer)
439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
440 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_UNKNOWN, &This->adapter->gl_info);
441 struct wined3d_buffer *object;
444 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
446 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
449 ERR("Failed to allocate memory\n");
450 return E_OUTOFMEMORY;
453 object->vtbl = &wined3d_buffer_vtbl;
454 object->desc = *desc;
456 FIXME("Ignoring access flags (pool)\n");
458 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, desc->byte_width,
459 desc->usage, format_desc, WINED3DPOOL_MANAGED, parent);
462 WARN("Failed to initialize resource, returning %#x\n", hr);
463 HeapFree(GetProcessHeap(), 0, object);
466 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
468 TRACE("Created resource %p\n", object);
470 TRACE("size %#x, usage=%#x, format %s, memory @ %p, iface @ %p\n", object->resource.size, object->resource.usage,
471 debug_d3dformat(object->resource.format_desc->format), object->resource.allocatedMemory, object);
477 hr = IWineD3DBuffer_Map((IWineD3DBuffer *)object, 0, desc->byte_width, &ptr, 0);
480 ERR("Failed to map buffer, hr %#x\n", hr);
481 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
485 memcpy(ptr, data, desc->byte_width);
487 hr = IWineD3DBuffer_Unmap((IWineD3DBuffer *)object);
490 ERR("Failed to unmap buffer, hr %#x\n", hr);
491 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
496 *buffer = (IWineD3DBuffer *)object;
501 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
502 DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer, IUnknown *parent)
504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
505 /* Dummy format for now */
506 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_VERTEXDATA, &This->adapter->gl_info);
507 struct wined3d_buffer *object;
508 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
513 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
514 *ppVertexBuffer = NULL;
515 return WINED3DERR_INVALIDCALL;
516 } else if(Pool == WINED3DPOOL_SCRATCH) {
517 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
518 * anyway, SCRATCH vertex buffers aren't usable anywhere
520 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
521 *ppVertexBuffer = NULL;
522 return WINED3DERR_INVALIDCALL;
525 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
528 ERR("Out of memory\n");
529 *ppVertexBuffer = NULL;
530 return WINED3DERR_OUTOFVIDEOMEMORY;
533 object->vtbl = &wined3d_buffer_vtbl;
534 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, Size, Usage, format_desc, Pool, parent);
537 WARN("Failed to initialize resource, returning %#x\n", hr);
538 HeapFree(GetProcessHeap(), 0, object);
539 *ppVertexBuffer = NULL;
542 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
544 TRACE("(%p) : Created resource %p\n", This, object);
546 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);
547 *ppVertexBuffer = (IWineD3DBuffer *)object;
549 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
550 * drawStridedFast (half-life 2).
552 * Basically converting the vertices in the buffer is quite expensive, and observations
553 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
554 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
556 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
557 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
558 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
559 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
561 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
562 * more. In this call we can convert dx7 buffers too.
564 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
565 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
566 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
567 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
568 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
569 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
570 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
571 } else if(dxVersion <= 7 && conv) {
572 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
574 object->flags |= WINED3D_BUFFER_CREATEBO;
579 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
580 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer, IUnknown *parent)
582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
583 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_UNKNOWN, &This->adapter->gl_info);
584 struct wined3d_buffer *object;
587 TRACE("(%p) Creating index buffer\n", This);
589 /* Allocate the storage for the device */
590 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
593 ERR("Out of memory\n");
594 *ppIndexBuffer = NULL;
595 return WINED3DERR_OUTOFVIDEOMEMORY;
598 object->vtbl = &wined3d_buffer_vtbl;
599 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, Length, Usage, format_desc, Pool, parent);
602 WARN("Failed to initialize resource, returning %#x\n", hr);
603 HeapFree(GetProcessHeap(), 0, object);
604 *ppIndexBuffer = NULL;
607 object->buffer_type_hint = GL_ELEMENT_ARRAY_BUFFER_ARB;
609 TRACE("(%p) : Created resource %p\n", This, object);
611 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
612 object->flags |= WINED3D_BUFFER_CREATEBO;
615 TRACE("(%p) : Len=%d, Use=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage,
616 Pool, object, object->resource.allocatedMemory);
617 *ppIndexBuffer = (IWineD3DBuffer *) object;
622 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
625 IWineD3DStateBlockImpl *object;
629 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
632 ERR("Out of memory\n");
633 *ppStateBlock = NULL;
634 return WINED3DERR_OUTOFVIDEOMEMORY;
637 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
638 object->wineD3DDevice = This;
639 object->parent = parent;
641 object->blockType = Type;
643 *ppStateBlock = (IWineD3DStateBlock *)object;
645 for(i = 0; i < LIGHTMAP_SIZE; i++) {
646 list_init(&object->lightMap[i]);
649 temp_result = allocate_shader_constants(object);
650 if (FAILED(temp_result))
652 HeapFree(GetProcessHeap(), 0, object);
656 /* Special case - Used during initialization to produce a placeholder stateblock
657 so other functions called can update a state block */
658 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
660 /* Don't bother increasing the reference count otherwise a device will never
661 be freed due to circular dependencies */
665 /* Otherwise, might as well set the whole state block to the appropriate values */
666 if (This->stateBlock != NULL)
667 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
669 memset(object->streamFreq, 1, sizeof(object->streamFreq));
671 /* Reset the ref and type after kludging it */
672 object->wineD3DDevice = This;
674 object->blockType = Type;
676 TRACE("Updating changed flags appropriate for type %d\n", Type);
678 if (Type == WINED3DSBT_ALL) {
680 TRACE("ALL => Pretend everything has changed\n");
681 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
683 /* Lights are not part of the changed / set structure */
684 for(j = 0; j < LIGHTMAP_SIZE; j++) {
686 LIST_FOR_EACH(e, &object->lightMap[j]) {
687 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
688 light->changed = TRUE;
689 light->enabledChanged = TRUE;
692 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
693 object->contained_render_states[j - 1] = j;
695 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
696 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
697 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
698 object->contained_transform_states[j - 1] = j;
700 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
701 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
702 object->contained_vs_consts_f[j] = j;
704 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
705 for(j = 0; j < MAX_CONST_I; j++) {
706 object->contained_vs_consts_i[j] = j;
708 object->num_contained_vs_consts_i = MAX_CONST_I;
709 for(j = 0; j < MAX_CONST_B; j++) {
710 object->contained_vs_consts_b[j] = j;
712 object->num_contained_vs_consts_b = MAX_CONST_B;
713 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
714 object->contained_ps_consts_f[j] = j;
716 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
717 for(j = 0; j < MAX_CONST_I; j++) {
718 object->contained_ps_consts_i[j] = j;
720 object->num_contained_ps_consts_i = MAX_CONST_I;
721 for(j = 0; j < MAX_CONST_B; j++) {
722 object->contained_ps_consts_b[j] = j;
724 object->num_contained_ps_consts_b = MAX_CONST_B;
725 for(i = 0; i < MAX_TEXTURES; i++) {
726 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
728 object->contained_tss_states[object->num_contained_tss_states].stage = i;
729 object->contained_tss_states[object->num_contained_tss_states].state = j;
730 object->num_contained_tss_states++;
733 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
734 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
735 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
736 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
737 object->num_contained_sampler_states++;
741 for(i = 0; i < MAX_STREAMS; i++) {
742 if(object->streamSource[i]) {
743 IWineD3DBuffer_AddRef(object->streamSource[i]);
746 if(object->pIndexData) {
747 IWineD3DBuffer_AddRef(object->pIndexData);
749 if(object->vertexShader) {
750 IWineD3DVertexShader_AddRef(object->vertexShader);
752 if(object->pixelShader) {
753 IWineD3DPixelShader_AddRef(object->pixelShader);
756 } else if (Type == WINED3DSBT_PIXELSTATE) {
758 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
759 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
761 object->changed.pixelShader = TRUE;
763 /* Pixel Shader Constants */
764 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
765 object->contained_ps_consts_f[i] = i;
766 object->changed.pixelShaderConstantsF[i] = TRUE;
768 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
769 for (i = 0; i < MAX_CONST_B; ++i) {
770 object->contained_ps_consts_b[i] = i;
771 object->changed.pixelShaderConstantsB |= (1 << i);
773 object->num_contained_ps_consts_b = MAX_CONST_B;
774 for (i = 0; i < MAX_CONST_I; ++i) {
775 object->contained_ps_consts_i[i] = i;
776 object->changed.pixelShaderConstantsI |= (1 << i);
778 object->num_contained_ps_consts_i = MAX_CONST_I;
780 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
781 DWORD rs = SavedPixelStates_R[i];
782 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
783 object->contained_render_states[i] = rs;
785 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
786 for (j = 0; j < MAX_TEXTURES; j++) {
787 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
788 DWORD state = SavedPixelStates_T[i];
789 object->changed.textureState[j] |= 1 << state;
790 object->contained_tss_states[object->num_contained_tss_states].stage = j;
791 object->contained_tss_states[object->num_contained_tss_states].state = state;
792 object->num_contained_tss_states++;
795 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
796 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
797 DWORD state = SavedPixelStates_S[i];
798 object->changed.samplerState[j] |= 1 << state;
799 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
800 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
801 object->num_contained_sampler_states++;
804 if(object->pixelShader) {
805 IWineD3DPixelShader_AddRef(object->pixelShader);
808 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
809 * on them. This makes releasing the buffer easier
811 for(i = 0; i < MAX_STREAMS; i++) {
812 object->streamSource[i] = NULL;
814 object->pIndexData = NULL;
815 object->vertexShader = NULL;
817 } else if (Type == WINED3DSBT_VERTEXSTATE) {
819 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
820 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
822 object->changed.vertexShader = TRUE;
824 /* Vertex Shader Constants */
825 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
826 object->changed.vertexShaderConstantsF[i] = TRUE;
827 object->contained_vs_consts_f[i] = i;
829 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
830 for (i = 0; i < MAX_CONST_B; ++i) {
831 object->contained_vs_consts_b[i] = i;
832 object->changed.vertexShaderConstantsB |= (1 << i);
834 object->num_contained_vs_consts_b = MAX_CONST_B;
835 for (i = 0; i < MAX_CONST_I; ++i) {
836 object->contained_vs_consts_i[i] = i;
837 object->changed.vertexShaderConstantsI |= (1 << i);
839 object->num_contained_vs_consts_i = MAX_CONST_I;
840 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
841 DWORD rs = SavedVertexStates_R[i];
842 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
843 object->contained_render_states[i] = rs;
845 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
846 for (j = 0; j < MAX_TEXTURES; j++) {
847 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
848 DWORD state = SavedVertexStates_T[i];
849 object->changed.textureState[j] |= 1 << state;
850 object->contained_tss_states[object->num_contained_tss_states].stage = j;
851 object->contained_tss_states[object->num_contained_tss_states].state = state;
852 object->num_contained_tss_states++;
855 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
856 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
857 DWORD state = SavedVertexStates_S[i];
858 object->changed.samplerState[j] |= 1 << state;
859 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
860 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
861 object->num_contained_sampler_states++;
865 for(j = 0; j < LIGHTMAP_SIZE; j++) {
867 LIST_FOR_EACH(e, &object->lightMap[j]) {
868 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
869 light->changed = TRUE;
870 light->enabledChanged = TRUE;
874 for(i = 0; i < MAX_STREAMS; i++) {
875 if(object->streamSource[i]) {
876 IWineD3DBuffer_AddRef(object->streamSource[i]);
879 if(object->vertexShader) {
880 IWineD3DVertexShader_AddRef(object->vertexShader);
882 object->pIndexData = NULL;
883 object->pixelShader = NULL;
885 FIXME("Unrecognized state block type %d\n", Type);
888 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
892 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface,
893 UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level,
894 IWineD3DSurface **ppSurface, WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool,
895 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl, IUnknown *parent)
897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
898 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
899 unsigned int Size = 1;
900 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(Format, &GLINFO_LOCATION);
904 TRACE("(%p) Create surface\n",This);
906 if(MultisampleQuality > 0) {
907 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
908 MultisampleQuality=0;
911 /** FIXME: Check that the format is supported
913 *******************************/
915 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
916 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
918 *********************************/
919 mul_4w = (Width + 3) & ~3;
920 mul_4h = (Height + 3) & ~3;
921 if (WINED3DFMT_UNKNOWN == Format) {
923 } else if (Format == WINED3DFMT_DXT1) {
924 /* DXT1 is half byte per pixel */
925 Size = (mul_4w * glDesc->byte_count * mul_4h) >> 1;
927 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
928 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
929 Format == WINED3DFMT_ATI2N) {
930 Size = (mul_4w * glDesc->byte_count * mul_4h);
932 /* The pitch is a multiple of 4 bytes */
933 Size = ((Width * glDesc->byte_count) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
937 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
939 /** Create and initialise the surface resource **/
940 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
943 ERR("Out of memory\n");
945 return WINED3DERR_OUTOFVIDEOMEMORY;
948 /* Look at the implementation and set the correct Vtable */
952 /* Check if a 3D adapter is available when creating gl surfaces */
955 ERR("OpenGL surfaces are not available without opengl\n");
956 HeapFree(GetProcessHeap(), 0, object);
957 return WINED3DERR_NOTAVAILABLE;
959 object->lpVtbl = &IWineD3DSurface_Vtbl;
963 object->lpVtbl = &IWineGDISurface_Vtbl;
967 /* To be sure to catch this */
968 ERR("Unknown requested surface implementation %d!\n", Impl);
969 HeapFree(GetProcessHeap(), 0, object);
970 return WINED3DERR_INVALIDCALL;
973 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_SURFACE, This, Size, Usage, glDesc, Pool, parent);
976 WARN("Failed to initialize resource, returning %#x\n", hr);
977 HeapFree(GetProcessHeap(), 0, object);
982 TRACE("(%p) : Created resource %p\n", This, object);
984 *ppSurface = (IWineD3DSurface *)object;
986 /* "Standalone" surface */
987 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
989 object->currentDesc.Width = Width;
990 object->currentDesc.Height = Height;
991 object->currentDesc.MultiSampleType = MultiSample;
992 object->currentDesc.MultiSampleQuality = MultisampleQuality;
993 object->glDescription.level = Level;
994 list_init(&object->overlays);
997 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
998 object->Flags |= Discard ? SFLAG_DISCARD : 0;
999 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1000 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1002 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1004 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
1005 * this function is too deep to need to care about things like this.
1006 * Levels need to be checked too, and possibly Type since they all affect what can be done.
1007 * ****************************************/
1009 case WINED3DPOOL_SCRATCH:
1011 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
1012 "which are mutually exclusive, setting lockable to TRUE\n");
1015 case WINED3DPOOL_SYSTEMMEM:
1016 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
1017 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1018 case WINED3DPOOL_MANAGED:
1019 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
1020 "Usage of DYNAMIC which are mutually exclusive, not doing "
1021 "anything just telling you.\n");
1023 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1024 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1025 && !(Usage & WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1026 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1029 FIXME("(%p) Unknown pool %d\n", This, Pool);
1033 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1034 FIXME("Trying to create a render target that isn't in the default pool\n");
1037 /* mark the texture as dirty so that it gets loaded first time around*/
1038 surface_add_dirty_rect(*ppSurface, NULL);
1039 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1040 This, Width, Height, Format, debug_d3dformat(Format),
1041 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1043 list_init(&object->renderbuffers);
1045 /* Call the private setup routine */
1046 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)object);
1049 ERR("Private setup failed, returning %#x\n", hr);
1050 IWineD3DSurface_Release(*ppSurface);
1058 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1059 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
1061 struct wined3d_rendertarget_view *object;
1063 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1066 ERR("Failed to allocate memory\n");
1067 return E_OUTOFMEMORY;
1070 object->vtbl = &wined3d_rendertarget_view_vtbl;
1071 object->refcount = 1;
1072 IWineD3DResource_AddRef(resource);
1073 object->resource = resource;
1074 object->parent = parent;
1076 *rendertarget_view = (IWineD3DRendertargetView *)object;
1081 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1082 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1083 WINED3DPOOL Pool, IWineD3DTexture **ppTexture, IUnknown *parent)
1085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1086 IWineD3DTextureImpl *object;
1089 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1090 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1091 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1093 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1096 ERR("Out of memory\n");
1098 return WINED3DERR_OUTOFVIDEOMEMORY;
1101 object->lpVtbl = &IWineD3DTexture_Vtbl;
1103 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent);
1106 WARN("Failed to initialize texture, returning %#x\n", hr);
1107 HeapFree(GetProcessHeap(), 0, object);
1112 *ppTexture = (IWineD3DTexture *)object;
1114 TRACE("(%p) : Created texture %p\n", This, object);
1119 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1120 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1121 WINED3DPOOL Pool, IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent)
1123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1124 IWineD3DVolumeTextureImpl *object;
1127 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1128 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1130 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1133 ERR("Out of memory\n");
1134 *ppVolumeTexture = NULL;
1135 return WINED3DERR_OUTOFVIDEOMEMORY;
1138 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1139 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent);
1142 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1143 HeapFree(GetProcessHeap(), 0, object);
1144 *ppVolumeTexture = NULL;
1148 TRACE("(%p) : Created volume texture %p.\n", This, object);
1149 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1154 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1155 UINT Width, UINT Height, UINT Depth, DWORD Usage, WINED3DFORMAT Format,
1156 WINED3DPOOL Pool, IWineD3DVolume **ppVolume, IUnknown *parent)
1158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1159 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1160 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &GLINFO_LOCATION);
1163 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1164 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1165 return WINED3DERR_INVALIDCALL;
1168 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1171 ERR("Out of memory\n");
1173 return WINED3DERR_OUTOFVIDEOMEMORY;
1176 object->lpVtbl = &IWineD3DVolume_Vtbl;
1177 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_VOLUME, This,
1178 Width * Height * Depth * format_desc->byte_count, Usage, format_desc, Pool, parent);
1181 WARN("Failed to initialize resource, returning %#x\n", hr);
1182 HeapFree(GetProcessHeap(), 0, object);
1187 TRACE("(%p) : Created resource %p\n", This, object);
1189 *ppVolume = (IWineD3DVolume *)object;
1191 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1192 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1194 object->currentDesc.Width = Width;
1195 object->currentDesc.Height = Height;
1196 object->currentDesc.Depth = Depth;
1198 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1199 object->lockable = TRUE;
1200 object->locked = FALSE;
1201 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1202 object->dirty = TRUE;
1204 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1209 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1210 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1211 WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture, IUnknown *parent)
1213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1214 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1217 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1220 ERR("Out of memory\n");
1221 *ppCubeTexture = NULL;
1222 return WINED3DERR_OUTOFVIDEOMEMORY;
1225 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1226 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent);
1229 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1230 HeapFree(GetProcessHeap(), 0, object);
1231 *ppCubeTexture = NULL;
1235 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1236 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1241 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1243 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1244 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1245 const IWineD3DQueryVtbl *vtable;
1247 /* Just a check to see if we support this type of query */
1249 case WINED3DQUERYTYPE_OCCLUSION:
1250 TRACE("(%p) occlusion query\n", This);
1251 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1254 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1256 vtable = &IWineD3DOcclusionQuery_Vtbl;
1259 case WINED3DQUERYTYPE_EVENT:
1260 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1261 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1262 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1264 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1266 vtable = &IWineD3DEventQuery_Vtbl;
1270 case WINED3DQUERYTYPE_VCACHE:
1271 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1272 case WINED3DQUERYTYPE_VERTEXSTATS:
1273 case WINED3DQUERYTYPE_TIMESTAMP:
1274 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1275 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1276 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1277 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1278 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1279 case WINED3DQUERYTYPE_PIXELTIMINGS:
1280 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1281 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1283 /* Use the base Query vtable until we have a special one for each query */
1284 vtable = &IWineD3DQuery_Vtbl;
1285 FIXME("(%p) Unhandled query type %d\n", This, Type);
1287 if(NULL == ppQuery || hr != WINED3D_OK) {
1291 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1294 ERR("Out of memory\n");
1296 return WINED3DERR_OUTOFVIDEOMEMORY;
1299 object->lpVtbl = vtable;
1300 object->type = Type;
1301 object->state = QUERY_CREATED;
1302 object->wineD3DDevice = This;
1303 object->parent = parent;
1306 *ppQuery = (IWineD3DQuery *)object;
1308 /* allocated the 'extended' data based on the type of query requested */
1310 case WINED3DQUERYTYPE_OCCLUSION:
1311 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1312 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1314 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1315 TRACE("(%p) Allocating data for an occlusion query\n", This);
1317 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1319 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1323 case WINED3DQUERYTYPE_EVENT:
1324 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1325 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1327 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1329 if(GL_SUPPORT(APPLE_FENCE)) {
1330 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1331 checkGLcall("glGenFencesAPPLE");
1332 } else if(GL_SUPPORT(NV_FENCE)) {
1333 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1334 checkGLcall("glGenFencesNV");
1339 case WINED3DQUERYTYPE_VCACHE:
1340 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1341 case WINED3DQUERYTYPE_VERTEXSTATS:
1342 case WINED3DQUERYTYPE_TIMESTAMP:
1343 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1344 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1345 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1346 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1347 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1348 case WINED3DQUERYTYPE_PIXELTIMINGS:
1349 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1350 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1352 object->extendedData = 0;
1353 FIXME("(%p) Unhandled query type %d\n",This , Type);
1355 TRACE("(%p) : Created Query %p\n", This, object);
1359 /*****************************************************************************
1360 * IWineD3DDeviceImpl_SetupFullscreenWindow
1362 * Helper function that modifies a HWND's Style and ExStyle for proper
1366 * iface: Pointer to the IWineD3DDevice interface
1367 * window: Window to setup
1369 *****************************************************************************/
1370 static LONG fullscreen_style(LONG orig_style) {
1371 LONG style = orig_style;
1372 style &= ~WS_CAPTION;
1373 style &= ~WS_THICKFRAME;
1375 /* Make sure the window is managed, otherwise we won't get keyboard input */
1376 style |= WS_POPUP | WS_SYSMENU;
1381 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1382 LONG exStyle = orig_exStyle;
1384 /* Filter out window decorations */
1385 exStyle &= ~WS_EX_WINDOWEDGE;
1386 exStyle &= ~WS_EX_CLIENTEDGE;
1391 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1394 LONG style, exStyle;
1395 /* Don't do anything if an original style is stored.
1396 * That shouldn't happen
1398 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1399 if (This->style || This->exStyle) {
1400 ERR("(%p): Want to change the window parameters of HWND %p, but "
1401 "another style is stored for restoration afterwards\n", This, window);
1404 /* Get the parameters and save them */
1405 style = GetWindowLongW(window, GWL_STYLE);
1406 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1407 This->style = style;
1408 This->exStyle = exStyle;
1410 style = fullscreen_style(style);
1411 exStyle = fullscreen_exStyle(exStyle);
1413 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1414 This->style, This->exStyle, style, exStyle);
1416 SetWindowLongW(window, GWL_STYLE, style);
1417 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1419 /* Inform the window about the update. */
1420 SetWindowPos(window, HWND_TOP, 0, 0,
1421 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1424 /*****************************************************************************
1425 * IWineD3DDeviceImpl_RestoreWindow
1427 * Helper function that restores a windows' properties when taking it out
1428 * of fullscreen mode
1431 * iface: Pointer to the IWineD3DDevice interface
1432 * window: Window to setup
1434 *****************************************************************************/
1435 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1437 LONG style, exStyle;
1439 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1440 * switch, do nothing
1442 if (!This->style && !This->exStyle) return;
1444 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1445 This, window, This->style, This->exStyle);
1447 style = GetWindowLongW(window, GWL_STYLE);
1448 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1450 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1451 * Some applications change it before calling Reset() when switching between windowed and
1452 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1454 if(style == fullscreen_style(This->style) &&
1455 exStyle == fullscreen_style(This->exStyle)) {
1456 SetWindowLongW(window, GWL_STYLE, This->style);
1457 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1460 /* Delete the old values */
1464 /* Inform the window about the update */
1465 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1466 0, 0, 0, 0, /* Pos, Size, ignored */
1467 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1470 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1471 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1472 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1473 IUnknown *parent, WINED3DSURFTYPE surface_type)
1475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1478 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1480 IUnknown *bufferParent;
1481 BOOL displaymode_set = FALSE;
1482 WINED3DDISPLAYMODE Mode;
1483 const struct GlPixelFormatDesc *format_desc;
1485 TRACE("(%p) : Created Additional Swap Chain\n", This);
1487 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1488 * does a device hold a reference to a swap chain giving them a lifetime of the device
1489 * or does the swap chain notify the device of its destruction.
1490 *******************************/
1492 /* Check the params */
1493 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1494 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1495 return WINED3DERR_INVALIDCALL;
1496 } else if (pPresentationParameters->BackBufferCount > 1) {
1497 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");
1500 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1503 ERR("Out of memory\n");
1504 *ppSwapChain = NULL;
1505 return WINED3DERR_OUTOFVIDEOMEMORY;
1508 switch(surface_type) {
1510 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1512 case SURFACE_OPENGL:
1513 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1515 case SURFACE_UNKNOWN:
1516 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1517 HeapFree(GetProcessHeap(), 0, object);
1518 return WINED3DERR_INVALIDCALL;
1520 object->wineD3DDevice = This;
1521 object->parent = parent;
1524 *ppSwapChain = (IWineD3DSwapChain *)object;
1526 /*********************
1527 * Lookup the window Handle and the relating X window handle
1528 ********************/
1530 /* Setup hwnd we are using, plus which display this equates to */
1531 object->win_handle = pPresentationParameters->hDeviceWindow;
1532 if (!object->win_handle) {
1533 object->win_handle = This->createParms.hFocusWindow;
1535 if(!pPresentationParameters->Windowed && object->win_handle) {
1536 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1537 pPresentationParameters->BackBufferWidth,
1538 pPresentationParameters->BackBufferHeight);
1541 hDc = GetDC(object->win_handle);
1542 TRACE("Using hDc %p\n", hDc);
1545 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1546 return WINED3DERR_NOTAVAILABLE;
1549 /* Get info on the current display setup */
1550 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1551 object->orig_width = Mode.Width;
1552 object->orig_height = Mode.Height;
1553 object->orig_fmt = Mode.Format;
1554 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1556 if (pPresentationParameters->Windowed &&
1557 ((pPresentationParameters->BackBufferWidth == 0) ||
1558 (pPresentationParameters->BackBufferHeight == 0) ||
1559 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1562 GetClientRect(object->win_handle, &Rect);
1564 if (pPresentationParameters->BackBufferWidth == 0) {
1565 pPresentationParameters->BackBufferWidth = Rect.right;
1566 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1568 if (pPresentationParameters->BackBufferHeight == 0) {
1569 pPresentationParameters->BackBufferHeight = Rect.bottom;
1570 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1572 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1573 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1574 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1578 /* Put the correct figures in the presentation parameters */
1579 TRACE("Copying across presentation parameters\n");
1580 object->presentParms = *pPresentationParameters;
1582 TRACE("calling rendertarget CB\n");
1583 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1584 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1585 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1586 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1587 if (SUCCEEDED(hr)) {
1588 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1589 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1590 if(surface_type == SURFACE_OPENGL) {
1591 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1594 ERR("Failed to create the front buffer\n");
1598 /*********************
1599 * Windowed / Fullscreen
1600 *******************/
1603 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1604 * so we should really check to see if there is a fullscreen swapchain already
1605 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1606 **************************************/
1608 if (!pPresentationParameters->Windowed) {
1609 WINED3DDISPLAYMODE mode;
1612 /* Change the display settings */
1613 mode.Width = pPresentationParameters->BackBufferWidth;
1614 mode.Height = pPresentationParameters->BackBufferHeight;
1615 mode.Format = pPresentationParameters->BackBufferFormat;
1616 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1618 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1619 displaymode_set = TRUE;
1623 * Create an opengl context for the display visual
1624 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1625 * use different properties after that point in time. FIXME: How to handle when requested format
1626 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1627 * it chooses is identical to the one already being used!
1628 **********************************/
1629 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1631 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1632 if(!object->context) {
1633 ERR("Failed to create the context array\n");
1637 object->num_contexts = 1;
1639 if(surface_type == SURFACE_OPENGL) {
1640 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1641 if (!object->context[0]) {
1642 ERR("Failed to create a new context\n");
1643 hr = WINED3DERR_NOTAVAILABLE;
1646 TRACE("Context created (HWND=%p, glContext=%p)\n",
1647 object->win_handle, object->context[0]->glCtx);
1651 /*********************
1652 * Create the back, front and stencil buffers
1653 *******************/
1654 if(object->presentParms.BackBufferCount > 0) {
1657 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1658 if(!object->backBuffer) {
1659 ERR("Out of memory\n");
1664 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1665 TRACE("calling rendertarget CB\n");
1666 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1667 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1668 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1669 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1671 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1672 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1674 ERR("Cannot create new back buffer\n");
1677 if(surface_type == SURFACE_OPENGL) {
1679 glDrawBuffer(GL_BACK);
1680 checkGLcall("glDrawBuffer(GL_BACK)");
1685 object->backBuffer = NULL;
1687 /* Single buffering - draw to front buffer */
1688 if(surface_type == SURFACE_OPENGL) {
1690 glDrawBuffer(GL_FRONT);
1691 checkGLcall("glDrawBuffer(GL_FRONT)");
1696 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1697 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1698 TRACE("Creating depth stencil buffer\n");
1699 if (This->auto_depth_stencil_buffer == NULL ) {
1700 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1701 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1702 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1703 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1704 &This->auto_depth_stencil_buffer);
1705 if (SUCCEEDED(hr)) {
1706 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1708 ERR("Failed to create the auto depth stencil\n");
1714 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1716 TRACE("Created swapchain %p\n", object);
1717 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1721 if (displaymode_set) {
1725 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1728 /* Change the display settings */
1729 memset(&devmode, 0, sizeof(devmode));
1730 devmode.dmSize = sizeof(devmode);
1731 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1732 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1733 devmode.dmPelsWidth = object->orig_width;
1734 devmode.dmPelsHeight = object->orig_height;
1735 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1738 if (object->backBuffer) {
1740 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1741 if(object->backBuffer[i]) {
1742 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1743 IUnknown_Release(bufferParent); /* once for the get parent */
1744 if (IUnknown_Release(bufferParent) > 0) {
1745 FIXME("(%p) Something's still holding the back buffer\n",This);
1749 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1750 object->backBuffer = NULL;
1752 if(object->context && object->context[0])
1753 DestroyContext(This, object->context[0]);
1754 if(object->frontBuffer) {
1755 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1756 IUnknown_Release(bufferParent); /* once for the get parent */
1757 if (IUnknown_Release(bufferParent) > 0) {
1758 FIXME("(%p) Something's still holding the front buffer\n",This);
1761 HeapFree(GetProcessHeap(), 0, object);
1765 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1766 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1768 TRACE("(%p)\n", This);
1770 return This->NumberOfSwapChains;
1773 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1775 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1777 if(iSwapChain < This->NumberOfSwapChains) {
1778 *pSwapChain = This->swapchains[iSwapChain];
1779 IWineD3DSwapChain_AddRef(*pSwapChain);
1780 TRACE("(%p) returning %p\n", This, *pSwapChain);
1783 TRACE("Swapchain out of range\n");
1785 return WINED3DERR_INVALIDCALL;
1790 * Vertex Declaration
1792 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1793 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1795 IWineD3DVertexDeclarationImpl *object = NULL;
1796 HRESULT hr = WINED3D_OK;
1798 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1799 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1801 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1804 ERR("Out of memory\n");
1805 *ppVertexDeclaration = NULL;
1806 return WINED3DERR_OUTOFVIDEOMEMORY;
1809 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
1810 object->wineD3DDevice = This;
1811 object->parent = parent;
1814 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1816 hr = vertexdeclaration_init(object, elements, element_count);
1819 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1820 *ppVertexDeclaration = NULL;
1826 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1827 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1829 unsigned int idx, idx2;
1830 unsigned int offset;
1831 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1832 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1833 BOOL has_blend_idx = has_blend &&
1834 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1835 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1836 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1837 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1838 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1839 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1840 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1842 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1843 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1844 WINED3DVERTEXELEMENT *elements = NULL;
1847 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1848 if (has_blend_idx) num_blends--;
1850 /* Compute declaration size */
1851 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1852 has_psize + has_diffuse + has_specular + num_textures;
1854 /* convert the declaration */
1855 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1856 if (!elements) return ~0U;
1860 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1861 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1862 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1864 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1865 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1866 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1869 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1870 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1872 elements[idx].usage_idx = 0;
1875 if (has_blend && (num_blends > 0)) {
1876 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1877 elements[idx].format = WINED3DFMT_A8R8G8B8;
1879 switch(num_blends) {
1880 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1881 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1882 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1883 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1885 ERR("Unexpected amount of blend values: %u\n", num_blends);
1888 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1889 elements[idx].usage_idx = 0;
1892 if (has_blend_idx) {
1893 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1894 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1895 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1896 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1897 elements[idx].format = WINED3DFMT_A8R8G8B8;
1899 elements[idx].format = WINED3DFMT_R32_FLOAT;
1900 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1901 elements[idx].usage_idx = 0;
1905 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1906 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1907 elements[idx].usage_idx = 0;
1911 elements[idx].format = WINED3DFMT_R32_FLOAT;
1912 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1913 elements[idx].usage_idx = 0;
1917 elements[idx].format = WINED3DFMT_A8R8G8B8;
1918 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1919 elements[idx].usage_idx = 0;
1923 elements[idx].format = WINED3DFMT_A8R8G8B8;
1924 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1925 elements[idx].usage_idx = 1;
1928 for (idx2 = 0; idx2 < num_textures; idx2++) {
1929 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1930 switch (numcoords) {
1931 case WINED3DFVF_TEXTUREFORMAT1:
1932 elements[idx].format = WINED3DFMT_R32_FLOAT;
1934 case WINED3DFVF_TEXTUREFORMAT2:
1935 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1937 case WINED3DFVF_TEXTUREFORMAT3:
1938 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1940 case WINED3DFVF_TEXTUREFORMAT4:
1941 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1944 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1945 elements[idx].usage_idx = idx2;
1949 /* Now compute offsets, and initialize the rest of the fields */
1950 for (idx = 0, offset = 0; idx < size; ++idx)
1952 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1953 elements[idx].input_slot = 0;
1954 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1955 elements[idx].offset = offset;
1956 offset += format_desc->component_count * format_desc->component_size;
1959 *ppVertexElements = elements;
1963 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1964 WINED3DVERTEXELEMENT* elements = NULL;
1965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1969 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1970 if (size == ~0U) return WINED3DERR_OUTOFVIDEOMEMORY;
1972 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1973 HeapFree(GetProcessHeap(), 0, elements);
1974 if (hr != S_OK) return hr;
1979 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1980 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1981 IWineD3DVertexShader **ppVertexShader, IUnknown *parent)
1983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1984 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1985 HRESULT hr = WINED3D_OK;
1987 if (!pFunction) return WINED3DERR_INVALIDCALL;
1989 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1992 ERR("Out of memory\n");
1993 *ppVertexShader = NULL;
1994 return WINED3DERR_OUTOFVIDEOMEMORY;
1997 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
1998 object->parent = parent;
1999 shader_init(&object->baseShader, iface);
2000 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2001 *ppVertexShader = (IWineD3DVertexShader *)object;
2003 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
2005 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction, output_signature);
2008 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2009 IWineD3DVertexShader_Release(*ppVertexShader);
2010 *ppVertexShader = NULL;
2017 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
2018 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
2019 IWineD3DPixelShader **ppPixelShader, IUnknown *parent)
2021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2022 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2023 HRESULT hr = WINED3D_OK;
2025 if (!pFunction) return WINED3DERR_INVALIDCALL;
2027 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2030 ERR("Out of memory\n");
2031 *ppPixelShader = NULL;
2032 return WINED3DERR_OUTOFVIDEOMEMORY;
2035 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
2036 object->parent = parent;
2037 shader_init(&object->baseShader, iface);
2038 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2039 *ppPixelShader = (IWineD3DPixelShader *)object;
2041 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
2043 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction, output_signature);
2046 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2047 IWineD3DPixelShader_Release(*ppPixelShader);
2048 *ppPixelShader = NULL;
2055 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
2056 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
2058 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2059 IWineD3DPaletteImpl *object;
2061 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2063 /* Create the new object */
2064 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2066 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2067 return E_OUTOFMEMORY;
2070 object->lpVtbl = &IWineD3DPalette_Vtbl;
2072 object->Flags = Flags;
2073 object->parent = Parent;
2074 object->wineD3DDevice = This;
2075 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2076 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2079 HeapFree( GetProcessHeap(), 0, object);
2080 return E_OUTOFMEMORY;
2083 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2085 IWineD3DPalette_Release((IWineD3DPalette *) object);
2089 *Palette = (IWineD3DPalette *) object;
2094 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2098 HDC dcb = NULL, dcs = NULL;
2099 WINEDDCOLORKEY colorkey;
2101 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2104 GetObjectA(hbm, sizeof(BITMAP), &bm);
2105 dcb = CreateCompatibleDC(NULL);
2107 SelectObject(dcb, hbm);
2111 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2112 * couldn't be loaded
2114 memset(&bm, 0, sizeof(bm));
2119 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2120 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2121 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL);
2123 ERR("Wine logo requested, but failed to create surface\n");
2128 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2129 if(FAILED(hr)) goto out;
2130 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2131 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2133 colorkey.dwColorSpaceLowValue = 0;
2134 colorkey.dwColorSpaceHighValue = 0;
2135 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2137 /* Fill the surface with a white color to show that wined3d is there */
2138 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2151 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2153 /* Under DirectX you can have texture stage operations even if no texture is
2154 bound, whereas opengl will only do texture operations when a valid texture is
2155 bound. We emulate this by creating dummy textures and binding them to each
2156 texture stage, but disable all stages by default. Hence if a stage is enabled
2157 then the default texture will kick in until replaced by a SetTexture call */
2160 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2161 /* The dummy texture does not have client storage backing */
2162 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2163 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2165 for (i = 0; i < GL_LIMITS(textures); i++) {
2166 GLubyte white = 255;
2168 /* Make appropriate texture active */
2169 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2170 checkGLcall("glActiveTextureARB");
2172 /* Generate an opengl texture name */
2173 glGenTextures(1, &This->dummyTextureName[i]);
2174 checkGLcall("glGenTextures");
2175 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2177 /* Generate a dummy 2d texture (not using 1d because they cause many
2178 * DRI drivers fall back to sw) */
2179 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2180 checkGLcall("glBindTexture");
2182 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2183 checkGLcall("glTexImage2D");
2185 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2186 /* Reenable because if supported it is enabled by default */
2187 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2188 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2194 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2195 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2198 IWineD3DSwapChainImpl *swapchain = NULL;
2203 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2205 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2206 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2208 /* TODO: Test if OpenGL is compiled in and loaded */
2210 TRACE("(%p) : Creating stateblock\n", This);
2211 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2212 hr = IWineD3DDevice_CreateStateBlock(iface,
2214 (IWineD3DStateBlock **)&This->stateBlock,
2216 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2217 WARN("Failed to create stateblock\n");
2220 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2221 This->updateStateBlock = This->stateBlock;
2222 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2224 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2225 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2227 This->NumberOfPalettes = 1;
2228 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2229 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2230 ERR("Out of memory!\n");
2233 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2234 if(!This->palettes[0]) {
2235 ERR("Out of memory!\n");
2238 for (i = 0; i < 256; ++i) {
2239 This->palettes[0][i].peRed = 0xFF;
2240 This->palettes[0][i].peGreen = 0xFF;
2241 This->palettes[0][i].peBlue = 0xFF;
2242 This->palettes[0][i].peFlags = 0xFF;
2244 This->currentPalette = 0;
2246 /* Initialize the texture unit mapping to a 1:1 mapping */
2247 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2248 if (state < GL_LIMITS(fragment_samplers)) {
2249 This->texUnitMap[state] = state;
2250 This->rev_tex_unit_map[state] = state;
2252 This->texUnitMap[state] = -1;
2253 This->rev_tex_unit_map[state] = -1;
2257 /* Setup the implicit swapchain */
2258 TRACE("Creating implicit swapchain\n");
2259 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2260 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2263 WARN("Failed to create implicit swapchain\n");
2267 This->NumberOfSwapChains = 1;
2268 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2269 if(!This->swapchains) {
2270 ERR("Out of memory!\n");
2273 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2275 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2276 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2277 This->render_targets[0] = swapchain->backBuffer[0];
2278 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2281 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2282 This->render_targets[0] = swapchain->frontBuffer;
2283 This->lastActiveRenderTarget = swapchain->frontBuffer;
2285 IWineD3DSurface_AddRef(This->render_targets[0]);
2286 This->activeContext = swapchain->context[0];
2287 This->lastThread = GetCurrentThreadId();
2289 /* Depth Stencil support */
2290 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2291 if (NULL != This->stencilBufferTarget) {
2292 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2295 hr = This->shader_backend->shader_alloc_private(iface);
2297 TRACE("Shader private data couldn't be allocated\n");
2300 hr = This->frag_pipe->alloc_private(iface);
2302 TRACE("Fragment pipeline private data couldn't be allocated\n");
2305 hr = This->blitter->alloc_private(iface);
2307 TRACE("Blitter private data couldn't be allocated\n");
2311 /* Set up some starting GL setup */
2313 /* Setup all the devices defaults */
2314 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2315 create_dummy_textures(This);
2319 /* Initialize the current view state */
2320 This->view_ident = 1;
2321 This->contexts[0]->last_was_rhw = 0;
2322 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2323 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2325 switch(wined3d_settings.offscreen_rendering_mode) {
2328 This->offscreenBuffer = GL_BACK;
2331 case ORM_BACKBUFFER:
2333 if(This->activeContext->aux_buffers > 0) {
2334 TRACE("Using auxilliary buffer for offscreen rendering\n");
2335 This->offscreenBuffer = GL_AUX0;
2337 TRACE("Using back buffer for offscreen rendering\n");
2338 This->offscreenBuffer = GL_BACK;
2343 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2346 /* Clear the screen */
2347 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2348 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2351 This->d3d_initialized = TRUE;
2353 if(wined3d_settings.logo) {
2354 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2356 This->highest_dirty_ps_const = 0;
2357 This->highest_dirty_vs_const = 0;
2361 HeapFree(GetProcessHeap(), 0, This->render_targets);
2362 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2363 HeapFree(GetProcessHeap(), 0, This->swapchains);
2364 This->NumberOfSwapChains = 0;
2365 if(This->palettes) {
2366 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2367 HeapFree(GetProcessHeap(), 0, This->palettes);
2369 This->NumberOfPalettes = 0;
2371 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2373 if(This->stateBlock) {
2374 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2375 This->stateBlock = NULL;
2377 if (This->blit_priv) {
2378 This->blitter->free_private(iface);
2380 if (This->fragment_priv) {
2381 This->frag_pipe->free_private(iface);
2383 if (This->shader_priv) {
2384 This->shader_backend->shader_free_private(iface);
2389 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2390 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2393 IWineD3DSwapChainImpl *swapchain = NULL;
2396 /* Setup the implicit swapchain */
2397 TRACE("Creating implicit swapchain\n");
2398 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2399 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2402 WARN("Failed to create implicit swapchain\n");
2406 This->NumberOfSwapChains = 1;
2407 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2408 if(!This->swapchains) {
2409 ERR("Out of memory!\n");
2412 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2416 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2420 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2422 IWineD3DResource_UnLoad(resource);
2423 IWineD3DResource_Release(resource);
2427 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2431 TRACE("(%p)\n", This);
2433 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2435 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2436 * it was created. Thus make sure a context is active for the glDelete* calls
2438 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2440 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2442 /* Unload resources */
2443 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2445 TRACE("Deleting high order patches\n");
2446 for(i = 0; i < PATCHMAP_SIZE; i++) {
2447 struct list *e1, *e2;
2448 struct WineD3DRectPatch *patch;
2449 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2450 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2451 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2455 /* Delete the palette conversion shader if it is around */
2456 if(This->paletteConversionShader) {
2458 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2460 This->paletteConversionShader = 0;
2463 /* Delete the pbuffer context if there is any */
2464 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2466 /* Delete the mouse cursor texture */
2467 if(This->cursorTexture) {
2469 glDeleteTextures(1, &This->cursorTexture);
2471 This->cursorTexture = 0;
2474 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2475 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2477 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2478 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2481 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2482 * private data, it might contain opengl pointers
2484 if(This->depth_blt_texture) {
2486 glDeleteTextures(1, &This->depth_blt_texture);
2488 This->depth_blt_texture = 0;
2490 if (This->depth_blt_rb) {
2492 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2494 This->depth_blt_rb = 0;
2495 This->depth_blt_rb_w = 0;
2496 This->depth_blt_rb_h = 0;
2499 /* Release the update stateblock */
2500 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2501 if(This->updateStateBlock != This->stateBlock)
2502 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2504 This->updateStateBlock = NULL;
2506 { /* because were not doing proper internal refcounts releasing the primary state block
2507 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2508 to set this->stateBlock = NULL; first */
2509 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2510 This->stateBlock = NULL;
2512 /* Release the stateblock */
2513 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2514 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2518 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2519 This->blitter->free_private(iface);
2520 This->frag_pipe->free_private(iface);
2521 This->shader_backend->shader_free_private(iface);
2523 /* Release the buffers (with sanity checks)*/
2524 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2525 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2526 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2527 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2529 This->stencilBufferTarget = NULL;
2531 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2532 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2533 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2535 TRACE("Setting rendertarget to NULL\n");
2536 This->render_targets[0] = NULL;
2538 if (This->auto_depth_stencil_buffer) {
2539 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2540 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2542 This->auto_depth_stencil_buffer = NULL;
2545 for(i=0; i < This->NumberOfSwapChains; i++) {
2546 TRACE("Releasing the implicit swapchain %d\n", i);
2547 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2548 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2552 HeapFree(GetProcessHeap(), 0, This->swapchains);
2553 This->swapchains = NULL;
2554 This->NumberOfSwapChains = 0;
2556 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2557 HeapFree(GetProcessHeap(), 0, This->palettes);
2558 This->palettes = NULL;
2559 This->NumberOfPalettes = 0;
2561 HeapFree(GetProcessHeap(), 0, This->render_targets);
2562 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2563 This->render_targets = NULL;
2564 This->draw_buffers = NULL;
2566 This->d3d_initialized = FALSE;
2570 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2574 for(i=0; i < This->NumberOfSwapChains; i++) {
2575 TRACE("Releasing the implicit swapchain %d\n", i);
2576 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2577 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2581 HeapFree(GetProcessHeap(), 0, This->swapchains);
2582 This->swapchains = NULL;
2583 This->NumberOfSwapChains = 0;
2587 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2588 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2589 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2591 * There is no way to deactivate thread safety once it is enabled.
2593 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2596 /*For now just store the flag(needed in case of ddraw) */
2597 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2602 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2603 const WINED3DDISPLAYMODE* pMode) {
2605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2607 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2610 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2612 /* Resize the screen even without a window:
2613 * The app could have unset it with SetCooperativeLevel, but not called
2614 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2615 * but we don't have any hwnd
2618 memset(&devmode, 0, sizeof(devmode));
2619 devmode.dmSize = sizeof(devmode);
2620 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2621 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2622 devmode.dmPelsWidth = pMode->Width;
2623 devmode.dmPelsHeight = pMode->Height;
2625 devmode.dmDisplayFrequency = pMode->RefreshRate;
2626 if (pMode->RefreshRate != 0) {
2627 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2630 /* Only change the mode if necessary */
2631 if( (This->ddraw_width == pMode->Width) &&
2632 (This->ddraw_height == pMode->Height) &&
2633 (This->ddraw_format == pMode->Format) &&
2634 (pMode->RefreshRate == 0) ) {
2638 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2639 if (ret != DISP_CHANGE_SUCCESSFUL) {
2640 if(devmode.dmDisplayFrequency != 0) {
2641 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2642 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2643 devmode.dmDisplayFrequency = 0;
2644 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2646 if(ret != DISP_CHANGE_SUCCESSFUL) {
2647 return WINED3DERR_NOTAVAILABLE;
2651 /* Store the new values */
2652 This->ddraw_width = pMode->Width;
2653 This->ddraw_height = pMode->Height;
2654 This->ddraw_format = pMode->Format;
2656 /* And finally clip mouse to our screen */
2657 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2658 ClipCursor(&clip_rc);
2663 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2665 *ppD3D= This->wineD3D;
2666 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2667 IWineD3D_AddRef(*ppD3D);
2671 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2674 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2675 (This->adapter->TextureRam/(1024*1024)),
2676 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2677 /* return simulated texture memory left */
2678 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2682 * Get / Set Stream Source
2684 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2685 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2688 IWineD3DBuffer *oldSrc;
2690 if (StreamNumber >= MAX_STREAMS) {
2691 WARN("Stream out of range %d\n", StreamNumber);
2692 return WINED3DERR_INVALIDCALL;
2693 } else if(OffsetInBytes & 0x3) {
2694 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2695 return WINED3DERR_INVALIDCALL;
2698 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2699 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2701 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2703 if(oldSrc == pStreamData &&
2704 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2705 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2706 TRACE("Application is setting the old values over, nothing to do\n");
2710 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2712 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2713 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2716 /* Handle recording of state blocks */
2717 if (This->isRecordingState) {
2718 TRACE("Recording... not performing anything\n");
2719 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2720 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2724 if (pStreamData != NULL) {
2725 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2726 IWineD3DBuffer_AddRef(pStreamData);
2728 if (oldSrc != NULL) {
2729 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2730 IWineD3DBuffer_Release(oldSrc);
2733 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2738 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2739 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2743 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2744 This->stateBlock->streamSource[StreamNumber],
2745 This->stateBlock->streamOffset[StreamNumber],
2746 This->stateBlock->streamStride[StreamNumber]);
2748 if (StreamNumber >= MAX_STREAMS) {
2749 WARN("Stream out of range %d\n", StreamNumber);
2750 return WINED3DERR_INVALIDCALL;
2752 *pStream = This->stateBlock->streamSource[StreamNumber];
2753 *pStride = This->stateBlock->streamStride[StreamNumber];
2755 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2758 if (*pStream != NULL) {
2759 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2764 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2765 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2766 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2767 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2769 /* Verify input at least in d3d9 this is invalid*/
2770 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2771 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2772 return WINED3DERR_INVALIDCALL;
2774 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2775 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2776 return WINED3DERR_INVALIDCALL;
2779 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2780 return WINED3DERR_INVALIDCALL;
2783 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2784 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2786 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2787 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2789 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2790 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2791 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2797 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2800 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2801 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2803 TRACE("(%p) : returning %d\n", This, *Divider);
2809 * Get / Set & Multiply Transform
2811 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2814 /* Most of this routine, comments included copied from ddraw tree initially: */
2815 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2817 /* Handle recording of state blocks */
2818 if (This->isRecordingState) {
2819 TRACE("Recording... not performing anything\n");
2820 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2821 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2826 * If the new matrix is the same as the current one,
2827 * we cut off any further processing. this seems to be a reasonable
2828 * optimization because as was noticed, some apps (warcraft3 for example)
2829 * tend towards setting the same matrix repeatedly for some reason.
2831 * From here on we assume that the new matrix is different, wherever it matters.
2833 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2834 TRACE("The app is setting the same matrix over again\n");
2837 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2841 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2842 where ViewMat = Camera space, WorldMat = world space.
2844 In OpenGL, camera and world space is combined into GL_MODELVIEW
2845 matrix. The Projection matrix stay projection matrix.
2848 /* Capture the times we can just ignore the change for now */
2849 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2850 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2851 /* Handled by the state manager */
2854 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2858 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2860 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2861 *pMatrix = This->stateBlock->transforms[State];
2865 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2866 const WINED3DMATRIX *mat = NULL;
2869 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2870 * below means it will be recorded in a state block change, but it
2871 * works regardless where it is recorded.
2872 * If this is found to be wrong, change to StateBlock.
2874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2875 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2877 if (State <= HIGHEST_TRANSFORMSTATE)
2879 mat = &This->updateStateBlock->transforms[State];
2881 FIXME("Unhandled transform state!!\n");
2884 multiply_matrix(&temp, mat, pMatrix);
2886 /* Apply change via set transform - will reapply to eg. lights this way */
2887 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2893 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2894 you can reference any indexes you want as long as that number max are enabled at any
2895 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2896 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2897 but when recording, just build a chain pretty much of commands to be replayed. */
2899 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2901 PLIGHTINFOEL *object = NULL;
2902 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2906 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2908 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2912 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2913 return WINED3DERR_INVALIDCALL;
2916 switch(pLight->Type) {
2917 case WINED3DLIGHT_POINT:
2918 case WINED3DLIGHT_SPOT:
2919 case WINED3DLIGHT_PARALLELPOINT:
2920 case WINED3DLIGHT_GLSPOT:
2921 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2924 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2925 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2926 return WINED3DERR_INVALIDCALL;
2930 case WINED3DLIGHT_DIRECTIONAL:
2931 /* Ignores attenuation */
2935 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2936 return WINED3DERR_INVALIDCALL;
2939 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2940 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2941 if(object->OriginalIndex == Index) break;
2946 TRACE("Adding new light\n");
2947 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2949 ERR("Out of memory error when allocating a light\n");
2950 return E_OUTOFMEMORY;
2952 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2953 object->glIndex = -1;
2954 object->OriginalIndex = Index;
2955 object->changed = TRUE;
2958 /* Initialize the object */
2959 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,
2960 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2961 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2962 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2963 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2964 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2965 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2967 /* Save away the information */
2968 object->OriginalParms = *pLight;
2970 switch (pLight->Type) {
2971 case WINED3DLIGHT_POINT:
2973 object->lightPosn[0] = pLight->Position.x;
2974 object->lightPosn[1] = pLight->Position.y;
2975 object->lightPosn[2] = pLight->Position.z;
2976 object->lightPosn[3] = 1.0f;
2977 object->cutoff = 180.0f;
2981 case WINED3DLIGHT_DIRECTIONAL:
2983 object->lightPosn[0] = -pLight->Direction.x;
2984 object->lightPosn[1] = -pLight->Direction.y;
2985 object->lightPosn[2] = -pLight->Direction.z;
2986 object->lightPosn[3] = 0.0;
2987 object->exponent = 0.0f;
2988 object->cutoff = 180.0f;
2991 case WINED3DLIGHT_SPOT:
2993 object->lightPosn[0] = pLight->Position.x;
2994 object->lightPosn[1] = pLight->Position.y;
2995 object->lightPosn[2] = pLight->Position.z;
2996 object->lightPosn[3] = 1.0;
2999 object->lightDirn[0] = pLight->Direction.x;
3000 object->lightDirn[1] = pLight->Direction.y;
3001 object->lightDirn[2] = pLight->Direction.z;
3002 object->lightDirn[3] = 1.0;
3005 * opengl-ish and d3d-ish spot lights use too different models for the
3006 * light "intensity" as a function of the angle towards the main light direction,
3007 * so we only can approximate very roughly.
3008 * however spot lights are rather rarely used in games (if ever used at all).
3009 * furthermore if still used, probably nobody pays attention to such details.
3011 if (pLight->Falloff == 0) {
3012 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3013 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3014 * will always be 1.0 for both of them, and we don't have to care for the
3015 * rest of the rather complex calculation
3017 object->exponent = 0;
3019 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
3020 if (rho < 0.0001) rho = 0.0001f;
3021 object->exponent = -0.3/log(cos(rho/2));
3023 if (object->exponent > 128.0) {
3024 object->exponent = 128.0;
3026 object->cutoff = pLight->Phi*90/M_PI;
3032 FIXME("Unrecognized light type %d\n", pLight->Type);
3035 /* Update the live definitions if the light is currently assigned a glIndex */
3036 if (object->glIndex != -1 && !This->isRecordingState) {
3037 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
3042 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
3043 PLIGHTINFOEL *lightInfo = NULL;
3044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3045 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
3047 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
3049 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3050 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3051 if(lightInfo->OriginalIndex == Index) break;
3055 if (lightInfo == NULL) {
3056 TRACE("Light information requested but light not defined\n");
3057 return WINED3DERR_INVALIDCALL;
3060 *pLight = lightInfo->OriginalParms;
3065 * Get / Set Light Enable
3066 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3068 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
3069 PLIGHTINFOEL *lightInfo = NULL;
3070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3071 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3073 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
3075 /* Tests show true = 128...not clear why */
3076 Enable = Enable? 128: 0;
3078 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3079 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3080 if(lightInfo->OriginalIndex == Index) break;
3083 TRACE("Found light: %p\n", lightInfo);
3085 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3086 if (lightInfo == NULL) {
3088 TRACE("Light enabled requested but light not defined, so defining one!\n");
3089 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3091 /* Search for it again! Should be fairly quick as near head of list */
3092 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3093 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3094 if(lightInfo->OriginalIndex == Index) break;
3097 if (lightInfo == NULL) {
3098 FIXME("Adding default lights has failed dismally\n");
3099 return WINED3DERR_INVALIDCALL;
3103 lightInfo->enabledChanged = TRUE;
3105 if(lightInfo->glIndex != -1) {
3106 if(!This->isRecordingState) {
3107 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3110 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3111 lightInfo->glIndex = -1;
3113 TRACE("Light already disabled, nothing to do\n");
3115 lightInfo->enabled = FALSE;
3117 lightInfo->enabled = TRUE;
3118 if (lightInfo->glIndex != -1) {
3120 TRACE("Nothing to do as light was enabled\n");
3123 /* Find a free gl light */
3124 for(i = 0; i < This->maxConcurrentLights; i++) {
3125 if(This->updateStateBlock->activeLights[i] == NULL) {
3126 This->updateStateBlock->activeLights[i] = lightInfo;
3127 lightInfo->glIndex = i;
3131 if(lightInfo->glIndex == -1) {
3132 /* Our tests show that Windows returns D3D_OK in this situation, even with
3133 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3134 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3135 * as well for those lights.
3137 * TODO: Test how this affects rendering
3139 WARN("Too many concurrently active lights\n");
3143 /* i == lightInfo->glIndex */
3144 if(!This->isRecordingState) {
3145 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3153 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3155 PLIGHTINFOEL *lightInfo = NULL;
3156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3158 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3159 TRACE("(%p) : for idx(%d)\n", This, Index);
3161 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3162 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3163 if(lightInfo->OriginalIndex == Index) break;
3167 if (lightInfo == NULL) {
3168 TRACE("Light enabled state requested but light not defined\n");
3169 return WINED3DERR_INVALIDCALL;
3171 /* true is 128 according to SetLightEnable */
3172 *pEnable = lightInfo->enabled ? 128 : 0;
3177 * Get / Set Clip Planes
3179 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3181 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3183 /* Validate Index */
3184 if (Index >= GL_LIMITS(clipplanes)) {
3185 TRACE("Application has requested clipplane this device doesn't support\n");
3186 return WINED3DERR_INVALIDCALL;
3189 This->updateStateBlock->changed.clipplane |= 1 << Index;
3191 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3192 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3193 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3194 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3195 TRACE("Application is setting old values over, nothing to do\n");
3199 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3200 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3201 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3202 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3204 /* Handle recording of state blocks */
3205 if (This->isRecordingState) {
3206 TRACE("Recording... not performing anything\n");
3210 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3215 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3217 TRACE("(%p) : for idx %d\n", This, Index);
3219 /* Validate Index */
3220 if (Index >= GL_LIMITS(clipplanes)) {
3221 TRACE("Application has requested clipplane this device doesn't support\n");
3222 return WINED3DERR_INVALIDCALL;
3225 pPlane[0] = This->stateBlock->clipplane[Index][0];
3226 pPlane[1] = This->stateBlock->clipplane[Index][1];
3227 pPlane[2] = This->stateBlock->clipplane[Index][2];
3228 pPlane[3] = This->stateBlock->clipplane[Index][3];
3233 * Get / Set Clip Plane Status
3234 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3236 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3238 FIXME("(%p) : stub\n", This);
3239 if (NULL == pClipStatus) {
3240 return WINED3DERR_INVALIDCALL;
3242 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3243 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3247 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3249 FIXME("(%p) : stub\n", This);
3250 if (NULL == pClipStatus) {
3251 return WINED3DERR_INVALIDCALL;
3253 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3254 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3259 * Get / Set Material
3261 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3264 This->updateStateBlock->changed.material = TRUE;
3265 This->updateStateBlock->material = *pMaterial;
3267 /* Handle recording of state blocks */
3268 if (This->isRecordingState) {
3269 TRACE("Recording... not performing anything\n");
3273 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3277 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3279 *pMaterial = This->updateStateBlock->material;
3280 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3281 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3282 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3283 pMaterial->Ambient.b, pMaterial->Ambient.a);
3284 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3285 pMaterial->Specular.b, pMaterial->Specular.a);
3286 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3287 pMaterial->Emissive.b, pMaterial->Emissive.a);
3288 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3296 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DBuffer* pIndexData, WINED3DFORMAT fmt) {
3297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3298 IWineD3DBuffer *oldIdxs;
3300 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3301 oldIdxs = This->updateStateBlock->pIndexData;
3303 This->updateStateBlock->changed.indices = TRUE;
3304 This->updateStateBlock->pIndexData = pIndexData;
3305 This->updateStateBlock->IndexFmt = fmt;
3307 /* Handle recording of state blocks */
3308 if (This->isRecordingState) {
3309 TRACE("Recording... not performing anything\n");
3310 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3311 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3315 if(oldIdxs != pIndexData) {
3316 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3318 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3319 IWineD3DBuffer_AddRef(pIndexData);
3322 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3323 IWineD3DBuffer_Release(oldIdxs);
3330 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DBuffer** ppIndexData) {
3331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3333 *ppIndexData = This->stateBlock->pIndexData;
3335 /* up ref count on ppindexdata */
3337 IWineD3DBuffer_AddRef(*ppIndexData);
3338 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3340 TRACE("(%p) No index data set\n", This);
3342 TRACE("Returning %p\n", *ppIndexData);
3347 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3348 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3350 TRACE("(%p)->(%d)\n", This, BaseIndex);
3352 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3353 TRACE("Application is setting the old value over, nothing to do\n");
3357 This->updateStateBlock->baseVertexIndex = BaseIndex;
3359 if (This->isRecordingState) {
3360 TRACE("Recording... not performing anything\n");
3363 /* The base vertex index affects the stream sources */
3364 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3368 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3370 TRACE("(%p) : base_index %p\n", This, base_index);
3372 *base_index = This->stateBlock->baseVertexIndex;
3374 TRACE("Returning %u\n", *base_index);
3380 * Get / Set Viewports
3382 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3385 TRACE("(%p)\n", This);
3386 This->updateStateBlock->changed.viewport = TRUE;
3387 This->updateStateBlock->viewport = *pViewport;
3389 /* Handle recording of state blocks */
3390 if (This->isRecordingState) {
3391 TRACE("Recording... not performing anything\n");
3395 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3396 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3398 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3403 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3405 TRACE("(%p)\n", This);
3406 *pViewport = This->stateBlock->viewport;
3411 * Get / Set Render States
3412 * TODO: Verify against dx9 definitions
3414 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3417 DWORD oldValue = This->stateBlock->renderState[State];
3419 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3421 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3422 This->updateStateBlock->renderState[State] = Value;
3424 /* Handle recording of state blocks */
3425 if (This->isRecordingState) {
3426 TRACE("Recording... not performing anything\n");
3430 /* Compared here and not before the assignment to allow proper stateblock recording */
3431 if(Value == oldValue) {
3432 TRACE("Application is setting the old value over, nothing to do\n");
3434 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3440 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3442 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3443 *pValue = This->stateBlock->renderState[State];
3448 * Get / Set Sampler States
3449 * TODO: Verify against dx9 definitions
3452 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3456 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3457 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3459 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3460 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3463 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3464 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3465 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3468 * SetSampler is designed to allow for more than the standard up to 8 textures
3469 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3470 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3472 * http://developer.nvidia.com/object/General_FAQ.html#t6
3474 * There are two new settings for GForce
3476 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3477 * and the texture one:
3478 * GL_MAX_TEXTURE_COORDS_ARB.
3479 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3482 oldValue = This->stateBlock->samplerState[Sampler][Type];
3483 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3484 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3486 /* Handle recording of state blocks */
3487 if (This->isRecordingState) {
3488 TRACE("Recording... not performing anything\n");
3492 if(oldValue == Value) {
3493 TRACE("Application is setting the old value over, nothing to do\n");
3497 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3502 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3505 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3506 This, Sampler, debug_d3dsamplerstate(Type), Type);
3508 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3509 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3512 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3513 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3514 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3516 *Value = This->stateBlock->samplerState[Sampler][Type];
3517 TRACE("(%p) : Returning %#x\n", This, *Value);
3522 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3525 This->updateStateBlock->changed.scissorRect = TRUE;
3526 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3527 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3530 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3532 if(This->isRecordingState) {
3533 TRACE("Recording... not performing anything\n");
3537 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3542 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3545 *pRect = This->updateStateBlock->scissorRect;
3546 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3550 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3552 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3554 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3556 This->updateStateBlock->vertexDecl = pDecl;
3557 This->updateStateBlock->changed.vertexDecl = TRUE;
3559 if (This->isRecordingState) {
3560 TRACE("Recording... not performing anything\n");
3562 } else if(pDecl == oldDecl) {
3563 /* Checked after the assignment to allow proper stateblock recording */
3564 TRACE("Application is setting the old declaration over, nothing to do\n");
3568 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3572 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3575 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3577 *ppDecl = This->stateBlock->vertexDecl;
3578 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3582 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3584 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3586 This->updateStateBlock->vertexShader = pShader;
3587 This->updateStateBlock->changed.vertexShader = TRUE;
3589 if (This->isRecordingState) {
3590 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3591 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3592 TRACE("Recording... not performing anything\n");
3594 } else if(oldShader == pShader) {
3595 /* Checked here to allow proper stateblock recording */
3596 TRACE("App is setting the old shader over, nothing to do\n");
3600 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3601 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3602 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3604 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3609 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3612 if (NULL == ppShader) {
3613 return WINED3DERR_INVALIDCALL;
3615 *ppShader = This->stateBlock->vertexShader;
3616 if( NULL != *ppShader)
3617 IWineD3DVertexShader_AddRef(*ppShader);
3619 TRACE("(%p) : returning %p\n", This, *ppShader);
3623 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3624 IWineD3DDevice *iface,
3626 CONST BOOL *srcData,
3629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3630 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3632 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3633 iface, srcData, start, count);
3635 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3637 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3638 for (i = 0; i < cnt; i++)
3639 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3641 for (i = start; i < cnt + start; ++i) {
3642 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3645 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3650 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3651 IWineD3DDevice *iface,
3656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3657 int cnt = min(count, MAX_CONST_B - start);
3659 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3660 iface, dstData, start, count);
3662 if (dstData == NULL || cnt < 0)
3663 return WINED3DERR_INVALIDCALL;
3665 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3669 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3670 IWineD3DDevice *iface,
3675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3676 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3678 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3679 iface, srcData, start, count);
3681 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3683 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3684 for (i = 0; i < cnt; i++)
3685 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3686 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3688 for (i = start; i < cnt + start; ++i) {
3689 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3692 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3697 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3698 IWineD3DDevice *iface,
3703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3704 int cnt = min(count, MAX_CONST_I - start);
3706 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3707 iface, dstData, start, count);
3709 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3710 return WINED3DERR_INVALIDCALL;
3712 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3716 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3717 IWineD3DDevice *iface,
3719 CONST float *srcData,
3722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3725 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3726 iface, srcData, start, count);
3728 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3729 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3730 return WINED3DERR_INVALIDCALL;
3732 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3734 for (i = 0; i < count; i++)
3735 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3736 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3739 if (!This->isRecordingState)
3741 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3742 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3745 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3746 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3751 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3752 IWineD3DDevice *iface,
3757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3758 int cnt = min(count, This->d3d_vshader_constantF - start);
3760 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3761 iface, dstData, start, count);
3763 if (dstData == NULL || cnt < 0)
3764 return WINED3DERR_INVALIDCALL;
3766 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3770 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3772 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3774 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3778 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3779 int i = This->rev_tex_unit_map[unit];
3780 int j = This->texUnitMap[stage];
3782 This->texUnitMap[stage] = unit;
3783 if (i != -1 && i != stage) {
3784 This->texUnitMap[i] = -1;
3787 This->rev_tex_unit_map[unit] = stage;
3788 if (j != -1 && j != unit) {
3789 This->rev_tex_unit_map[j] = -1;
3793 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3796 This->fixed_function_usage_map = 0;
3797 for (i = 0; i < MAX_TEXTURES; ++i) {
3798 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3799 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3800 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3801 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3802 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3803 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3804 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3805 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3807 if (color_op == WINED3DTOP_DISABLE) {
3808 /* Not used, and disable higher stages */
3812 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3813 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3814 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3815 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3816 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3817 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3818 This->fixed_function_usage_map |= (1 << i);
3821 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3822 This->fixed_function_usage_map |= (1 << (i + 1));
3827 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3828 unsigned int i, tex;
3831 device_update_fixed_function_usage_map(This);
3832 ffu_map = This->fixed_function_usage_map;
3834 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3835 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3836 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3838 if (!(ffu_map & 1)) continue;
3840 if (This->texUnitMap[i] != i) {
3841 device_map_stage(This, i, i);
3842 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3843 markTextureStagesDirty(This, i);
3849 /* Now work out the mapping */
3851 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3853 if (!(ffu_map & 1)) continue;
3855 if (This->texUnitMap[i] != tex) {
3856 device_map_stage(This, i, tex);
3857 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3858 markTextureStagesDirty(This, i);
3865 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3866 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3867 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3870 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3871 if (sampler_type[i] && This->texUnitMap[i] != i)
3873 device_map_stage(This, i, i);
3874 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3875 if (i < MAX_TEXTURES) {
3876 markTextureStagesDirty(This, i);
3882 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3883 const DWORD *vshader_sampler_tokens, int unit)
3885 int current_mapping = This->rev_tex_unit_map[unit];
3887 if (current_mapping == -1) {
3888 /* Not currently used */
3892 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3893 /* Used by a fragment sampler */
3895 if (!pshader_sampler_tokens) {
3896 /* No pixel shader, check fixed function */
3897 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3900 /* Pixel shader, check the shader's sampler map */
3901 return !pshader_sampler_tokens[current_mapping];
3904 /* Used by a vertex sampler */
3905 return !vshader_sampler_tokens[current_mapping];
3908 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3909 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3910 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3911 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3912 int start = GL_LIMITS(combined_samplers) - 1;
3916 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3918 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3919 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3920 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3923 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3924 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3925 if (vshader_sampler_type[i])
3927 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3929 /* Already mapped somewhere */
3933 while (start >= 0) {
3934 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3936 device_map_stage(This, vsampler_idx, start);
3937 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3949 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3950 BOOL vs = use_vs(This->stateBlock);
3951 BOOL ps = use_ps(This->stateBlock);
3954 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3955 * that would be really messy and require shader recompilation
3956 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3957 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3960 device_map_psamplers(This);
3962 device_map_fixed_function_samplers(This);
3966 device_map_vsamplers(This, ps);
3970 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3972 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3973 This->updateStateBlock->pixelShader = pShader;
3974 This->updateStateBlock->changed.pixelShader = TRUE;
3976 /* Handle recording of state blocks */
3977 if (This->isRecordingState) {
3978 TRACE("Recording... not performing anything\n");
3981 if (This->isRecordingState) {
3982 TRACE("Recording... not performing anything\n");
3983 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3984 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3988 if(pShader == oldShader) {
3989 TRACE("App is setting the old pixel shader over, nothing to do\n");
3993 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3994 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3996 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3997 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4002 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4005 if (NULL == ppShader) {
4006 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4007 return WINED3DERR_INVALIDCALL;
4010 *ppShader = This->stateBlock->pixelShader;
4011 if (NULL != *ppShader) {
4012 IWineD3DPixelShader_AddRef(*ppShader);
4014 TRACE("(%p) : returning %p\n", This, *ppShader);
4018 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4019 IWineD3DDevice *iface,
4021 CONST BOOL *srcData,
4024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4025 unsigned int i, cnt = min(count, MAX_CONST_B - start);
4027 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4028 iface, srcData, start, count);
4030 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
4032 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4033 for (i = 0; i < cnt; i++)
4034 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4036 for (i = start; i < cnt + start; ++i) {
4037 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
4040 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4045 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4046 IWineD3DDevice *iface,
4051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4052 int cnt = min(count, MAX_CONST_B - start);
4054 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4055 iface, dstData, start, count);
4057 if (dstData == NULL || cnt < 0)
4058 return WINED3DERR_INVALIDCALL;
4060 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4064 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4065 IWineD3DDevice *iface,
4070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4071 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4073 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4074 iface, srcData, start, count);
4076 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4078 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4079 for (i = 0; i < cnt; i++)
4080 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4081 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4083 for (i = start; i < cnt + start; ++i) {
4084 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4087 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4092 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4093 IWineD3DDevice *iface,
4098 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4099 int cnt = min(count, MAX_CONST_I - start);
4101 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4102 iface, dstData, start, count);
4104 if (dstData == NULL || cnt < 0)
4105 return WINED3DERR_INVALIDCALL;
4107 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4111 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4112 IWineD3DDevice *iface,
4114 CONST float *srcData,
4117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4120 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4121 iface, srcData, start, count);
4123 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4124 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
4125 return WINED3DERR_INVALIDCALL;
4127 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4129 for (i = 0; i < count; i++)
4130 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4131 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4134 if (!This->isRecordingState)
4136 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4137 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4140 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4141 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4146 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4147 IWineD3DDevice *iface,
4152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4153 int cnt = min(count, This->d3d_pshader_constantF - start);
4155 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4156 iface, dstData, start, count);
4158 if (dstData == NULL || cnt < 0)
4159 return WINED3DERR_INVALIDCALL;
4161 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4165 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4166 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4167 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
4170 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4173 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4177 if (stream_info->elements[WINED3D_FFP_NORMAL].data)
4179 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4182 if (!stream_info->elements[WINED3D_FFP_POSITION].data)
4184 ERR("Source has no position mask\n");
4185 return WINED3DERR_INVALIDCALL;
4188 /* We might access VBOs from this code, so hold the lock */
4191 if (dest->resource.allocatedMemory == NULL) {
4192 buffer_get_sysmem(dest);
4195 /* Get a pointer into the destination vbo(create one if none exists) and
4196 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4198 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4200 dest->flags |= WINED3D_BUFFER_CREATEBO;
4201 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4204 if (dest->buffer_object)
4206 unsigned char extrabytes = 0;
4207 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4208 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4209 * this may write 4 extra bytes beyond the area that should be written
4211 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4212 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4213 if(!dest_conv_addr) {
4214 ERR("Out of memory\n");
4215 /* Continue without storing converted vertices */
4217 dest_conv = dest_conv_addr;
4221 * a) WINED3DRS_CLIPPING is enabled
4222 * b) WINED3DVOP_CLIP is passed
4224 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4225 static BOOL warned = FALSE;
4227 * The clipping code is not quite correct. Some things need
4228 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4229 * so disable clipping for now.
4230 * (The graphics in Half-Life are broken, and my processvertices
4231 * test crashes with IDirect3DDevice3)
4237 FIXME("Clipping is broken and disabled for now\n");
4239 } else doClip = FALSE;
4240 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4242 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4245 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4246 WINED3DTS_PROJECTION,
4248 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4249 WINED3DTS_WORLDMATRIX(0),
4252 TRACE("View mat:\n");
4253 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);
4254 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);
4255 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);
4256 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);
4258 TRACE("Proj mat:\n");
4259 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);
4260 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);
4261 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);
4262 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);
4264 TRACE("World mat:\n");
4265 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);
4266 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);
4267 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);
4268 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);
4270 /* Get the viewport */
4271 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4272 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4273 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4275 multiply_matrix(&mat,&view_mat,&world_mat);
4276 multiply_matrix(&mat,&proj_mat,&mat);
4278 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4280 for (i = 0; i < dwCount; i+= 1) {
4281 unsigned int tex_index;
4283 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4284 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4285 /* The position first */
4286 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4287 const float *p = (const float *)(element->data + i * element->stride);
4289 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4291 /* Multiplication with world, view and projection matrix */
4292 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);
4293 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);
4294 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);
4295 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);
4297 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4299 /* WARNING: The following things are taken from d3d7 and were not yet checked
4300 * against d3d8 or d3d9!
4303 /* Clipping conditions: From msdn
4305 * A vertex is clipped if it does not match the following requirements
4309 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4311 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4312 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4317 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4318 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4321 /* "Normal" viewport transformation (not clipped)
4322 * 1) The values are divided by rhw
4323 * 2) The y axis is negative, so multiply it with -1
4324 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4325 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4326 * 4) Multiply x with Width/2 and add Width/2
4327 * 5) The same for the height
4328 * 6) Add the viewpoint X and Y to the 2D coordinates and
4329 * The minimum Z value to z
4330 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4332 * Well, basically it's simply a linear transformation into viewport
4344 z *= vp.MaxZ - vp.MinZ;
4346 x += vp.Width / 2 + vp.X;
4347 y += vp.Height / 2 + vp.Y;
4352 /* That vertex got clipped
4353 * Contrary to OpenGL it is not dropped completely, it just
4354 * undergoes a different calculation.
4356 TRACE("Vertex got clipped\n");
4363 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4364 * outside of the main vertex buffer memory. That needs some more
4369 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4372 ( (float *) dest_ptr)[0] = x;
4373 ( (float *) dest_ptr)[1] = y;
4374 ( (float *) dest_ptr)[2] = z;
4375 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4377 dest_ptr += 3 * sizeof(float);
4379 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4380 dest_ptr += sizeof(float);
4385 ( (float *) dest_conv)[0] = x * w;
4386 ( (float *) dest_conv)[1] = y * w;
4387 ( (float *) dest_conv)[2] = z * w;
4388 ( (float *) dest_conv)[3] = w;
4390 dest_conv += 3 * sizeof(float);
4392 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4393 dest_conv += sizeof(float);
4397 if (DestFVF & WINED3DFVF_PSIZE) {
4398 dest_ptr += sizeof(DWORD);
4399 if(dest_conv) dest_conv += sizeof(DWORD);
4401 if (DestFVF & WINED3DFVF_NORMAL) {
4402 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4403 const float *normal = (const float *)(element->data + i * element->stride);
4404 /* AFAIK this should go into the lighting information */
4405 FIXME("Didn't expect the destination to have a normal\n");
4406 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4408 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4412 if (DestFVF & WINED3DFVF_DIFFUSE) {
4413 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4414 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4416 static BOOL warned = FALSE;
4419 ERR("No diffuse color in source, but destination has one\n");
4423 *( (DWORD *) dest_ptr) = 0xffffffff;
4424 dest_ptr += sizeof(DWORD);
4427 *( (DWORD *) dest_conv) = 0xffffffff;
4428 dest_conv += sizeof(DWORD);
4432 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4434 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4435 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4436 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4437 dest_conv += sizeof(DWORD);
4442 if (DestFVF & WINED3DFVF_SPECULAR) {
4443 /* What's the color value in the feedback buffer? */
4444 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4445 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4447 static BOOL warned = FALSE;
4450 ERR("No specular color in source, but destination has one\n");
4454 *( (DWORD *) dest_ptr) = 0xFF000000;
4455 dest_ptr += sizeof(DWORD);
4458 *( (DWORD *) dest_conv) = 0xFF000000;
4459 dest_conv += sizeof(DWORD);
4463 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4465 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4466 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4467 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4468 dest_conv += sizeof(DWORD);
4473 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4474 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4475 const float *tex_coord = (const float *)(element->data + i * element->stride);
4477 ERR("No source texture, but destination requests one\n");
4478 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4479 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4482 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4484 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4491 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4492 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4493 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4494 dwCount * get_flexible_vertex_size(DestFVF),
4496 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4497 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4504 #undef copy_and_next
4506 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4507 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4511 struct wined3d_stream_info stream_info;
4512 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4513 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4516 ERR("Output vertex declaration not implemented yet\n");
4519 /* Need any context to write to the vbo. */
4520 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4522 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4523 * control the streamIsUP flag, thus restore it afterwards.
4525 This->stateBlock->streamIsUP = FALSE;
4526 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4527 This->stateBlock->streamIsUP = streamWasUP;
4529 if(vbo || SrcStartIndex) {
4531 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4532 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4534 * Also get the start index in, but only loop over all elements if there's something to add at all.
4536 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4538 struct wined3d_stream_info_element *e = &stream_info.elements[i];
4539 if (e->buffer_object)
4541 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4542 e->buffer_object = 0;
4543 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4545 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4546 vb->buffer_object = 0;
4549 if (e->data) e->data += e->stride * SrcStartIndex;
4553 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4554 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4558 * Get / Set Texture Stage States
4559 * TODO: Verify against dx9 definitions
4561 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4563 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4565 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4567 if (Stage >= MAX_TEXTURES) {
4568 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4572 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4573 This->updateStateBlock->textureState[Stage][Type] = Value;
4575 if (This->isRecordingState) {
4576 TRACE("Recording... not performing anything\n");
4580 /* Checked after the assignments to allow proper stateblock recording */
4581 if(oldValue == Value) {
4582 TRACE("App is setting the old value over, nothing to do\n");
4586 if(Stage > This->stateBlock->lowest_disabled_stage &&
4587 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4588 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4589 * Changes in other states are important on disabled stages too
4594 if(Type == WINED3DTSS_COLOROP) {
4597 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4598 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4599 * they have to be disabled
4601 * The current stage is dirtified below.
4603 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4604 TRACE("Additionally dirtifying stage %u\n", i);
4605 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4607 This->stateBlock->lowest_disabled_stage = Stage;
4608 TRACE("New lowest disabled: %u\n", Stage);
4609 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4610 /* Previously disabled stage enabled. Stages above it may need enabling
4611 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4612 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4614 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4617 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4618 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4621 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4622 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4624 This->stateBlock->lowest_disabled_stage = i;
4625 TRACE("New lowest disabled: %u\n", i);
4629 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4634 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4636 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4637 *pValue = This->updateStateBlock->textureState[Stage][Type];
4644 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4646 IWineD3DBaseTexture *oldTexture;
4648 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4650 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4651 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4654 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4655 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4656 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4659 oldTexture = This->updateStateBlock->textures[Stage];
4661 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4662 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4664 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4665 return WINED3DERR_INVALIDCALL;
4668 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4669 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4671 This->updateStateBlock->changed.textures |= 1 << Stage;
4672 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4673 This->updateStateBlock->textures[Stage] = pTexture;
4675 /* Handle recording of state blocks */
4676 if (This->isRecordingState) {
4677 TRACE("Recording... not performing anything\n");
4681 if(oldTexture == pTexture) {
4682 TRACE("App is setting the same texture again, nothing to do\n");
4686 /** NOTE: MSDN says that setTexture increases the reference count,
4687 * and that the application must set the texture back to null (or have a leaky application),
4688 * This means we should pass the refcount up to the parent
4689 *******************************/
4690 if (NULL != This->updateStateBlock->textures[Stage]) {
4691 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4692 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4693 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4695 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4697 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4699 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4702 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4703 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4704 * so the COLOROP and ALPHAOP have to be dirtified.
4706 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4707 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4709 if(bindCount == 1) {
4710 new->baseTexture.sampler = Stage;
4712 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4716 if (NULL != oldTexture) {
4717 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4718 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4720 IWineD3DBaseTexture_Release(oldTexture);
4721 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4722 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4723 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4726 if(bindCount && old->baseTexture.sampler == Stage) {
4728 /* Have to do a search for the other sampler(s) where the texture is bound to
4729 * Shouldn't happen as long as apps bind a texture only to one stage
4731 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4732 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4733 if(This->updateStateBlock->textures[i] == oldTexture) {
4734 old->baseTexture.sampler = i;
4741 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4746 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4749 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4751 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4752 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4755 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4756 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4757 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4760 *ppTexture=This->stateBlock->textures[Stage];
4762 IWineD3DBaseTexture_AddRef(*ppTexture);
4764 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4772 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4773 IWineD3DSurface **ppBackBuffer) {
4774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4775 IWineD3DSwapChain *swapChain;
4778 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4780 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4781 if (hr == WINED3D_OK) {
4782 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4783 IWineD3DSwapChain_Release(swapChain);
4785 *ppBackBuffer = NULL;
4790 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4792 WARN("(%p) : stub, calling idirect3d for now\n", This);
4793 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4796 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4798 IWineD3DSwapChain *swapChain;
4801 if(iSwapChain > 0) {
4802 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4803 if (hr == WINED3D_OK) {
4804 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4805 IWineD3DSwapChain_Release(swapChain);
4807 FIXME("(%p) Error getting display mode\n", This);
4810 /* Don't read the real display mode,
4811 but return the stored mode instead. X11 can't change the color
4812 depth, and some apps are pretty angry if they SetDisplayMode from
4813 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4815 Also don't relay to the swapchain because with ddraw it's possible
4816 that there isn't a swapchain at all */
4817 pMode->Width = This->ddraw_width;
4818 pMode->Height = This->ddraw_height;
4819 pMode->Format = This->ddraw_format;
4820 pMode->RefreshRate = 0;
4828 * Stateblock related functions
4831 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4833 IWineD3DStateBlock *stateblock;
4836 TRACE("(%p)\n", This);
4838 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4840 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4841 if (FAILED(hr)) return hr;
4843 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4844 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4845 This->isRecordingState = TRUE;
4847 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4852 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4855 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4857 if (!This->isRecordingState) {
4858 WARN("(%p) not recording! returning error\n", This);
4859 *ppStateBlock = NULL;
4860 return WINED3DERR_INVALIDCALL;
4863 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
4865 DWORD map = object->changed.renderState[i];
4866 for (j = 0; map; map >>= 1, ++j)
4868 if (!(map & 1)) continue;
4870 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
4874 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
4876 DWORD map = object->changed.transform[i];
4877 for (j = 0; map; map >>= 1, ++j)
4879 if (!(map & 1)) continue;
4881 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
4884 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4885 if(object->changed.vertexShaderConstantsF[i]) {
4886 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4887 object->num_contained_vs_consts_f++;
4890 for(i = 0; i < MAX_CONST_I; i++) {
4891 if (object->changed.vertexShaderConstantsI & (1 << i))
4893 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4894 object->num_contained_vs_consts_i++;
4897 for(i = 0; i < MAX_CONST_B; i++) {
4898 if (object->changed.vertexShaderConstantsB & (1 << i))
4900 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4901 object->num_contained_vs_consts_b++;
4904 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4906 if (object->changed.pixelShaderConstantsF[i])
4908 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4909 ++object->num_contained_ps_consts_f;
4912 for(i = 0; i < MAX_CONST_I; i++) {
4913 if (object->changed.pixelShaderConstantsI & (1 << i))
4915 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4916 object->num_contained_ps_consts_i++;
4919 for(i = 0; i < MAX_CONST_B; i++) {
4920 if (object->changed.pixelShaderConstantsB & (1 << i))
4922 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4923 object->num_contained_ps_consts_b++;
4926 for(i = 0; i < MAX_TEXTURES; i++) {
4927 DWORD map = object->changed.textureState[i];
4929 for(j = 0; map; map >>= 1, ++j)
4931 if (!(map & 1)) continue;
4933 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4934 object->contained_tss_states[object->num_contained_tss_states].state = j;
4935 ++object->num_contained_tss_states;
4938 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4939 DWORD map = object->changed.samplerState[i];
4941 for (j = 0; map; map >>= 1, ++j)
4943 if (!(map & 1)) continue;
4945 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4946 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4947 ++object->num_contained_sampler_states;
4951 *ppStateBlock = (IWineD3DStateBlock*) object;
4952 This->isRecordingState = FALSE;
4953 This->updateStateBlock = This->stateBlock;
4954 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4955 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4956 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4961 * Scene related functions
4963 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4964 /* At the moment we have no need for any functionality at the beginning
4966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4967 TRACE("(%p)\n", This);
4970 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4971 return WINED3DERR_INVALIDCALL;
4973 This->inScene = TRUE;
4977 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4979 TRACE("(%p)\n", This);
4981 if(!This->inScene) {
4982 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4983 return WINED3DERR_INVALIDCALL;
4986 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4987 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4989 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4993 This->inScene = FALSE;
4997 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4998 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4999 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5001 IWineD3DSwapChain *swapChain = NULL;
5003 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5005 TRACE("(%p) Presenting the frame\n", This);
5007 for(i = 0 ; i < swapchains ; i ++) {
5009 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5010 TRACE("presentinng chain %d, %p\n", i, swapChain);
5011 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5012 IWineD3DSwapChain_Release(swapChain);
5018 /* Not called from the VTable (internal subroutine) */
5019 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5020 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5021 float Z, DWORD Stencil) {
5022 GLbitfield glMask = 0;
5024 WINED3DRECT curRect;
5026 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5027 UINT drawable_width, drawable_height;
5028 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5029 IWineD3DSwapChainImpl *swapchain = NULL;
5031 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5032 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5033 * for the cleared parts, and the untouched parts.
5035 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5036 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5037 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5038 * checking all this if the dest surface is in the drawable anyway.
5040 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5042 if(vp->X != 0 || vp->Y != 0 ||
5043 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5044 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5047 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5048 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5049 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5050 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5051 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5054 if(Count > 0 && pRects && (
5055 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5056 pRects[0].x2 < target->currentDesc.Width ||
5057 pRects[0].y2 < target->currentDesc.Height)) {
5058 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5065 target->get_drawable_size(target, &drawable_width, &drawable_height);
5067 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5070 /* Only set the values up once, as they are not changing */
5071 if (Flags & WINED3DCLEAR_STENCIL) {
5072 glClearStencil(Stencil);
5073 checkGLcall("glClearStencil");
5074 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5075 glStencilMask(0xFFFFFFFF);
5078 if (Flags & WINED3DCLEAR_ZBUFFER) {
5079 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5080 glDepthMask(GL_TRUE);
5082 checkGLcall("glClearDepth");
5083 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5084 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5086 if (vp->X != 0 || vp->Y != 0 ||
5087 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5088 surface_load_ds_location(This->stencilBufferTarget, location);
5090 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5091 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5092 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5093 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5094 surface_load_ds_location(This->stencilBufferTarget, location);
5096 else if (Count > 0 && pRects && (
5097 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5098 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5099 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5100 surface_load_ds_location(This->stencilBufferTarget, location);
5104 if (Flags & WINED3DCLEAR_TARGET) {
5105 TRACE("Clearing screen with glClear to color %x\n", Color);
5106 glClearColor(D3DCOLOR_R(Color),
5110 checkGLcall("glClearColor");
5112 /* Clear ALL colors! */
5113 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5114 glMask = glMask | GL_COLOR_BUFFER_BIT;
5117 vp_rect.left = vp->X;
5118 vp_rect.top = vp->Y;
5119 vp_rect.right = vp->X + vp->Width;
5120 vp_rect.bottom = vp->Y + vp->Height;
5121 if (!(Count > 0 && pRects)) {
5122 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5123 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5125 if(This->render_offscreen) {
5126 glScissor(vp_rect.left, vp_rect.top,
5127 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5129 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5130 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5132 checkGLcall("glScissor");
5134 checkGLcall("glClear");
5136 /* Now process each rect in turn */
5137 for (i = 0; i < Count; i++) {
5138 /* Note gl uses lower left, width/height */
5139 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5140 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5141 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5143 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5144 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5145 curRect.x1, (target->currentDesc.Height - curRect.y2),
5146 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5148 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5149 * The rectangle is not cleared, no error is returned, but further rectanlges are
5150 * still cleared if they are valid
5152 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5153 TRACE("Rectangle with negative dimensions, ignoring\n");
5157 if(This->render_offscreen) {
5158 glScissor(curRect.x1, curRect.y1,
5159 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5161 glScissor(curRect.x1, drawable_height - curRect.y2,
5162 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5164 checkGLcall("glScissor");
5167 checkGLcall("glClear");
5171 /* Restore the old values (why..?) */
5172 if (Flags & WINED3DCLEAR_STENCIL) {
5173 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5175 if (Flags & WINED3DCLEAR_TARGET) {
5176 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5177 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5178 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5179 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5180 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5182 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5183 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5185 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5187 if (Flags & WINED3DCLEAR_ZBUFFER) {
5188 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5189 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5190 surface_modify_ds_location(This->stencilBufferTarget, location);
5195 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5196 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5199 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5205 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5206 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5208 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5210 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5211 Count, pRects, Flags, Color, Z, Stencil);
5213 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5214 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5215 /* TODO: What about depth stencil buffers without stencil bits? */
5216 return WINED3DERR_INVALIDCALL;
5219 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5226 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5227 WINED3DPRIMITIVETYPE primitive_type)
5229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5231 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5233 This->updateStateBlock->changed.primitive_type = TRUE;
5234 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5237 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5238 WINED3DPRIMITIVETYPE *primitive_type)
5240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5242 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5244 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5246 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5249 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5253 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5255 if(!This->stateBlock->vertexDecl) {
5256 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5257 return WINED3DERR_INVALIDCALL;
5260 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5261 if(This->stateBlock->streamIsUP) {
5262 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5263 This->stateBlock->streamIsUP = FALSE;
5266 if(This->stateBlock->loadBaseVertexIndex != 0) {
5267 This->stateBlock->loadBaseVertexIndex = 0;
5268 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5270 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5271 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5272 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5276 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5277 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5281 IWineD3DBuffer *pIB;
5284 pIB = This->stateBlock->pIndexData;
5286 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5287 * without an index buffer set. (The first time at least...)
5288 * D3D8 simply dies, but I doubt it can do much harm to return
5289 * D3DERR_INVALIDCALL there as well. */
5290 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5291 return WINED3DERR_INVALIDCALL;
5294 if(!This->stateBlock->vertexDecl) {
5295 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5296 return WINED3DERR_INVALIDCALL;
5299 if(This->stateBlock->streamIsUP) {
5300 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5301 This->stateBlock->streamIsUP = FALSE;
5303 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
5305 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5306 This, minIndex, NumVertices, startIndex, index_count);
5308 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
5314 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5315 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5316 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5319 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5320 vbo ? NULL : ((struct wined3d_buffer *) pIB)->resource.allocatedMemory, minIndex);
5325 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5326 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5331 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5332 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5334 if(!This->stateBlock->vertexDecl) {
5335 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5336 return WINED3DERR_INVALIDCALL;
5339 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5340 vb = This->stateBlock->streamSource[0];
5341 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5342 if (vb) IWineD3DBuffer_Release(vb);
5343 This->stateBlock->streamOffset[0] = 0;
5344 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5345 This->stateBlock->streamIsUP = TRUE;
5346 This->stateBlock->loadBaseVertexIndex = 0;
5348 /* TODO: Only mark dirty if drawing from a different UP address */
5349 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5351 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5352 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5354 /* MSDN specifies stream zero settings must be set to NULL */
5355 This->stateBlock->streamStride[0] = 0;
5356 This->stateBlock->streamSource[0] = NULL;
5358 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5359 * the new stream sources or use UP drawing again
5364 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5365 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5366 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5373 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5374 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5375 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5377 if(!This->stateBlock->vertexDecl) {
5378 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5379 return WINED3DERR_INVALIDCALL;
5382 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5388 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5389 vb = This->stateBlock->streamSource[0];
5390 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5391 if (vb) IWineD3DBuffer_Release(vb);
5392 This->stateBlock->streamIsUP = TRUE;
5393 This->stateBlock->streamOffset[0] = 0;
5394 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5396 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5397 This->stateBlock->baseVertexIndex = 0;
5398 This->stateBlock->loadBaseVertexIndex = 0;
5399 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5400 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5401 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5403 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5404 idxStride, pIndexData, MinVertexIndex);
5406 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5407 This->stateBlock->streamSource[0] = NULL;
5408 This->stateBlock->streamStride[0] = 0;
5409 ib = This->stateBlock->pIndexData;
5411 IWineD3DBuffer_Release(ib);
5412 This->stateBlock->pIndexData = NULL;
5414 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5415 * SetStreamSource to specify a vertex buffer
5421 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5422 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5426 /* Mark the state dirty until we have nicer tracking
5427 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5430 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5431 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5432 This->stateBlock->baseVertexIndex = 0;
5433 This->up_strided = DrawPrimStrideData;
5434 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5435 This->up_strided = NULL;
5439 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5440 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5441 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5444 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5446 /* Mark the state dirty until we have nicer tracking
5447 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5450 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5451 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5452 This->stateBlock->streamIsUP = TRUE;
5453 This->stateBlock->baseVertexIndex = 0;
5454 This->up_strided = DrawPrimStrideData;
5455 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5456 This->up_strided = NULL;
5460 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5461 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5462 * not callable by the app directly no parameter validation checks are needed here.
5464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5465 WINED3DLOCKED_BOX src;
5466 WINED3DLOCKED_BOX dst;
5468 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5470 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5471 * dirtification to improve loading performance.
5473 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5474 if(FAILED(hr)) return hr;
5475 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5477 IWineD3DVolume_UnlockBox(pSourceVolume);
5481 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5483 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5485 IWineD3DVolume_UnlockBox(pSourceVolume);
5487 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5492 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5493 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5494 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5495 HRESULT hr = WINED3D_OK;
5496 WINED3DRESOURCETYPE sourceType;
5497 WINED3DRESOURCETYPE destinationType;
5500 /* TODO: think about moving the code into IWineD3DBaseTexture */
5502 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5504 /* verify that the source and destination textures aren't NULL */
5505 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5506 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5507 This, pSourceTexture, pDestinationTexture);
5508 hr = WINED3DERR_INVALIDCALL;
5511 if (pSourceTexture == pDestinationTexture) {
5512 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5513 This, pSourceTexture, pDestinationTexture);
5514 hr = WINED3DERR_INVALIDCALL;
5516 /* Verify that the source and destination textures are the same type */
5517 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5518 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5520 if (sourceType != destinationType) {
5521 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5523 hr = WINED3DERR_INVALIDCALL;
5526 /* check that both textures have the identical numbers of levels */
5527 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5528 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5529 hr = WINED3DERR_INVALIDCALL;
5532 if (WINED3D_OK == hr) {
5533 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5535 /* Make sure that the destination texture is loaded */
5536 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5538 /* Update every surface level of the texture */
5539 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5541 switch (sourceType) {
5542 case WINED3DRTYPE_TEXTURE:
5544 IWineD3DSurface *srcSurface;
5545 IWineD3DSurface *destSurface;
5547 for (i = 0 ; i < levels ; ++i) {
5548 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5549 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5550 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5551 IWineD3DSurface_Release(srcSurface);
5552 IWineD3DSurface_Release(destSurface);
5553 if (WINED3D_OK != hr) {
5554 WARN("(%p) : Call to update surface failed\n", This);
5560 case WINED3DRTYPE_CUBETEXTURE:
5562 IWineD3DSurface *srcSurface;
5563 IWineD3DSurface *destSurface;
5564 WINED3DCUBEMAP_FACES faceType;
5566 for (i = 0 ; i < levels ; ++i) {
5567 /* Update each cube face */
5568 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5569 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5570 if (WINED3D_OK != hr) {
5571 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5573 TRACE("Got srcSurface %p\n", srcSurface);
5575 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5576 if (WINED3D_OK != hr) {
5577 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5579 TRACE("Got desrSurface %p\n", destSurface);
5581 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5582 IWineD3DSurface_Release(srcSurface);
5583 IWineD3DSurface_Release(destSurface);
5584 if (WINED3D_OK != hr) {
5585 WARN("(%p) : Call to update surface failed\n", This);
5593 case WINED3DRTYPE_VOLUMETEXTURE:
5595 IWineD3DVolume *srcVolume = NULL;
5596 IWineD3DVolume *destVolume = NULL;
5598 for (i = 0 ; i < levels ; ++i) {
5599 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5600 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5601 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5602 IWineD3DVolume_Release(srcVolume);
5603 IWineD3DVolume_Release(destVolume);
5604 if (WINED3D_OK != hr) {
5605 WARN("(%p) : Call to update volume failed\n", This);
5613 FIXME("(%p) : Unsupported source and destination type\n", This);
5614 hr = WINED3DERR_INVALIDCALL;
5621 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5622 IWineD3DSwapChain *swapChain;
5624 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5625 if(hr == WINED3D_OK) {
5626 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5627 IWineD3DSwapChain_Release(swapChain);
5632 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5634 IWineD3DBaseTextureImpl *texture;
5637 TRACE("(%p) : %p\n", This, pNumPasses);
5639 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5640 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5641 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5642 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5644 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5645 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5646 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5649 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5650 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5652 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5653 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5656 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5657 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5660 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5661 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5662 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5667 /* return a sensible default */
5670 TRACE("returning D3D_OK\n");
5674 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5678 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5679 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5680 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
5681 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
5683 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5688 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5692 PALETTEENTRY **palettes;
5694 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5696 if (PaletteNumber >= MAX_PALETTES) {
5697 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5698 return WINED3DERR_INVALIDCALL;
5701 if (PaletteNumber >= This->NumberOfPalettes) {
5702 NewSize = This->NumberOfPalettes;
5705 } while(PaletteNumber >= NewSize);
5706 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5708 ERR("Out of memory!\n");
5709 return E_OUTOFMEMORY;
5711 This->palettes = palettes;
5712 This->NumberOfPalettes = NewSize;
5715 if (!This->palettes[PaletteNumber]) {
5716 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5717 if (!This->palettes[PaletteNumber]) {
5718 ERR("Out of memory!\n");
5719 return E_OUTOFMEMORY;
5723 for (j = 0; j < 256; ++j) {
5724 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5725 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5726 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5727 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5729 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5730 TRACE("(%p) : returning\n", This);
5734 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5737 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5738 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5739 /* What happens in such situation isn't documented; Native seems to silently abort
5740 on such conditions. Return Invalid Call. */
5741 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5742 return WINED3DERR_INVALIDCALL;
5744 for (j = 0; j < 256; ++j) {
5745 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5746 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5747 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5748 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5750 TRACE("(%p) : returning\n", This);
5754 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5756 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5757 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5758 (tested with reference rasterizer). Return Invalid Call. */
5759 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5760 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5761 return WINED3DERR_INVALIDCALL;
5763 /*TODO: stateblocks */
5764 if (This->currentPalette != PaletteNumber) {
5765 This->currentPalette = PaletteNumber;
5766 dirtify_p8_texture_samplers(This);
5768 TRACE("(%p) : returning\n", This);
5772 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5774 if (PaletteNumber == NULL) {
5775 WARN("(%p) : returning Invalid Call\n", This);
5776 return WINED3DERR_INVALIDCALL;
5778 /*TODO: stateblocks */
5779 *PaletteNumber = This->currentPalette;
5780 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5784 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5789 FIXME("(%p) : stub\n", This);
5793 This->softwareVertexProcessing = bSoftware;
5798 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5803 FIXME("(%p) : stub\n", This);
5806 return This->softwareVertexProcessing;
5810 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5812 IWineD3DSwapChain *swapChain;
5815 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5817 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5818 if(hr == WINED3D_OK){
5819 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5820 IWineD3DSwapChain_Release(swapChain);
5822 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5828 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5831 if(nSegments != 0.0f) {
5834 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5841 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5846 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5852 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5854 /** TODO: remove casts to IWineD3DSurfaceImpl
5855 * NOTE: move code to surface to accomplish this
5856 ****************************************/
5857 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5858 int srcWidth, srcHeight;
5859 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5860 WINED3DFORMAT destFormat, srcFormat;
5862 int srcLeft, destLeft, destTop;
5863 WINED3DPOOL srcPool, destPool;
5865 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5866 glDescriptor *glDescription = NULL;
5867 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5871 CONVERT_TYPES convert = NO_CONVERSION;
5873 WINED3DSURFACE_DESC winedesc;
5875 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5876 memset(&winedesc, 0, sizeof(winedesc));
5877 winedesc.Width = &srcSurfaceWidth;
5878 winedesc.Height = &srcSurfaceHeight;
5879 winedesc.Pool = &srcPool;
5880 winedesc.Format = &srcFormat;
5882 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5884 winedesc.Width = &destSurfaceWidth;
5885 winedesc.Height = &destSurfaceHeight;
5886 winedesc.Pool = &destPool;
5887 winedesc.Format = &destFormat;
5888 winedesc.Size = &destSize;
5890 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5892 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5893 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5894 return WINED3DERR_INVALIDCALL;
5897 /* This call loads the opengl surface directly, instead of copying the surface to the
5898 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5899 * copy in sysmem and use regular surface loading.
5901 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5902 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5903 if(convert != NO_CONVERSION) {
5904 return IWineD3DSurface_BltFast(pDestinationSurface,
5905 pDestPoint ? pDestPoint->x : 0,
5906 pDestPoint ? pDestPoint->y : 0,
5907 pSourceSurface, pSourceRect, 0);
5910 if (destFormat == WINED3DFMT_UNKNOWN) {
5911 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5912 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5914 /* Get the update surface description */
5915 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5918 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5921 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5922 checkGLcall("glActiveTextureARB");
5925 /* Make sure the surface is loaded and up to date */
5926 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5927 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5929 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5931 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5932 dst_format_desc = ((IWineD3DSurfaceImpl *)pDestinationSurface)->resource.format_desc;
5934 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5935 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5936 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5937 srcLeft = pSourceRect ? pSourceRect->left : 0;
5938 destLeft = pDestPoint ? pDestPoint->x : 0;
5939 destTop = pDestPoint ? pDestPoint->y : 0;
5942 /* This function doesn't support compressed textures
5943 the pitch is just bytesPerPixel * width */
5944 if(srcWidth != srcSurfaceWidth || srcLeft ){
5945 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5946 offset += srcLeft * src_format_desc->byte_count;
5947 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5949 /* TODO DXT formats */
5951 if(pSourceRect != NULL && pSourceRect->top != 0){
5952 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5954 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5955 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5956 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5959 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5961 /* need to lock the surface to get the data */
5962 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5967 /* TODO: Cube and volume support */
5969 /* not a whole row so we have to do it a line at a time */
5972 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5973 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5975 for (j = destTop; j < (srcHeight + destTop); ++j)
5977 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, j,
5978 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5982 } else { /* Full width, so just write out the whole texture */
5983 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5985 if (WINED3DFMT_DXT1 == destFormat ||
5986 WINED3DFMT_DXT2 == destFormat ||
5987 WINED3DFMT_DXT3 == destFormat ||
5988 WINED3DFMT_DXT4 == destFormat ||
5989 WINED3DFMT_DXT5 == destFormat) {
5990 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5991 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5992 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5993 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5994 } if (destFormat != srcFormat) {
5995 FIXME("Updating mixed format compressed texture is not curretly support\n");
5997 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
5998 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
6001 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6006 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6007 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
6010 checkGLcall("glTexSubImage2D");
6014 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6015 sampler = This->rev_tex_unit_map[0];
6016 if (sampler != -1) {
6017 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6023 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6025 struct WineD3DRectPatch *patch;
6026 GLenum old_primitive_type;
6030 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6032 if(!(Handle || pRectPatchInfo)) {
6033 /* TODO: Write a test for the return value, thus the FIXME */
6034 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6035 return WINED3DERR_INVALIDCALL;
6039 i = PATCHMAP_HASHFUNC(Handle);
6041 LIST_FOR_EACH(e, &This->patches[i]) {
6042 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6043 if(patch->Handle == Handle) {
6050 TRACE("Patch does not exist. Creating a new one\n");
6051 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6052 patch->Handle = Handle;
6053 list_add_head(&This->patches[i], &patch->entry);
6055 TRACE("Found existing patch %p\n", patch);
6058 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6059 * attributes we have to tesselate, read back, and draw. This needs a patch
6060 * management structure instance. Create one.
6062 * A possible improvement is to check if a vertex shader is used, and if not directly
6065 FIXME("Drawing an uncached patch. This is slow\n");
6066 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6069 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6070 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6071 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6073 TRACE("Tesselation density or patch info changed, retesselating\n");
6075 if(pRectPatchInfo) {
6076 patch->RectPatchInfo = *pRectPatchInfo;
6078 patch->numSegs[0] = pNumSegs[0];
6079 patch->numSegs[1] = pNumSegs[1];
6080 patch->numSegs[2] = pNumSegs[2];
6081 patch->numSegs[3] = pNumSegs[3];
6083 hr = tesselate_rectpatch(This, patch);
6085 WARN("Patch tesselation failed\n");
6087 /* Do not release the handle to store the params of the patch */
6089 HeapFree(GetProcessHeap(), 0, patch);
6095 This->currentPatch = patch;
6096 old_primitive_type = This->stateBlock->gl_primitive_type;
6097 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
6098 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
6099 This->stateBlock->gl_primitive_type = old_primitive_type;
6100 This->currentPatch = NULL;
6102 /* Destroy uncached patches */
6104 HeapFree(GetProcessHeap(), 0, patch->mem);
6105 HeapFree(GetProcessHeap(), 0, patch);
6110 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6112 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6113 FIXME("(%p) : Stub\n", This);
6117 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6120 struct WineD3DRectPatch *patch;
6122 TRACE("(%p) Handle(%d)\n", This, Handle);
6124 i = PATCHMAP_HASHFUNC(Handle);
6125 LIST_FOR_EACH(e, &This->patches[i]) {
6126 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6127 if(patch->Handle == Handle) {
6128 TRACE("Deleting patch %p\n", patch);
6129 list_remove(&patch->entry);
6130 HeapFree(GetProcessHeap(), 0, patch->mem);
6131 HeapFree(GetProcessHeap(), 0, patch);
6136 /* TODO: Write a test for the return value */
6137 FIXME("Attempt to destroy nonexistent patch\n");
6138 return WINED3DERR_INVALIDCALL;
6141 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6143 IWineD3DSwapChain *swapchain;
6145 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6146 if (SUCCEEDED(hr)) {
6147 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6154 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6155 const WINED3DRECT *rect, const float color[4])
6157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6158 IWineD3DSwapChain *swapchain;
6160 swapchain = get_swapchain(surface);
6164 TRACE("Surface %p is onscreen\n", surface);
6166 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6168 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6169 buffer = surface_get_gl_buffer(surface, swapchain);
6170 glDrawBuffer(buffer);
6171 checkGLcall("glDrawBuffer()");
6173 TRACE("Surface %p is offscreen\n", surface);
6175 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6177 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6178 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6179 context_attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, NULL, FALSE);
6183 glEnable(GL_SCISSOR_TEST);
6185 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6187 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6188 rect->x2 - rect->x1, rect->y2 - rect->y1);
6190 checkGLcall("glScissor");
6191 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6193 glDisable(GL_SCISSOR_TEST);
6195 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6197 glDisable(GL_BLEND);
6198 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6200 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6201 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6203 glClearColor(color[0], color[1], color[2], color[3]);
6204 glClear(GL_COLOR_BUFFER_BIT);
6205 checkGLcall("glClear");
6207 if (This->activeContext->current_fbo) {
6208 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6210 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6211 checkGLcall("glBindFramebuffer()");
6214 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6215 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6216 glDrawBuffer(GL_BACK);
6217 checkGLcall("glDrawBuffer()");
6223 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6224 unsigned int r, g, b, a;
6227 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6228 destfmt == WINED3DFMT_R8G8B8)
6231 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6233 a = (color & 0xff000000) >> 24;
6234 r = (color & 0x00ff0000) >> 16;
6235 g = (color & 0x0000ff00) >> 8;
6236 b = (color & 0x000000ff) >> 0;
6240 case WINED3DFMT_R5G6B5:
6241 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6248 TRACE("Returning %08x\n", ret);
6251 case WINED3DFMT_X1R5G5B5:
6252 case WINED3DFMT_A1R5G5B5:
6261 TRACE("Returning %08x\n", ret);
6264 case WINED3DFMT_A8_UNORM:
6265 TRACE("Returning %08x\n", a);
6268 case WINED3DFMT_X4R4G4B4:
6269 case WINED3DFMT_A4R4G4B4:
6278 TRACE("Returning %08x\n", ret);
6281 case WINED3DFMT_R3G3B2:
6288 TRACE("Returning %08x\n", ret);
6291 case WINED3DFMT_X8B8G8R8:
6292 case WINED3DFMT_R8G8B8A8_UNORM:
6297 TRACE("Returning %08x\n", ret);
6300 case WINED3DFMT_A2R10G10B10:
6302 r = (r * 1024) / 256;
6303 g = (g * 1024) / 256;
6304 b = (b * 1024) / 256;
6309 TRACE("Returning %08x\n", ret);
6312 case WINED3DFMT_R10G10B10A2_UNORM:
6314 r = (r * 1024) / 256;
6315 g = (g * 1024) / 256;
6316 b = (b * 1024) / 256;
6321 TRACE("Returning %08x\n", ret);
6325 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6330 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6332 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6334 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6336 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6337 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6338 return WINED3DERR_INVALIDCALL;
6341 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6342 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6343 color_fill_fbo(iface, pSurface, pRect, c);
6346 /* Just forward this to the DirectDraw blitting engine */
6347 memset(&BltFx, 0, sizeof(BltFx));
6348 BltFx.dwSize = sizeof(BltFx);
6349 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6350 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6351 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6355 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6356 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6358 IWineD3DResource *resource;
6359 IWineD3DSurface *surface;
6362 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6365 ERR("Failed to get resource, hr %#x\n", hr);
6369 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6371 FIXME("Only supported on surface resources\n");
6372 IWineD3DResource_Release(resource);
6376 surface = (IWineD3DSurface *)resource;
6378 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6380 color_fill_fbo(iface, surface, NULL, color);
6387 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6389 c = ((DWORD)(color[2] * 255.0));
6390 c |= ((DWORD)(color[1] * 255.0)) << 8;
6391 c |= ((DWORD)(color[0] * 255.0)) << 16;
6392 c |= ((DWORD)(color[3] * 255.0)) << 24;
6394 /* Just forward this to the DirectDraw blitting engine */
6395 memset(&BltFx, 0, sizeof(BltFx));
6396 BltFx.dwSize = sizeof(BltFx);
6397 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6398 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6401 ERR("Blt failed, hr %#x\n", hr);
6405 IWineD3DResource_Release(resource);
6408 /* rendertarget and depth stencil functions */
6409 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6410 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6412 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6413 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6414 return WINED3DERR_INVALIDCALL;
6417 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6418 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6419 /* Note inc ref on returned surface */
6420 if(*ppRenderTarget != NULL)
6421 IWineD3DSurface_AddRef(*ppRenderTarget);
6425 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6427 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6428 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6429 IWineD3DSwapChainImpl *Swapchain;
6432 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6434 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6435 if(hr != WINED3D_OK) {
6436 ERR("Can't get the swapchain\n");
6440 /* Make sure to release the swapchain */
6441 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6443 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6444 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6445 return WINED3DERR_INVALIDCALL;
6447 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6448 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6449 return WINED3DERR_INVALIDCALL;
6452 if(Swapchain->frontBuffer != Front) {
6453 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6455 if(Swapchain->frontBuffer)
6457 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6458 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6460 Swapchain->frontBuffer = Front;
6462 if(Swapchain->frontBuffer) {
6463 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6464 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6468 if(Back && !Swapchain->backBuffer) {
6469 /* We need memory for the back buffer array - only one back buffer this way */
6470 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6471 if(!Swapchain->backBuffer) {
6472 ERR("Out of memory\n");
6473 return E_OUTOFMEMORY;
6477 if(Swapchain->backBuffer[0] != Back) {
6478 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6480 /* What to do about the context here in the case of multithreading? Not sure.
6481 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6484 if(!Swapchain->backBuffer[0]) {
6485 /* GL was told to draw to the front buffer at creation,
6488 glDrawBuffer(GL_BACK);
6489 checkGLcall("glDrawBuffer(GL_BACK)");
6490 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6491 Swapchain->presentParms.BackBufferCount = 1;
6493 /* That makes problems - disable for now */
6494 /* glDrawBuffer(GL_FRONT); */
6495 checkGLcall("glDrawBuffer(GL_FRONT)");
6496 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6497 Swapchain->presentParms.BackBufferCount = 0;
6501 if(Swapchain->backBuffer[0])
6503 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6504 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6506 Swapchain->backBuffer[0] = Back;
6508 if(Swapchain->backBuffer[0]) {
6509 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6510 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6512 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6513 Swapchain->backBuffer = NULL;
6521 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6523 *ppZStencilSurface = This->stencilBufferTarget;
6524 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6526 if(*ppZStencilSurface != NULL) {
6527 /* Note inc ref on returned surface */
6528 IWineD3DSurface_AddRef(*ppZStencilSurface);
6531 return WINED3DERR_NOTFOUND;
6535 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6536 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6539 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6540 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6542 POINT offset = {0, 0};
6544 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6545 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6546 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6547 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6550 case WINED3DTEXF_LINEAR:
6551 gl_filter = GL_LINEAR;
6555 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6556 case WINED3DTEXF_NONE:
6557 case WINED3DTEXF_POINT:
6558 gl_filter = GL_NEAREST;
6562 /* Attach src surface to src fbo */
6563 src_swapchain = get_swapchain(src_surface);
6564 if (src_swapchain) {
6565 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6567 TRACE("Source surface %p is onscreen\n", src_surface);
6568 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6569 /* Make sure the drawable is up to date. In the offscreen case
6570 * attach_surface_fbo() implicitly takes care of this. */
6571 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6573 if(buffer == GL_FRONT) {
6576 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6577 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6578 h = windowsize.bottom - windowsize.top;
6579 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6580 src_rect->y1 = offset.y + h - src_rect->y1;
6581 src_rect->y2 = offset.y + h - src_rect->y2;
6583 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6584 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6588 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6589 glReadBuffer(buffer);
6590 checkGLcall("glReadBuffer()");
6592 TRACE("Source surface %p is offscreen\n", src_surface);
6594 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6595 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6596 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6597 checkGLcall("glReadBuffer()");
6598 context_attach_depth_stencil_fbo(This, GL_READ_FRAMEBUFFER_EXT, NULL, FALSE);
6602 /* Attach dst surface to dst fbo */
6603 dst_swapchain = get_swapchain(dst_surface);
6604 if (dst_swapchain) {
6605 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6607 TRACE("Destination surface %p is onscreen\n", dst_surface);
6608 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6609 /* Make sure the drawable is up to date. In the offscreen case
6610 * attach_surface_fbo() implicitly takes care of this. */
6611 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6613 if(buffer == GL_FRONT) {
6616 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6617 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6618 h = windowsize.bottom - windowsize.top;
6619 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6620 dst_rect->y1 = offset.y + h - dst_rect->y1;
6621 dst_rect->y2 = offset.y + h - dst_rect->y2;
6623 /* Screen coords = window coords, surface height = window height */
6624 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6625 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6629 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6630 glDrawBuffer(buffer);
6631 checkGLcall("glDrawBuffer()");
6633 TRACE("Destination surface %p is offscreen\n", dst_surface);
6635 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6636 if(!src_swapchain) {
6637 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6641 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6642 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6643 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6644 checkGLcall("glDrawBuffer()");
6645 context_attach_depth_stencil_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, NULL, FALSE);
6647 glDisable(GL_SCISSOR_TEST);
6648 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6651 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6652 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6653 checkGLcall("glBlitFramebuffer()");
6655 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6656 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6657 checkGLcall("glBlitFramebuffer()");
6660 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6662 if (This->activeContext->current_fbo) {
6663 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6665 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6666 checkGLcall("glBindFramebuffer()");
6669 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6670 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6671 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6672 glDrawBuffer(GL_BACK);
6673 checkGLcall("glDrawBuffer()");
6678 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6680 WINED3DVIEWPORT viewport;
6682 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6684 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6685 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6686 This, RenderTargetIndex, GL_LIMITS(buffers));
6687 return WINED3DERR_INVALIDCALL;
6690 /* MSDN says that null disables the render target
6691 but a device must always be associated with a render target
6692 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6694 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6695 FIXME("Trying to set render target 0 to NULL\n");
6696 return WINED3DERR_INVALIDCALL;
6698 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6699 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);
6700 return WINED3DERR_INVALIDCALL;
6703 /* If we are trying to set what we already have, don't bother */
6704 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6705 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6708 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6709 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6710 This->render_targets[RenderTargetIndex] = pRenderTarget;
6712 /* Render target 0 is special */
6713 if(RenderTargetIndex == 0) {
6714 /* Finally, reset the viewport as the MSDN states. */
6715 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6716 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6719 viewport.MaxZ = 1.0f;
6720 viewport.MinZ = 0.0f;
6721 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6722 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6723 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6725 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6730 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6732 HRESULT hr = WINED3D_OK;
6733 IWineD3DSurface *tmp;
6735 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6737 if (pNewZStencil == This->stencilBufferTarget) {
6738 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6740 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6741 * depending on the renter target implementation being used.
6742 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6743 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6744 * stencil buffer and incur an extra memory overhead
6745 ******************************************************/
6747 if (This->stencilBufferTarget) {
6748 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6749 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6750 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6752 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6753 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6754 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6758 tmp = This->stencilBufferTarget;
6759 This->stencilBufferTarget = pNewZStencil;
6760 /* should we be calling the parent or the wined3d surface? */
6761 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6762 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6765 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6766 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6767 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6768 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6769 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6776 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6777 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6779 /* TODO: the use of Impl is deprecated. */
6780 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6781 WINED3DLOCKED_RECT lockedRect;
6783 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6785 /* some basic validation checks */
6786 if(This->cursorTexture) {
6787 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6789 glDeleteTextures(1, &This->cursorTexture);
6791 This->cursorTexture = 0;
6794 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6795 This->haveHardwareCursor = TRUE;
6797 This->haveHardwareCursor = FALSE;
6800 WINED3DLOCKED_RECT rect;
6802 /* MSDN: Cursor must be A8R8G8B8 */
6803 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
6805 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6806 return WINED3DERR_INVALIDCALL;
6809 /* MSDN: Cursor must be smaller than the display mode */
6810 if(pSur->currentDesc.Width > This->ddraw_width ||
6811 pSur->currentDesc.Height > This->ddraw_height) {
6812 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);
6813 return WINED3DERR_INVALIDCALL;
6816 if (!This->haveHardwareCursor) {
6817 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6819 /* Do not store the surface's pointer because the application may
6820 * release it after setting the cursor image. Windows doesn't
6821 * addref the set surface, so we can't do this either without
6822 * creating circular refcount dependencies. Copy out the gl texture
6825 This->cursorWidth = pSur->currentDesc.Width;
6826 This->cursorHeight = pSur->currentDesc.Height;
6827 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6829 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
6830 char *mem, *bits = rect.pBits;
6831 GLint intfmt = glDesc->glInternal;
6832 GLint format = glDesc->glFormat;
6833 GLint type = glDesc->glType;
6834 INT height = This->cursorHeight;
6835 INT width = This->cursorWidth;
6836 INT bpp = glDesc->byte_count;
6839 /* Reformat the texture memory (pitch and width can be
6841 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6842 for(i = 0; i < height; i++)
6843 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6844 IWineD3DSurface_UnlockRect(pCursorBitmap);
6847 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6848 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6849 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6852 /* Make sure that a proper texture unit is selected */
6853 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6854 checkGLcall("glActiveTextureARB");
6855 sampler = This->rev_tex_unit_map[0];
6856 if (sampler != -1) {
6857 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6859 /* Create a new cursor texture */
6860 glGenTextures(1, &This->cursorTexture);
6861 checkGLcall("glGenTextures");
6862 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6863 checkGLcall("glBindTexture");
6864 /* Copy the bitmap memory into the cursor texture */
6865 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6866 HeapFree(GetProcessHeap(), 0, mem);
6867 checkGLcall("glTexImage2D");
6869 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6870 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6871 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6878 FIXME("A cursor texture was not returned.\n");
6879 This->cursorTexture = 0;
6884 /* Draw a hardware cursor */
6885 ICONINFO cursorInfo;
6887 /* Create and clear maskBits because it is not needed for
6888 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6890 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6891 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6892 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6893 WINED3DLOCK_NO_DIRTY_UPDATE |
6894 WINED3DLOCK_READONLY
6896 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6897 pSur->currentDesc.Height);
6899 cursorInfo.fIcon = FALSE;
6900 cursorInfo.xHotspot = XHotSpot;
6901 cursorInfo.yHotspot = YHotSpot;
6902 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6903 pSur->currentDesc.Height, 1,
6905 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6906 pSur->currentDesc.Height, 1,
6907 32, lockedRect.pBits);
6908 IWineD3DSurface_UnlockRect(pCursorBitmap);
6909 /* Create our cursor and clean up. */
6910 cursor = CreateIconIndirect(&cursorInfo);
6912 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6913 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6914 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6915 This->hardwareCursor = cursor;
6916 HeapFree(GetProcessHeap(), 0, maskBits);
6920 This->xHotSpot = XHotSpot;
6921 This->yHotSpot = YHotSpot;
6925 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6927 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6929 This->xScreenSpace = XScreenSpace;
6930 This->yScreenSpace = YScreenSpace;
6936 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6938 BOOL oldVisible = This->bCursorVisible;
6941 TRACE("(%p) : visible(%d)\n", This, bShow);
6944 * When ShowCursor is first called it should make the cursor appear at the OS's last
6945 * known cursor position. Because of this, some applications just repetitively call
6946 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6949 This->xScreenSpace = pt.x;
6950 This->yScreenSpace = pt.y;
6952 if (This->haveHardwareCursor) {
6953 This->bCursorVisible = bShow;
6955 SetCursor(This->hardwareCursor);
6961 if (This->cursorTexture)
6962 This->bCursorVisible = bShow;
6968 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6970 IWineD3DResourceImpl *resource;
6971 TRACE("(%p) : state (%u)\n", This, This->state);
6973 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6974 switch (This->state) {
6977 case WINED3DERR_DEVICELOST:
6979 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6980 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6981 return WINED3DERR_DEVICENOTRESET;
6983 return WINED3DERR_DEVICELOST;
6985 case WINED3DERR_DRIVERINTERNALERROR:
6986 return WINED3DERR_DRIVERINTERNALERROR;
6990 return WINED3DERR_DRIVERINTERNALERROR;
6994 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6996 /** FIXME: Resource tracking needs to be done,
6997 * The closes we can do to this is set the priorities of all managed textures low
6998 * and then reset them.
6999 ***********************************************************/
7000 FIXME("(%p) : stub\n", This);
7004 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
7006 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7008 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7009 if(surface->Flags & SFLAG_DIBSECTION) {
7010 /* Release the DC */
7011 SelectObject(surface->hDC, surface->dib.holdbitmap);
7012 DeleteDC(surface->hDC);
7013 /* Release the DIB section */
7014 DeleteObject(surface->dib.DIBsection);
7015 surface->dib.bitmap_data = NULL;
7016 surface->resource.allocatedMemory = NULL;
7017 surface->Flags &= ~SFLAG_DIBSECTION;
7019 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7020 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7021 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7022 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7023 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7024 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7026 surface->pow2Width = surface->pow2Height = 1;
7027 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7028 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7030 surface->glRect.left = 0;
7031 surface->glRect.top = 0;
7032 surface->glRect.right = surface->pow2Width;
7033 surface->glRect.bottom = surface->pow2Height;
7035 if(surface->glDescription.textureName) {
7036 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7038 glDeleteTextures(1, &surface->glDescription.textureName);
7040 surface->glDescription.textureName = 0;
7041 surface->Flags &= ~SFLAG_CLIENT;
7043 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7044 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7045 surface->Flags |= SFLAG_NONPOW2;
7047 surface->Flags &= ~SFLAG_NONPOW2;
7049 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7050 surface->resource.allocatedMemory = NULL;
7051 surface->resource.heapMemory = NULL;
7052 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7053 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7054 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7055 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7057 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7061 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7062 TRACE("Unloading resource %p\n", resource);
7063 IWineD3DResource_UnLoad(resource);
7064 IWineD3DResource_Release(resource);
7068 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7071 WINED3DDISPLAYMODE m;
7074 /* All Windowed modes are supported, as is leaving the current mode */
7075 if(pp->Windowed) return TRUE;
7076 if(!pp->BackBufferWidth) return TRUE;
7077 if(!pp->BackBufferHeight) return TRUE;
7079 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7080 for(i = 0; i < count; i++) {
7081 memset(&m, 0, sizeof(m));
7082 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7084 ERR("EnumAdapterModes failed\n");
7086 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7087 /* Mode found, it is supported */
7091 /* Mode not found -> not supported */
7095 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7097 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7099 IWineD3DBaseShaderImpl *shader;
7101 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7102 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7103 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7107 if(This->depth_blt_texture) {
7108 glDeleteTextures(1, &This->depth_blt_texture);
7109 This->depth_blt_texture = 0;
7111 if (This->depth_blt_rb) {
7112 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7113 This->depth_blt_rb = 0;
7114 This->depth_blt_rb_w = 0;
7115 This->depth_blt_rb_h = 0;
7119 This->blitter->free_private(iface);
7120 This->frag_pipe->free_private(iface);
7121 This->shader_backend->shader_free_private(iface);
7124 for (i = 0; i < GL_LIMITS(textures); i++) {
7125 /* Textures are recreated below */
7126 glDeleteTextures(1, &This->dummyTextureName[i]);
7127 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7128 This->dummyTextureName[i] = 0;
7132 while(This->numContexts) {
7133 DestroyContext(This, This->contexts[0]);
7135 This->activeContext = NULL;
7136 HeapFree(GetProcessHeap(), 0, swapchain->context);
7137 swapchain->context = NULL;
7138 swapchain->num_contexts = 0;
7141 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7143 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7145 IWineD3DSurfaceImpl *target;
7147 /* Recreate the primary swapchain's context */
7148 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7149 if(swapchain->backBuffer) {
7150 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7152 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7154 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7155 &swapchain->presentParms);
7156 swapchain->num_contexts = 1;
7157 This->activeContext = swapchain->context[0];
7159 create_dummy_textures(This);
7161 hr = This->shader_backend->shader_alloc_private(iface);
7163 ERR("Failed to recreate shader private data\n");
7166 hr = This->frag_pipe->alloc_private(iface);
7168 TRACE("Fragment pipeline private data couldn't be allocated\n");
7171 hr = This->blitter->alloc_private(iface);
7173 TRACE("Blitter private data couldn't be allocated\n");
7180 This->blitter->free_private(iface);
7181 This->frag_pipe->free_private(iface);
7182 This->shader_backend->shader_free_private(iface);
7186 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7188 IWineD3DSwapChainImpl *swapchain;
7190 BOOL DisplayModeChanged = FALSE;
7191 WINED3DDISPLAYMODE mode;
7192 TRACE("(%p)\n", This);
7194 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7196 ERR("Failed to get the first implicit swapchain\n");
7200 if(!is_display_mode_supported(This, pPresentationParameters)) {
7201 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7202 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7203 pPresentationParameters->BackBufferHeight);
7204 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7205 return WINED3DERR_INVALIDCALL;
7208 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7209 * on an existing gl context, so there's no real need for recreation.
7211 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7213 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7215 TRACE("New params:\n");
7216 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7217 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7218 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7219 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7220 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7221 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7222 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7223 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7224 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7225 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7226 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7227 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7228 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7230 /* No special treatment of these parameters. Just store them */
7231 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7232 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7233 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7234 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7236 /* What to do about these? */
7237 if(pPresentationParameters->BackBufferCount != 0 &&
7238 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7239 ERR("Cannot change the back buffer count yet\n");
7241 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7242 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7243 ERR("Cannot change the back buffer format yet\n");
7245 if(pPresentationParameters->hDeviceWindow != NULL &&
7246 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7247 ERR("Cannot change the device window yet\n");
7249 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7252 TRACE("Creating the depth stencil buffer\n");
7254 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
7256 pPresentationParameters->BackBufferWidth,
7257 pPresentationParameters->BackBufferHeight,
7258 pPresentationParameters->AutoDepthStencilFormat,
7259 pPresentationParameters->MultiSampleType,
7260 pPresentationParameters->MultiSampleQuality,
7262 &This->auto_depth_stencil_buffer);
7265 ERR("Failed to create the depth stencil buffer\n");
7266 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7267 return WINED3DERR_INVALIDCALL;
7271 /* Reset the depth stencil */
7272 if (pPresentationParameters->EnableAutoDepthStencil)
7273 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7275 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7277 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7279 if(pPresentationParameters->Windowed) {
7280 mode.Width = swapchain->orig_width;
7281 mode.Height = swapchain->orig_height;
7282 mode.RefreshRate = 0;
7283 mode.Format = swapchain->presentParms.BackBufferFormat;
7285 mode.Width = pPresentationParameters->BackBufferWidth;
7286 mode.Height = pPresentationParameters->BackBufferHeight;
7287 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7288 mode.Format = swapchain->presentParms.BackBufferFormat;
7291 /* Should Width == 800 && Height == 0 set 800x600? */
7292 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7293 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7294 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7298 if(!pPresentationParameters->Windowed) {
7299 DisplayModeChanged = TRUE;
7301 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7302 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7304 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7305 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7306 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7308 if(This->auto_depth_stencil_buffer) {
7309 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7313 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7314 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7315 DisplayModeChanged) {
7317 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7319 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7320 if(swapchain->presentParms.Windowed) {
7321 /* switch from windowed to fs */
7322 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7323 pPresentationParameters->BackBufferWidth,
7324 pPresentationParameters->BackBufferHeight);
7326 /* Fullscreen -> fullscreen mode change */
7327 MoveWindow(swapchain->win_handle, 0, 0,
7328 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7331 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7332 /* Fullscreen -> windowed switch */
7333 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7335 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7336 } else if(!pPresentationParameters->Windowed) {
7337 DWORD style = This->style, exStyle = This->exStyle;
7338 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7339 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7340 * Reset to clear up their mess. Guild Wars also loses the device during that.
7344 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7345 pPresentationParameters->BackBufferWidth,
7346 pPresentationParameters->BackBufferHeight);
7347 This->style = style;
7348 This->exStyle = exStyle;
7351 TRACE("Resetting stateblock\n");
7352 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7353 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7355 /* Note: No parent needed for initial internal stateblock */
7356 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7357 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7358 else TRACE("Created stateblock %p\n", This->stateBlock);
7359 This->updateStateBlock = This->stateBlock;
7360 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7362 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7364 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7367 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7368 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7370 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7376 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7378 /** FIXME: always true at the moment **/
7379 if(!bEnableDialogs) {
7380 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7386 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7388 TRACE("(%p) : pParameters %p\n", This, pParameters);
7390 *pParameters = This->createParms;
7394 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7395 IWineD3DSwapChain *swapchain;
7397 TRACE("Relaying to swapchain\n");
7399 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7400 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7401 IWineD3DSwapChain_Release(swapchain);
7406 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7407 IWineD3DSwapChain *swapchain;
7409 TRACE("Relaying to swapchain\n");
7411 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7412 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7413 IWineD3DSwapChain_Release(swapchain);
7419 /** ********************************************************
7420 * Notification functions
7421 ** ********************************************************/
7422 /** This function must be called in the release of a resource when ref == 0,
7423 * the contents of resource must still be correct,
7424 * any handles to other resource held by the caller must be closed
7425 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7426 *****************************************************/
7427 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7429 TRACE("(%p) : Adding resource %p\n", This, resource);
7431 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7434 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7436 TRACE("(%p) : Removing resource %p\n", This, resource);
7438 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7441 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7443 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7446 TRACE("(%p) : resource %p\n", This, resource);
7448 context_resource_released((IWineD3DDevice *)This, resource, type);
7451 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7452 case WINED3DRTYPE_SURFACE: {
7455 /* Cleanup any FBO attachments if d3d is enabled */
7456 if(This->d3d_initialized) {
7457 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7458 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7460 TRACE("Last active render target destroyed\n");
7461 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7462 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7463 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7464 * and the lastActiveRenderTarget member shouldn't matter
7467 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7468 TRACE("Activating primary back buffer\n");
7469 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7470 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7471 /* Single buffering environment */
7472 TRACE("Activating primary front buffer\n");
7473 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7475 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7476 /* Implicit render target destroyed, that means the device is being destroyed
7477 * whatever we set here, it shouldn't matter
7479 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7482 /* May happen during ddraw uninitialization */
7483 TRACE("Render target set, but swapchain does not exist!\n");
7484 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7488 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7489 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7490 This->render_targets[i] = NULL;
7493 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7494 This->stencilBufferTarget = NULL;
7500 case WINED3DRTYPE_TEXTURE:
7501 case WINED3DRTYPE_CUBETEXTURE:
7502 case WINED3DRTYPE_VOLUMETEXTURE:
7503 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7504 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7505 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7506 This->stateBlock->textures[counter] = NULL;
7508 if (This->updateStateBlock != This->stateBlock ){
7509 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7510 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7511 This->updateStateBlock->textures[counter] = NULL;
7516 case WINED3DRTYPE_VOLUME:
7517 /* TODO: nothing really? */
7519 case WINED3DRTYPE_BUFFER:
7522 TRACE("Cleaning up stream pointers\n");
7524 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7525 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7526 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7528 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7529 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7530 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7531 This->updateStateBlock->streamSource[streamNumber] = 0;
7532 /* Set changed flag? */
7535 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) */
7536 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7537 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7538 This->stateBlock->streamSource[streamNumber] = 0;
7543 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7544 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7545 This->updateStateBlock->pIndexData = NULL;
7548 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7549 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7550 This->stateBlock->pIndexData = NULL;
7557 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7562 /* Remove the resource from the resourceStore */
7563 device_resource_remove(This, resource);
7565 TRACE("Resource released\n");
7569 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7571 IWineD3DResourceImpl *resource, *cursor;
7573 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7575 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7576 TRACE("enumerating resource %p\n", resource);
7577 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7578 ret = pCallback((IWineD3DResource *) resource, pData);
7579 if(ret == S_FALSE) {
7580 TRACE("Canceling enumeration\n");
7587 /**********************************************************
7588 * IWineD3DDevice VTbl follows
7589 **********************************************************/
7591 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7593 /*** IUnknown methods ***/
7594 IWineD3DDeviceImpl_QueryInterface,
7595 IWineD3DDeviceImpl_AddRef,
7596 IWineD3DDeviceImpl_Release,
7597 /*** IWineD3DDevice methods ***/
7598 IWineD3DDeviceImpl_GetParent,
7599 /*** Creation methods**/
7600 IWineD3DDeviceImpl_CreateBuffer,
7601 IWineD3DDeviceImpl_CreateVertexBuffer,
7602 IWineD3DDeviceImpl_CreateIndexBuffer,
7603 IWineD3DDeviceImpl_CreateStateBlock,
7604 IWineD3DDeviceImpl_CreateSurface,
7605 IWineD3DDeviceImpl_CreateRendertargetView,
7606 IWineD3DDeviceImpl_CreateTexture,
7607 IWineD3DDeviceImpl_CreateVolumeTexture,
7608 IWineD3DDeviceImpl_CreateVolume,
7609 IWineD3DDeviceImpl_CreateCubeTexture,
7610 IWineD3DDeviceImpl_CreateQuery,
7611 IWineD3DDeviceImpl_CreateSwapChain,
7612 IWineD3DDeviceImpl_CreateVertexDeclaration,
7613 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7614 IWineD3DDeviceImpl_CreateVertexShader,
7615 IWineD3DDeviceImpl_CreatePixelShader,
7616 IWineD3DDeviceImpl_CreatePalette,
7617 /*** Odd functions **/
7618 IWineD3DDeviceImpl_Init3D,
7619 IWineD3DDeviceImpl_InitGDI,
7620 IWineD3DDeviceImpl_Uninit3D,
7621 IWineD3DDeviceImpl_UninitGDI,
7622 IWineD3DDeviceImpl_SetMultithreaded,
7623 IWineD3DDeviceImpl_EvictManagedResources,
7624 IWineD3DDeviceImpl_GetAvailableTextureMem,
7625 IWineD3DDeviceImpl_GetBackBuffer,
7626 IWineD3DDeviceImpl_GetCreationParameters,
7627 IWineD3DDeviceImpl_GetDeviceCaps,
7628 IWineD3DDeviceImpl_GetDirect3D,
7629 IWineD3DDeviceImpl_GetDisplayMode,
7630 IWineD3DDeviceImpl_SetDisplayMode,
7631 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7632 IWineD3DDeviceImpl_GetRasterStatus,
7633 IWineD3DDeviceImpl_GetSwapChain,
7634 IWineD3DDeviceImpl_Reset,
7635 IWineD3DDeviceImpl_SetDialogBoxMode,
7636 IWineD3DDeviceImpl_SetCursorProperties,
7637 IWineD3DDeviceImpl_SetCursorPosition,
7638 IWineD3DDeviceImpl_ShowCursor,
7639 IWineD3DDeviceImpl_TestCooperativeLevel,
7640 /*** Getters and setters **/
7641 IWineD3DDeviceImpl_SetClipPlane,
7642 IWineD3DDeviceImpl_GetClipPlane,
7643 IWineD3DDeviceImpl_SetClipStatus,
7644 IWineD3DDeviceImpl_GetClipStatus,
7645 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7646 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7647 IWineD3DDeviceImpl_SetDepthStencilSurface,
7648 IWineD3DDeviceImpl_GetDepthStencilSurface,
7649 IWineD3DDeviceImpl_SetGammaRamp,
7650 IWineD3DDeviceImpl_GetGammaRamp,
7651 IWineD3DDeviceImpl_SetIndices,
7652 IWineD3DDeviceImpl_GetIndices,
7653 IWineD3DDeviceImpl_SetBaseVertexIndex,
7654 IWineD3DDeviceImpl_GetBaseVertexIndex,
7655 IWineD3DDeviceImpl_SetLight,
7656 IWineD3DDeviceImpl_GetLight,
7657 IWineD3DDeviceImpl_SetLightEnable,
7658 IWineD3DDeviceImpl_GetLightEnable,
7659 IWineD3DDeviceImpl_SetMaterial,
7660 IWineD3DDeviceImpl_GetMaterial,
7661 IWineD3DDeviceImpl_SetNPatchMode,
7662 IWineD3DDeviceImpl_GetNPatchMode,
7663 IWineD3DDeviceImpl_SetPaletteEntries,
7664 IWineD3DDeviceImpl_GetPaletteEntries,
7665 IWineD3DDeviceImpl_SetPixelShader,
7666 IWineD3DDeviceImpl_GetPixelShader,
7667 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7668 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7669 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7670 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7671 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7672 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7673 IWineD3DDeviceImpl_SetRenderState,
7674 IWineD3DDeviceImpl_GetRenderState,
7675 IWineD3DDeviceImpl_SetRenderTarget,
7676 IWineD3DDeviceImpl_GetRenderTarget,
7677 IWineD3DDeviceImpl_SetFrontBackBuffers,
7678 IWineD3DDeviceImpl_SetSamplerState,
7679 IWineD3DDeviceImpl_GetSamplerState,
7680 IWineD3DDeviceImpl_SetScissorRect,
7681 IWineD3DDeviceImpl_GetScissorRect,
7682 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7683 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7684 IWineD3DDeviceImpl_SetStreamSource,
7685 IWineD3DDeviceImpl_GetStreamSource,
7686 IWineD3DDeviceImpl_SetStreamSourceFreq,
7687 IWineD3DDeviceImpl_GetStreamSourceFreq,
7688 IWineD3DDeviceImpl_SetTexture,
7689 IWineD3DDeviceImpl_GetTexture,
7690 IWineD3DDeviceImpl_SetTextureStageState,
7691 IWineD3DDeviceImpl_GetTextureStageState,
7692 IWineD3DDeviceImpl_SetTransform,
7693 IWineD3DDeviceImpl_GetTransform,
7694 IWineD3DDeviceImpl_SetVertexDeclaration,
7695 IWineD3DDeviceImpl_GetVertexDeclaration,
7696 IWineD3DDeviceImpl_SetVertexShader,
7697 IWineD3DDeviceImpl_GetVertexShader,
7698 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7699 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7700 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7701 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7702 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7703 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7704 IWineD3DDeviceImpl_SetViewport,
7705 IWineD3DDeviceImpl_GetViewport,
7706 IWineD3DDeviceImpl_MultiplyTransform,
7707 IWineD3DDeviceImpl_ValidateDevice,
7708 IWineD3DDeviceImpl_ProcessVertices,
7709 /*** State block ***/
7710 IWineD3DDeviceImpl_BeginStateBlock,
7711 IWineD3DDeviceImpl_EndStateBlock,
7712 /*** Scene management ***/
7713 IWineD3DDeviceImpl_BeginScene,
7714 IWineD3DDeviceImpl_EndScene,
7715 IWineD3DDeviceImpl_Present,
7716 IWineD3DDeviceImpl_Clear,
7717 IWineD3DDeviceImpl_ClearRendertargetView,
7719 IWineD3DDeviceImpl_SetPrimitiveType,
7720 IWineD3DDeviceImpl_GetPrimitiveType,
7721 IWineD3DDeviceImpl_DrawPrimitive,
7722 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7723 IWineD3DDeviceImpl_DrawPrimitiveUP,
7724 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7725 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7726 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7727 IWineD3DDeviceImpl_DrawRectPatch,
7728 IWineD3DDeviceImpl_DrawTriPatch,
7729 IWineD3DDeviceImpl_DeletePatch,
7730 IWineD3DDeviceImpl_ColorFill,
7731 IWineD3DDeviceImpl_UpdateTexture,
7732 IWineD3DDeviceImpl_UpdateSurface,
7733 IWineD3DDeviceImpl_GetFrontBufferData,
7734 /*** object tracking ***/
7735 IWineD3DDeviceImpl_EnumResources
7738 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7739 WINED3DRS_ALPHABLENDENABLE ,
7740 WINED3DRS_ALPHAFUNC ,
7741 WINED3DRS_ALPHAREF ,
7742 WINED3DRS_ALPHATESTENABLE ,
7744 WINED3DRS_COLORWRITEENABLE ,
7745 WINED3DRS_DESTBLEND ,
7746 WINED3DRS_DITHERENABLE ,
7747 WINED3DRS_FILLMODE ,
7748 WINED3DRS_FOGDENSITY ,
7750 WINED3DRS_FOGSTART ,
7751 WINED3DRS_LASTPIXEL ,
7752 WINED3DRS_SHADEMODE ,
7753 WINED3DRS_SRCBLEND ,
7754 WINED3DRS_STENCILENABLE ,
7755 WINED3DRS_STENCILFAIL ,
7756 WINED3DRS_STENCILFUNC ,
7757 WINED3DRS_STENCILMASK ,
7758 WINED3DRS_STENCILPASS ,
7759 WINED3DRS_STENCILREF ,
7760 WINED3DRS_STENCILWRITEMASK ,
7761 WINED3DRS_STENCILZFAIL ,
7762 WINED3DRS_TEXTUREFACTOR ,
7773 WINED3DRS_ZWRITEENABLE
7776 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7777 WINED3DTSS_ALPHAARG0 ,
7778 WINED3DTSS_ALPHAARG1 ,
7779 WINED3DTSS_ALPHAARG2 ,
7780 WINED3DTSS_ALPHAOP ,
7781 WINED3DTSS_BUMPENVLOFFSET ,
7782 WINED3DTSS_BUMPENVLSCALE ,
7783 WINED3DTSS_BUMPENVMAT00 ,
7784 WINED3DTSS_BUMPENVMAT01 ,
7785 WINED3DTSS_BUMPENVMAT10 ,
7786 WINED3DTSS_BUMPENVMAT11 ,
7787 WINED3DTSS_COLORARG0 ,
7788 WINED3DTSS_COLORARG1 ,
7789 WINED3DTSS_COLORARG2 ,
7790 WINED3DTSS_COLOROP ,
7791 WINED3DTSS_RESULTARG ,
7792 WINED3DTSS_TEXCOORDINDEX ,
7793 WINED3DTSS_TEXTURETRANSFORMFLAGS
7796 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7797 WINED3DSAMP_ADDRESSU ,
7798 WINED3DSAMP_ADDRESSV ,
7799 WINED3DSAMP_ADDRESSW ,
7800 WINED3DSAMP_BORDERCOLOR ,
7801 WINED3DSAMP_MAGFILTER ,
7802 WINED3DSAMP_MINFILTER ,
7803 WINED3DSAMP_MIPFILTER ,
7804 WINED3DSAMP_MIPMAPLODBIAS ,
7805 WINED3DSAMP_MAXMIPLEVEL ,
7806 WINED3DSAMP_MAXANISOTROPY ,
7807 WINED3DSAMP_SRGBTEXTURE ,
7808 WINED3DSAMP_ELEMENTINDEX
7811 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7813 WINED3DRS_AMBIENTMATERIALSOURCE ,
7814 WINED3DRS_CLIPPING ,
7815 WINED3DRS_CLIPPLANEENABLE ,
7816 WINED3DRS_COLORVERTEX ,
7817 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7818 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7819 WINED3DRS_FOGDENSITY ,
7821 WINED3DRS_FOGSTART ,
7822 WINED3DRS_FOGTABLEMODE ,
7823 WINED3DRS_FOGVERTEXMODE ,
7824 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7825 WINED3DRS_LIGHTING ,
7826 WINED3DRS_LOCALVIEWER ,
7827 WINED3DRS_MULTISAMPLEANTIALIAS ,
7828 WINED3DRS_MULTISAMPLEMASK ,
7829 WINED3DRS_NORMALIZENORMALS ,
7830 WINED3DRS_PATCHEDGESTYLE ,
7831 WINED3DRS_POINTSCALE_A ,
7832 WINED3DRS_POINTSCALE_B ,
7833 WINED3DRS_POINTSCALE_C ,
7834 WINED3DRS_POINTSCALEENABLE ,
7835 WINED3DRS_POINTSIZE ,
7836 WINED3DRS_POINTSIZE_MAX ,
7837 WINED3DRS_POINTSIZE_MIN ,
7838 WINED3DRS_POINTSPRITEENABLE ,
7839 WINED3DRS_RANGEFOGENABLE ,
7840 WINED3DRS_SPECULARMATERIALSOURCE ,
7841 WINED3DRS_TWEENFACTOR ,
7842 WINED3DRS_VERTEXBLEND ,
7843 WINED3DRS_CULLMODE ,
7847 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7848 WINED3DTSS_TEXCOORDINDEX ,
7849 WINED3DTSS_TEXTURETRANSFORMFLAGS
7852 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7853 WINED3DSAMP_DMAPOFFSET
7856 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7857 DWORD rep = This->StateTable[state].representative;
7861 WineD3DContext *context;
7864 for(i = 0; i < This->numContexts; i++) {
7865 context = This->contexts[i];
7866 if(isStateDirty(context, rep)) continue;
7868 context->dirtyArray[context->numDirtyEntries++] = rep;
7871 context->isStateDirty[idx] |= (1 << shift);
7875 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7876 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7877 /* The drawable size of a pbuffer render target is the current pbuffer size
7879 *width = dev->pbufferWidth;
7880 *height = dev->pbufferHeight;
7883 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7884 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7886 *width = This->pow2Width;
7887 *height = This->pow2Height;
7890 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7891 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7892 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7893 * current context's drawable, which is the size of the back buffer of the swapchain
7894 * the active context belongs to. The back buffer of the swapchain is stored as the
7895 * surface the context belongs to.
7897 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7898 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;