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 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1125 IWineD3DVolumeTextureImpl *object;
1132 /* TODO: It should only be possible to create textures for formats
1133 that are reported as supported */
1134 if (WINED3DFMT_UNKNOWN >= Format) {
1135 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1136 return WINED3DERR_INVALIDCALL;
1138 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1139 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
1140 return WINED3DERR_INVALIDCALL;
1143 /* Calculate levels for mip mapping */
1144 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1146 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1148 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1149 return WINED3DERR_INVALIDCALL;
1154 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1155 return WINED3DERR_INVALIDCALL;
1162 Levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
1163 TRACE("Calculated levels = %d\n", Levels);
1166 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1169 ERR("Out of memory\n");
1170 *ppVolumeTexture = NULL;
1171 return WINED3DERR_OUTOFVIDEOMEMORY;
1174 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1175 hr = basetexture_init((IWineD3DBaseTextureImpl *)object, Levels,
1176 WINED3DRTYPE_VOLUMETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1179 WARN("Failed to initialize basetexture, returning %#x\n", hr);
1180 HeapFree(GetProcessHeap(), 0, object);
1181 *ppVolumeTexture = NULL;
1185 TRACE("(%p) : Created basetexture %p\n", This, object);
1187 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1188 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1190 /* Is NP2 support for volumes needed? */
1191 object->baseTexture.pow2Matrix[ 0] = 1.0;
1192 object->baseTexture.pow2Matrix[ 5] = 1.0;
1193 object->baseTexture.pow2Matrix[10] = 1.0;
1194 object->baseTexture.pow2Matrix[15] = 1.0;
1196 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1198 object->baseTexture.minMipLookup = minMipLookup;
1199 object->baseTexture.magLookup = magLookup;
1201 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1202 object->baseTexture.magLookup = magLookup_noFilter;
1205 /* Generate all the surfaces */
1210 for (i = 0; i < object->baseTexture.levels; i++)
1213 /* Create the volume */
1214 hr = IWineD3DDeviceParent_CreateVolume(This->device_parent, parent,
1215 tmpW, tmpH, tmpD, Format, Pool, Usage, &object->volumes[i]);
1217 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1218 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1219 *ppVolumeTexture = NULL;
1223 /* Set its container to this object */
1224 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1226 /* calculate the next mipmap level */
1227 tmpW = max(1, tmpW >> 1);
1228 tmpH = max(1, tmpH >> 1);
1229 tmpD = max(1, tmpD >> 1);
1231 object->baseTexture.internal_preload = volumetexture_internal_preload;
1233 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1234 TRACE("(%p) : Created volume texture %p\n", This, object);
1238 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1239 UINT Width, UINT Height, UINT Depth, DWORD Usage, WINED3DFORMAT Format,
1240 WINED3DPOOL Pool, IWineD3DVolume **ppVolume, IUnknown *parent)
1242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1243 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1244 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &GLINFO_LOCATION);
1247 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1248 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1249 return WINED3DERR_INVALIDCALL;
1252 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1255 ERR("Out of memory\n");
1257 return WINED3DERR_OUTOFVIDEOMEMORY;
1260 object->lpVtbl = &IWineD3DVolume_Vtbl;
1261 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_VOLUME, This,
1262 Width * Height * Depth * format_desc->byte_count, Usage, format_desc, Pool, parent);
1265 WARN("Failed to initialize resource, returning %#x\n", hr);
1266 HeapFree(GetProcessHeap(), 0, object);
1271 TRACE("(%p) : Created resource %p\n", This, object);
1273 *ppVolume = (IWineD3DVolume *)object;
1275 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1276 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1278 object->currentDesc.Width = Width;
1279 object->currentDesc.Height = Height;
1280 object->currentDesc.Depth = Depth;
1282 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1283 object->lockable = TRUE;
1284 object->locked = FALSE;
1285 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1286 object->dirty = TRUE;
1288 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1293 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1294 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1295 WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture, IUnknown *parent)
1297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1298 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1301 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1304 ERR("Out of memory\n");
1305 *ppCubeTexture = NULL;
1306 return WINED3DERR_OUTOFVIDEOMEMORY;
1309 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1310 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent);
1313 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1314 HeapFree(GetProcessHeap(), 0, object);
1315 *ppCubeTexture = NULL;
1319 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1320 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1325 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1327 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1328 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1329 const IWineD3DQueryVtbl *vtable;
1331 /* Just a check to see if we support this type of query */
1333 case WINED3DQUERYTYPE_OCCLUSION:
1334 TRACE("(%p) occlusion query\n", This);
1335 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1338 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1340 vtable = &IWineD3DOcclusionQuery_Vtbl;
1343 case WINED3DQUERYTYPE_EVENT:
1344 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1345 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1346 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1348 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1350 vtable = &IWineD3DEventQuery_Vtbl;
1354 case WINED3DQUERYTYPE_VCACHE:
1355 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1356 case WINED3DQUERYTYPE_VERTEXSTATS:
1357 case WINED3DQUERYTYPE_TIMESTAMP:
1358 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1359 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1360 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1361 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1362 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1363 case WINED3DQUERYTYPE_PIXELTIMINGS:
1364 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1365 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1367 /* Use the base Query vtable until we have a special one for each query */
1368 vtable = &IWineD3DQuery_Vtbl;
1369 FIXME("(%p) Unhandled query type %d\n", This, Type);
1371 if(NULL == ppQuery || hr != WINED3D_OK) {
1375 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1378 ERR("Out of memory\n");
1380 return WINED3DERR_OUTOFVIDEOMEMORY;
1383 object->lpVtbl = vtable;
1384 object->type = Type;
1385 object->state = QUERY_CREATED;
1386 object->wineD3DDevice = This;
1387 object->parent = parent;
1390 *ppQuery = (IWineD3DQuery *)object;
1392 /* allocated the 'extended' data based on the type of query requested */
1394 case WINED3DQUERYTYPE_OCCLUSION:
1395 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1396 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1398 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1399 TRACE("(%p) Allocating data for an occlusion query\n", This);
1401 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1403 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1407 case WINED3DQUERYTYPE_EVENT:
1408 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1409 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1411 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1413 if(GL_SUPPORT(APPLE_FENCE)) {
1414 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1415 checkGLcall("glGenFencesAPPLE");
1416 } else if(GL_SUPPORT(NV_FENCE)) {
1417 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1418 checkGLcall("glGenFencesNV");
1423 case WINED3DQUERYTYPE_VCACHE:
1424 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1425 case WINED3DQUERYTYPE_VERTEXSTATS:
1426 case WINED3DQUERYTYPE_TIMESTAMP:
1427 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1428 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1429 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1430 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1431 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1432 case WINED3DQUERYTYPE_PIXELTIMINGS:
1433 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1434 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1436 object->extendedData = 0;
1437 FIXME("(%p) Unhandled query type %d\n",This , Type);
1439 TRACE("(%p) : Created Query %p\n", This, object);
1443 /*****************************************************************************
1444 * IWineD3DDeviceImpl_SetupFullscreenWindow
1446 * Helper function that modifies a HWND's Style and ExStyle for proper
1450 * iface: Pointer to the IWineD3DDevice interface
1451 * window: Window to setup
1453 *****************************************************************************/
1454 static LONG fullscreen_style(LONG orig_style) {
1455 LONG style = orig_style;
1456 style &= ~WS_CAPTION;
1457 style &= ~WS_THICKFRAME;
1459 /* Make sure the window is managed, otherwise we won't get keyboard input */
1460 style |= WS_POPUP | WS_SYSMENU;
1465 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1466 LONG exStyle = orig_exStyle;
1468 /* Filter out window decorations */
1469 exStyle &= ~WS_EX_WINDOWEDGE;
1470 exStyle &= ~WS_EX_CLIENTEDGE;
1475 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1478 LONG style, exStyle;
1479 /* Don't do anything if an original style is stored.
1480 * That shouldn't happen
1482 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1483 if (This->style || This->exStyle) {
1484 ERR("(%p): Want to change the window parameters of HWND %p, but "
1485 "another style is stored for restoration afterwards\n", This, window);
1488 /* Get the parameters and save them */
1489 style = GetWindowLongW(window, GWL_STYLE);
1490 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1491 This->style = style;
1492 This->exStyle = exStyle;
1494 style = fullscreen_style(style);
1495 exStyle = fullscreen_exStyle(exStyle);
1497 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1498 This->style, This->exStyle, style, exStyle);
1500 SetWindowLongW(window, GWL_STYLE, style);
1501 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1503 /* Inform the window about the update. */
1504 SetWindowPos(window, HWND_TOP, 0, 0,
1505 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1508 /*****************************************************************************
1509 * IWineD3DDeviceImpl_RestoreWindow
1511 * Helper function that restores a windows' properties when taking it out
1512 * of fullscreen mode
1515 * iface: Pointer to the IWineD3DDevice interface
1516 * window: Window to setup
1518 *****************************************************************************/
1519 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1521 LONG style, exStyle;
1523 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1524 * switch, do nothing
1526 if (!This->style && !This->exStyle) return;
1528 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1529 This, window, This->style, This->exStyle);
1531 style = GetWindowLongW(window, GWL_STYLE);
1532 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1534 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1535 * Some applications change it before calling Reset() when switching between windowed and
1536 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1538 if(style == fullscreen_style(This->style) &&
1539 exStyle == fullscreen_style(This->exStyle)) {
1540 SetWindowLongW(window, GWL_STYLE, This->style);
1541 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1544 /* Delete the old values */
1548 /* Inform the window about the update */
1549 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1550 0, 0, 0, 0, /* Pos, Size, ignored */
1551 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1554 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1555 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1556 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1557 IUnknown *parent, WINED3DSURFTYPE surface_type)
1559 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1562 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1564 IUnknown *bufferParent;
1565 BOOL displaymode_set = FALSE;
1566 WINED3DDISPLAYMODE Mode;
1567 const struct GlPixelFormatDesc *format_desc;
1569 TRACE("(%p) : Created Additional Swap Chain\n", This);
1571 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1572 * does a device hold a reference to a swap chain giving them a lifetime of the device
1573 * or does the swap chain notify the device of its destruction.
1574 *******************************/
1576 /* Check the params */
1577 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1578 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1579 return WINED3DERR_INVALIDCALL;
1580 } else if (pPresentationParameters->BackBufferCount > 1) {
1581 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");
1584 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1587 ERR("Out of memory\n");
1588 *ppSwapChain = NULL;
1589 return WINED3DERR_OUTOFVIDEOMEMORY;
1592 switch(surface_type) {
1594 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1596 case SURFACE_OPENGL:
1597 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1599 case SURFACE_UNKNOWN:
1600 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1601 HeapFree(GetProcessHeap(), 0, object);
1602 return WINED3DERR_INVALIDCALL;
1604 object->wineD3DDevice = This;
1605 object->parent = parent;
1608 *ppSwapChain = (IWineD3DSwapChain *)object;
1610 /*********************
1611 * Lookup the window Handle and the relating X window handle
1612 ********************/
1614 /* Setup hwnd we are using, plus which display this equates to */
1615 object->win_handle = pPresentationParameters->hDeviceWindow;
1616 if (!object->win_handle) {
1617 object->win_handle = This->createParms.hFocusWindow;
1619 if(!pPresentationParameters->Windowed && object->win_handle) {
1620 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1621 pPresentationParameters->BackBufferWidth,
1622 pPresentationParameters->BackBufferHeight);
1625 hDc = GetDC(object->win_handle);
1626 TRACE("Using hDc %p\n", hDc);
1629 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1630 return WINED3DERR_NOTAVAILABLE;
1633 /* Get info on the current display setup */
1634 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1635 object->orig_width = Mode.Width;
1636 object->orig_height = Mode.Height;
1637 object->orig_fmt = Mode.Format;
1638 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1640 if (pPresentationParameters->Windowed &&
1641 ((pPresentationParameters->BackBufferWidth == 0) ||
1642 (pPresentationParameters->BackBufferHeight == 0) ||
1643 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1646 GetClientRect(object->win_handle, &Rect);
1648 if (pPresentationParameters->BackBufferWidth == 0) {
1649 pPresentationParameters->BackBufferWidth = Rect.right;
1650 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1652 if (pPresentationParameters->BackBufferHeight == 0) {
1653 pPresentationParameters->BackBufferHeight = Rect.bottom;
1654 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1656 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1657 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1658 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1662 /* Put the correct figures in the presentation parameters */
1663 TRACE("Copying across presentation parameters\n");
1664 object->presentParms = *pPresentationParameters;
1666 TRACE("calling rendertarget CB\n");
1667 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1668 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1669 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1670 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1671 if (SUCCEEDED(hr)) {
1672 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1673 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1674 if(surface_type == SURFACE_OPENGL) {
1675 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1678 ERR("Failed to create the front buffer\n");
1682 /*********************
1683 * Windowed / Fullscreen
1684 *******************/
1687 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1688 * so we should really check to see if there is a fullscreen swapchain already
1689 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1690 **************************************/
1692 if (!pPresentationParameters->Windowed) {
1693 WINED3DDISPLAYMODE mode;
1696 /* Change the display settings */
1697 mode.Width = pPresentationParameters->BackBufferWidth;
1698 mode.Height = pPresentationParameters->BackBufferHeight;
1699 mode.Format = pPresentationParameters->BackBufferFormat;
1700 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1702 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1703 displaymode_set = TRUE;
1707 * Create an opengl context for the display visual
1708 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1709 * use different properties after that point in time. FIXME: How to handle when requested format
1710 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1711 * it chooses is identical to the one already being used!
1712 **********************************/
1713 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1715 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1716 if(!object->context) {
1717 ERR("Failed to create the context array\n");
1721 object->num_contexts = 1;
1723 if(surface_type == SURFACE_OPENGL) {
1724 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1725 if (!object->context[0]) {
1726 ERR("Failed to create a new context\n");
1727 hr = WINED3DERR_NOTAVAILABLE;
1730 TRACE("Context created (HWND=%p, glContext=%p)\n",
1731 object->win_handle, object->context[0]->glCtx);
1735 /*********************
1736 * Create the back, front and stencil buffers
1737 *******************/
1738 if(object->presentParms.BackBufferCount > 0) {
1741 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1742 if(!object->backBuffer) {
1743 ERR("Out of memory\n");
1748 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1749 TRACE("calling rendertarget CB\n");
1750 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1751 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1752 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1753 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1755 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1756 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1758 ERR("Cannot create new back buffer\n");
1761 if(surface_type == SURFACE_OPENGL) {
1763 glDrawBuffer(GL_BACK);
1764 checkGLcall("glDrawBuffer(GL_BACK)");
1769 object->backBuffer = NULL;
1771 /* Single buffering - draw to front buffer */
1772 if(surface_type == SURFACE_OPENGL) {
1774 glDrawBuffer(GL_FRONT);
1775 checkGLcall("glDrawBuffer(GL_FRONT)");
1780 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1781 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1782 TRACE("Creating depth stencil buffer\n");
1783 if (This->auto_depth_stencil_buffer == NULL ) {
1784 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1785 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1786 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1787 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1788 &This->auto_depth_stencil_buffer);
1789 if (SUCCEEDED(hr)) {
1790 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1792 ERR("Failed to create the auto depth stencil\n");
1798 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1800 TRACE("Created swapchain %p\n", object);
1801 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1805 if (displaymode_set) {
1809 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1812 /* Change the display settings */
1813 memset(&devmode, 0, sizeof(devmode));
1814 devmode.dmSize = sizeof(devmode);
1815 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1816 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1817 devmode.dmPelsWidth = object->orig_width;
1818 devmode.dmPelsHeight = object->orig_height;
1819 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1822 if (object->backBuffer) {
1824 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1825 if(object->backBuffer[i]) {
1826 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1827 IUnknown_Release(bufferParent); /* once for the get parent */
1828 if (IUnknown_Release(bufferParent) > 0) {
1829 FIXME("(%p) Something's still holding the back buffer\n",This);
1833 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1834 object->backBuffer = NULL;
1836 if(object->context && object->context[0])
1837 DestroyContext(This, object->context[0]);
1838 if(object->frontBuffer) {
1839 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1840 IUnknown_Release(bufferParent); /* once for the get parent */
1841 if (IUnknown_Release(bufferParent) > 0) {
1842 FIXME("(%p) Something's still holding the front buffer\n",This);
1845 HeapFree(GetProcessHeap(), 0, object);
1849 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1850 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1852 TRACE("(%p)\n", This);
1854 return This->NumberOfSwapChains;
1857 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1859 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1861 if(iSwapChain < This->NumberOfSwapChains) {
1862 *pSwapChain = This->swapchains[iSwapChain];
1863 IWineD3DSwapChain_AddRef(*pSwapChain);
1864 TRACE("(%p) returning %p\n", This, *pSwapChain);
1867 TRACE("Swapchain out of range\n");
1869 return WINED3DERR_INVALIDCALL;
1874 * Vertex Declaration
1876 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1877 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1879 IWineD3DVertexDeclarationImpl *object = NULL;
1880 HRESULT hr = WINED3D_OK;
1882 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1883 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1885 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1888 ERR("Out of memory\n");
1889 *ppVertexDeclaration = NULL;
1890 return WINED3DERR_OUTOFVIDEOMEMORY;
1893 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
1894 object->wineD3DDevice = This;
1895 object->parent = parent;
1898 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1900 hr = vertexdeclaration_init(object, elements, element_count);
1903 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1904 *ppVertexDeclaration = NULL;
1910 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1911 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1913 unsigned int idx, idx2;
1914 unsigned int offset;
1915 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1916 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1917 BOOL has_blend_idx = has_blend &&
1918 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1919 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1920 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1921 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1922 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1923 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1924 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1926 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1927 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1928 WINED3DVERTEXELEMENT *elements = NULL;
1931 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1932 if (has_blend_idx) num_blends--;
1934 /* Compute declaration size */
1935 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1936 has_psize + has_diffuse + has_specular + num_textures;
1938 /* convert the declaration */
1939 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1940 if (!elements) return ~0U;
1944 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1945 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1946 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1948 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1949 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1950 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1953 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1954 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1956 elements[idx].usage_idx = 0;
1959 if (has_blend && (num_blends > 0)) {
1960 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1961 elements[idx].format = WINED3DFMT_A8R8G8B8;
1963 switch(num_blends) {
1964 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1965 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1966 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1967 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1969 ERR("Unexpected amount of blend values: %u\n", num_blends);
1972 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1973 elements[idx].usage_idx = 0;
1976 if (has_blend_idx) {
1977 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1978 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1979 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1980 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1981 elements[idx].format = WINED3DFMT_A8R8G8B8;
1983 elements[idx].format = WINED3DFMT_R32_FLOAT;
1984 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1985 elements[idx].usage_idx = 0;
1989 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1990 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1991 elements[idx].usage_idx = 0;
1995 elements[idx].format = WINED3DFMT_R32_FLOAT;
1996 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1997 elements[idx].usage_idx = 0;
2001 elements[idx].format = WINED3DFMT_A8R8G8B8;
2002 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
2003 elements[idx].usage_idx = 0;
2007 elements[idx].format = WINED3DFMT_A8R8G8B8;
2008 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
2009 elements[idx].usage_idx = 1;
2012 for (idx2 = 0; idx2 < num_textures; idx2++) {
2013 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
2014 switch (numcoords) {
2015 case WINED3DFVF_TEXTUREFORMAT1:
2016 elements[idx].format = WINED3DFMT_R32_FLOAT;
2018 case WINED3DFVF_TEXTUREFORMAT2:
2019 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
2021 case WINED3DFVF_TEXTUREFORMAT3:
2022 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2024 case WINED3DFVF_TEXTUREFORMAT4:
2025 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2028 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
2029 elements[idx].usage_idx = idx2;
2033 /* Now compute offsets, and initialize the rest of the fields */
2034 for (idx = 0, offset = 0; idx < size; ++idx)
2036 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
2037 elements[idx].input_slot = 0;
2038 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
2039 elements[idx].offset = offset;
2040 offset += format_desc->component_count * format_desc->component_size;
2043 *ppVertexElements = elements;
2047 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
2048 WINED3DVERTEXELEMENT* elements = NULL;
2049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2053 size = ConvertFvfToDeclaration(This, Fvf, &elements);
2054 if (size == ~0U) return WINED3DERR_OUTOFVIDEOMEMORY;
2056 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
2057 HeapFree(GetProcessHeap(), 0, elements);
2058 if (hr != S_OK) return hr;
2063 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
2064 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
2065 IWineD3DVertexShader **ppVertexShader, IUnknown *parent)
2067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2068 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
2069 HRESULT hr = WINED3D_OK;
2071 if (!pFunction) return WINED3DERR_INVALIDCALL;
2073 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2076 ERR("Out of memory\n");
2077 *ppVertexShader = NULL;
2078 return WINED3DERR_OUTOFVIDEOMEMORY;
2081 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
2082 object->parent = parent;
2083 shader_init(&object->baseShader, iface);
2084 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2085 *ppVertexShader = (IWineD3DVertexShader *)object;
2087 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
2089 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction, output_signature);
2092 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2093 IWineD3DVertexShader_Release(*ppVertexShader);
2094 *ppVertexShader = NULL;
2101 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
2102 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
2103 IWineD3DPixelShader **ppPixelShader, IUnknown *parent)
2105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2106 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2107 HRESULT hr = WINED3D_OK;
2109 if (!pFunction) return WINED3DERR_INVALIDCALL;
2111 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2114 ERR("Out of memory\n");
2115 *ppPixelShader = NULL;
2116 return WINED3DERR_OUTOFVIDEOMEMORY;
2119 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
2120 object->parent = parent;
2121 shader_init(&object->baseShader, iface);
2122 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2123 *ppPixelShader = (IWineD3DPixelShader *)object;
2125 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
2127 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction, output_signature);
2130 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2131 IWineD3DPixelShader_Release(*ppPixelShader);
2132 *ppPixelShader = NULL;
2139 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
2140 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
2142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2143 IWineD3DPaletteImpl *object;
2145 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2147 /* Create the new object */
2148 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2150 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2151 return E_OUTOFMEMORY;
2154 object->lpVtbl = &IWineD3DPalette_Vtbl;
2156 object->Flags = Flags;
2157 object->parent = Parent;
2158 object->wineD3DDevice = This;
2159 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2160 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2163 HeapFree( GetProcessHeap(), 0, object);
2164 return E_OUTOFMEMORY;
2167 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2169 IWineD3DPalette_Release((IWineD3DPalette *) object);
2173 *Palette = (IWineD3DPalette *) object;
2178 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2182 HDC dcb = NULL, dcs = NULL;
2183 WINEDDCOLORKEY colorkey;
2185 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2188 GetObjectA(hbm, sizeof(BITMAP), &bm);
2189 dcb = CreateCompatibleDC(NULL);
2191 SelectObject(dcb, hbm);
2195 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2196 * couldn't be loaded
2198 memset(&bm, 0, sizeof(bm));
2203 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2204 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2205 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL);
2207 ERR("Wine logo requested, but failed to create surface\n");
2212 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2213 if(FAILED(hr)) goto out;
2214 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2215 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2217 colorkey.dwColorSpaceLowValue = 0;
2218 colorkey.dwColorSpaceHighValue = 0;
2219 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2221 /* Fill the surface with a white color to show that wined3d is there */
2222 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2235 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2237 /* Under DirectX you can have texture stage operations even if no texture is
2238 bound, whereas opengl will only do texture operations when a valid texture is
2239 bound. We emulate this by creating dummy textures and binding them to each
2240 texture stage, but disable all stages by default. Hence if a stage is enabled
2241 then the default texture will kick in until replaced by a SetTexture call */
2244 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2245 /* The dummy texture does not have client storage backing */
2246 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2247 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2249 for (i = 0; i < GL_LIMITS(textures); i++) {
2250 GLubyte white = 255;
2252 /* Make appropriate texture active */
2253 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2254 checkGLcall("glActiveTextureARB");
2256 /* Generate an opengl texture name */
2257 glGenTextures(1, &This->dummyTextureName[i]);
2258 checkGLcall("glGenTextures");
2259 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2261 /* Generate a dummy 2d texture (not using 1d because they cause many
2262 * DRI drivers fall back to sw) */
2263 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2264 checkGLcall("glBindTexture");
2266 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2267 checkGLcall("glTexImage2D");
2269 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2270 /* Reenable because if supported it is enabled by default */
2271 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2272 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2278 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2279 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2282 IWineD3DSwapChainImpl *swapchain = NULL;
2287 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2289 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2290 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2292 /* TODO: Test if OpenGL is compiled in and loaded */
2294 TRACE("(%p) : Creating stateblock\n", This);
2295 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2296 hr = IWineD3DDevice_CreateStateBlock(iface,
2298 (IWineD3DStateBlock **)&This->stateBlock,
2300 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2301 WARN("Failed to create stateblock\n");
2304 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2305 This->updateStateBlock = This->stateBlock;
2306 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2308 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2309 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2311 This->NumberOfPalettes = 1;
2312 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2313 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2314 ERR("Out of memory!\n");
2317 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2318 if(!This->palettes[0]) {
2319 ERR("Out of memory!\n");
2322 for (i = 0; i < 256; ++i) {
2323 This->palettes[0][i].peRed = 0xFF;
2324 This->palettes[0][i].peGreen = 0xFF;
2325 This->palettes[0][i].peBlue = 0xFF;
2326 This->palettes[0][i].peFlags = 0xFF;
2328 This->currentPalette = 0;
2330 /* Initialize the texture unit mapping to a 1:1 mapping */
2331 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2332 if (state < GL_LIMITS(fragment_samplers)) {
2333 This->texUnitMap[state] = state;
2334 This->rev_tex_unit_map[state] = state;
2336 This->texUnitMap[state] = -1;
2337 This->rev_tex_unit_map[state] = -1;
2341 /* Setup the implicit swapchain */
2342 TRACE("Creating implicit swapchain\n");
2343 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2344 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2347 WARN("Failed to create implicit swapchain\n");
2351 This->NumberOfSwapChains = 1;
2352 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2353 if(!This->swapchains) {
2354 ERR("Out of memory!\n");
2357 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2359 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2360 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2361 This->render_targets[0] = swapchain->backBuffer[0];
2362 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2365 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2366 This->render_targets[0] = swapchain->frontBuffer;
2367 This->lastActiveRenderTarget = swapchain->frontBuffer;
2369 IWineD3DSurface_AddRef(This->render_targets[0]);
2370 This->activeContext = swapchain->context[0];
2371 This->lastThread = GetCurrentThreadId();
2373 /* Depth Stencil support */
2374 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2375 if (NULL != This->stencilBufferTarget) {
2376 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2379 hr = This->shader_backend->shader_alloc_private(iface);
2381 TRACE("Shader private data couldn't be allocated\n");
2384 hr = This->frag_pipe->alloc_private(iface);
2386 TRACE("Fragment pipeline private data couldn't be allocated\n");
2389 hr = This->blitter->alloc_private(iface);
2391 TRACE("Blitter private data couldn't be allocated\n");
2395 /* Set up some starting GL setup */
2397 /* Setup all the devices defaults */
2398 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2399 create_dummy_textures(This);
2403 /* Initialize the current view state */
2404 This->view_ident = 1;
2405 This->contexts[0]->last_was_rhw = 0;
2406 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2407 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2409 switch(wined3d_settings.offscreen_rendering_mode) {
2412 This->offscreenBuffer = GL_BACK;
2415 case ORM_BACKBUFFER:
2417 if(This->activeContext->aux_buffers > 0) {
2418 TRACE("Using auxilliary buffer for offscreen rendering\n");
2419 This->offscreenBuffer = GL_AUX0;
2421 TRACE("Using back buffer for offscreen rendering\n");
2422 This->offscreenBuffer = GL_BACK;
2427 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2430 /* Clear the screen */
2431 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2432 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2435 This->d3d_initialized = TRUE;
2437 if(wined3d_settings.logo) {
2438 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2440 This->highest_dirty_ps_const = 0;
2441 This->highest_dirty_vs_const = 0;
2445 HeapFree(GetProcessHeap(), 0, This->render_targets);
2446 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2447 HeapFree(GetProcessHeap(), 0, This->swapchains);
2448 This->NumberOfSwapChains = 0;
2449 if(This->palettes) {
2450 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2451 HeapFree(GetProcessHeap(), 0, This->palettes);
2453 This->NumberOfPalettes = 0;
2455 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2457 if(This->stateBlock) {
2458 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2459 This->stateBlock = NULL;
2461 if (This->blit_priv) {
2462 This->blitter->free_private(iface);
2464 if (This->fragment_priv) {
2465 This->frag_pipe->free_private(iface);
2467 if (This->shader_priv) {
2468 This->shader_backend->shader_free_private(iface);
2473 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2474 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2477 IWineD3DSwapChainImpl *swapchain = NULL;
2480 /* Setup the implicit swapchain */
2481 TRACE("Creating implicit swapchain\n");
2482 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2483 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2486 WARN("Failed to create implicit swapchain\n");
2490 This->NumberOfSwapChains = 1;
2491 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2492 if(!This->swapchains) {
2493 ERR("Out of memory!\n");
2496 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2500 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2504 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2506 IWineD3DResource_UnLoad(resource);
2507 IWineD3DResource_Release(resource);
2511 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2515 TRACE("(%p)\n", This);
2517 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2519 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2520 * it was created. Thus make sure a context is active for the glDelete* calls
2522 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2524 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2526 /* Unload resources */
2527 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2529 TRACE("Deleting high order patches\n");
2530 for(i = 0; i < PATCHMAP_SIZE; i++) {
2531 struct list *e1, *e2;
2532 struct WineD3DRectPatch *patch;
2533 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2534 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2535 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2539 /* Delete the palette conversion shader if it is around */
2540 if(This->paletteConversionShader) {
2542 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2544 This->paletteConversionShader = 0;
2547 /* Delete the pbuffer context if there is any */
2548 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2550 /* Delete the mouse cursor texture */
2551 if(This->cursorTexture) {
2553 glDeleteTextures(1, &This->cursorTexture);
2555 This->cursorTexture = 0;
2558 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2559 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2561 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2562 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2565 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2566 * private data, it might contain opengl pointers
2568 if(This->depth_blt_texture) {
2570 glDeleteTextures(1, &This->depth_blt_texture);
2572 This->depth_blt_texture = 0;
2574 if (This->depth_blt_rb) {
2576 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2578 This->depth_blt_rb = 0;
2579 This->depth_blt_rb_w = 0;
2580 This->depth_blt_rb_h = 0;
2583 /* Release the update stateblock */
2584 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2585 if(This->updateStateBlock != This->stateBlock)
2586 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2588 This->updateStateBlock = NULL;
2590 { /* because were not doing proper internal refcounts releasing the primary state block
2591 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2592 to set this->stateBlock = NULL; first */
2593 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2594 This->stateBlock = NULL;
2596 /* Release the stateblock */
2597 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2598 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2602 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2603 This->blitter->free_private(iface);
2604 This->frag_pipe->free_private(iface);
2605 This->shader_backend->shader_free_private(iface);
2607 /* Release the buffers (with sanity checks)*/
2608 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2609 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2610 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2611 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2613 This->stencilBufferTarget = NULL;
2615 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2616 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2617 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2619 TRACE("Setting rendertarget to NULL\n");
2620 This->render_targets[0] = NULL;
2622 if (This->auto_depth_stencil_buffer) {
2623 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2624 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2626 This->auto_depth_stencil_buffer = NULL;
2629 for(i=0; i < This->NumberOfSwapChains; i++) {
2630 TRACE("Releasing the implicit swapchain %d\n", i);
2631 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2632 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2636 HeapFree(GetProcessHeap(), 0, This->swapchains);
2637 This->swapchains = NULL;
2638 This->NumberOfSwapChains = 0;
2640 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2641 HeapFree(GetProcessHeap(), 0, This->palettes);
2642 This->palettes = NULL;
2643 This->NumberOfPalettes = 0;
2645 HeapFree(GetProcessHeap(), 0, This->render_targets);
2646 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2647 This->render_targets = NULL;
2648 This->draw_buffers = NULL;
2650 This->d3d_initialized = FALSE;
2654 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2658 for(i=0; i < This->NumberOfSwapChains; i++) {
2659 TRACE("Releasing the implicit swapchain %d\n", i);
2660 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2661 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2665 HeapFree(GetProcessHeap(), 0, This->swapchains);
2666 This->swapchains = NULL;
2667 This->NumberOfSwapChains = 0;
2671 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2672 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2673 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2675 * There is no way to deactivate thread safety once it is enabled.
2677 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2680 /*For now just store the flag(needed in case of ddraw) */
2681 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2686 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2687 const WINED3DDISPLAYMODE* pMode) {
2689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2691 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2694 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2696 /* Resize the screen even without a window:
2697 * The app could have unset it with SetCooperativeLevel, but not called
2698 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2699 * but we don't have any hwnd
2702 memset(&devmode, 0, sizeof(devmode));
2703 devmode.dmSize = sizeof(devmode);
2704 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2705 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2706 devmode.dmPelsWidth = pMode->Width;
2707 devmode.dmPelsHeight = pMode->Height;
2709 devmode.dmDisplayFrequency = pMode->RefreshRate;
2710 if (pMode->RefreshRate != 0) {
2711 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2714 /* Only change the mode if necessary */
2715 if( (This->ddraw_width == pMode->Width) &&
2716 (This->ddraw_height == pMode->Height) &&
2717 (This->ddraw_format == pMode->Format) &&
2718 (pMode->RefreshRate == 0) ) {
2722 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2723 if (ret != DISP_CHANGE_SUCCESSFUL) {
2724 if(devmode.dmDisplayFrequency != 0) {
2725 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2726 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2727 devmode.dmDisplayFrequency = 0;
2728 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2730 if(ret != DISP_CHANGE_SUCCESSFUL) {
2731 return WINED3DERR_NOTAVAILABLE;
2735 /* Store the new values */
2736 This->ddraw_width = pMode->Width;
2737 This->ddraw_height = pMode->Height;
2738 This->ddraw_format = pMode->Format;
2740 /* And finally clip mouse to our screen */
2741 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2742 ClipCursor(&clip_rc);
2747 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2748 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2749 *ppD3D= This->wineD3D;
2750 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2751 IWineD3D_AddRef(*ppD3D);
2755 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2758 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2759 (This->adapter->TextureRam/(1024*1024)),
2760 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2761 /* return simulated texture memory left */
2762 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2766 * Get / Set Stream Source
2768 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2769 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2772 IWineD3DBuffer *oldSrc;
2774 if (StreamNumber >= MAX_STREAMS) {
2775 WARN("Stream out of range %d\n", StreamNumber);
2776 return WINED3DERR_INVALIDCALL;
2777 } else if(OffsetInBytes & 0x3) {
2778 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2779 return WINED3DERR_INVALIDCALL;
2782 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2783 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2785 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2787 if(oldSrc == pStreamData &&
2788 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2789 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2790 TRACE("Application is setting the old values over, nothing to do\n");
2794 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2796 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2797 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2800 /* Handle recording of state blocks */
2801 if (This->isRecordingState) {
2802 TRACE("Recording... not performing anything\n");
2803 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2804 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2808 if (pStreamData != NULL) {
2809 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2810 IWineD3DBuffer_AddRef(pStreamData);
2812 if (oldSrc != NULL) {
2813 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2814 IWineD3DBuffer_Release(oldSrc);
2817 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2822 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2823 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2825 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2827 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2828 This->stateBlock->streamSource[StreamNumber],
2829 This->stateBlock->streamOffset[StreamNumber],
2830 This->stateBlock->streamStride[StreamNumber]);
2832 if (StreamNumber >= MAX_STREAMS) {
2833 WARN("Stream out of range %d\n", StreamNumber);
2834 return WINED3DERR_INVALIDCALL;
2836 *pStream = This->stateBlock->streamSource[StreamNumber];
2837 *pStride = This->stateBlock->streamStride[StreamNumber];
2839 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2842 if (*pStream != NULL) {
2843 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2848 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2850 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2851 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2853 /* Verify input at least in d3d9 this is invalid*/
2854 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2855 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2856 return WINED3DERR_INVALIDCALL;
2858 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2859 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2860 return WINED3DERR_INVALIDCALL;
2863 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2864 return WINED3DERR_INVALIDCALL;
2867 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2868 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2870 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2871 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2873 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2874 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2875 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2881 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2884 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2885 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2887 TRACE("(%p) : returning %d\n", This, *Divider);
2893 * Get / Set & Multiply Transform
2895 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2898 /* Most of this routine, comments included copied from ddraw tree initially: */
2899 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2901 /* Handle recording of state blocks */
2902 if (This->isRecordingState) {
2903 TRACE("Recording... not performing anything\n");
2904 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2905 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2910 * If the new matrix is the same as the current one,
2911 * we cut off any further processing. this seems to be a reasonable
2912 * optimization because as was noticed, some apps (warcraft3 for example)
2913 * tend towards setting the same matrix repeatedly for some reason.
2915 * From here on we assume that the new matrix is different, wherever it matters.
2917 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2918 TRACE("The app is setting the same matrix over again\n");
2921 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2925 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2926 where ViewMat = Camera space, WorldMat = world space.
2928 In OpenGL, camera and world space is combined into GL_MODELVIEW
2929 matrix. The Projection matrix stay projection matrix.
2932 /* Capture the times we can just ignore the change for now */
2933 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2934 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2935 /* Handled by the state manager */
2938 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2942 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2944 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2945 *pMatrix = This->stateBlock->transforms[State];
2949 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2950 const WINED3DMATRIX *mat = NULL;
2953 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2954 * below means it will be recorded in a state block change, but it
2955 * works regardless where it is recorded.
2956 * If this is found to be wrong, change to StateBlock.
2958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2959 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2961 if (State <= HIGHEST_TRANSFORMSTATE)
2963 mat = &This->updateStateBlock->transforms[State];
2965 FIXME("Unhandled transform state!!\n");
2968 multiply_matrix(&temp, mat, pMatrix);
2970 /* Apply change via set transform - will reapply to eg. lights this way */
2971 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2977 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2978 you can reference any indexes you want as long as that number max are enabled at any
2979 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2980 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2981 but when recording, just build a chain pretty much of commands to be replayed. */
2983 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2985 PLIGHTINFOEL *object = NULL;
2986 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2989 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2990 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2992 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2996 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2997 return WINED3DERR_INVALIDCALL;
3000 switch(pLight->Type) {
3001 case WINED3DLIGHT_POINT:
3002 case WINED3DLIGHT_SPOT:
3003 case WINED3DLIGHT_PARALLELPOINT:
3004 case WINED3DLIGHT_GLSPOT:
3005 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
3008 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
3009 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
3010 return WINED3DERR_INVALIDCALL;
3014 case WINED3DLIGHT_DIRECTIONAL:
3015 /* Ignores attenuation */
3019 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
3020 return WINED3DERR_INVALIDCALL;
3023 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3024 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3025 if(object->OriginalIndex == Index) break;
3030 TRACE("Adding new light\n");
3031 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
3033 ERR("Out of memory error when allocating a light\n");
3034 return E_OUTOFMEMORY;
3036 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
3037 object->glIndex = -1;
3038 object->OriginalIndex = Index;
3039 object->changed = TRUE;
3042 /* Initialize the object */
3043 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,
3044 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
3045 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
3046 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
3047 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
3048 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
3049 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
3051 /* Save away the information */
3052 object->OriginalParms = *pLight;
3054 switch (pLight->Type) {
3055 case WINED3DLIGHT_POINT:
3057 object->lightPosn[0] = pLight->Position.x;
3058 object->lightPosn[1] = pLight->Position.y;
3059 object->lightPosn[2] = pLight->Position.z;
3060 object->lightPosn[3] = 1.0f;
3061 object->cutoff = 180.0f;
3065 case WINED3DLIGHT_DIRECTIONAL:
3067 object->lightPosn[0] = -pLight->Direction.x;
3068 object->lightPosn[1] = -pLight->Direction.y;
3069 object->lightPosn[2] = -pLight->Direction.z;
3070 object->lightPosn[3] = 0.0;
3071 object->exponent = 0.0f;
3072 object->cutoff = 180.0f;
3075 case WINED3DLIGHT_SPOT:
3077 object->lightPosn[0] = pLight->Position.x;
3078 object->lightPosn[1] = pLight->Position.y;
3079 object->lightPosn[2] = pLight->Position.z;
3080 object->lightPosn[3] = 1.0;
3083 object->lightDirn[0] = pLight->Direction.x;
3084 object->lightDirn[1] = pLight->Direction.y;
3085 object->lightDirn[2] = pLight->Direction.z;
3086 object->lightDirn[3] = 1.0;
3089 * opengl-ish and d3d-ish spot lights use too different models for the
3090 * light "intensity" as a function of the angle towards the main light direction,
3091 * so we only can approximate very roughly.
3092 * however spot lights are rather rarely used in games (if ever used at all).
3093 * furthermore if still used, probably nobody pays attention to such details.
3095 if (pLight->Falloff == 0) {
3096 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3097 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3098 * will always be 1.0 for both of them, and we don't have to care for the
3099 * rest of the rather complex calculation
3101 object->exponent = 0;
3103 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
3104 if (rho < 0.0001) rho = 0.0001f;
3105 object->exponent = -0.3/log(cos(rho/2));
3107 if (object->exponent > 128.0) {
3108 object->exponent = 128.0;
3110 object->cutoff = pLight->Phi*90/M_PI;
3116 FIXME("Unrecognized light type %d\n", pLight->Type);
3119 /* Update the live definitions if the light is currently assigned a glIndex */
3120 if (object->glIndex != -1 && !This->isRecordingState) {
3121 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
3126 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
3127 PLIGHTINFOEL *lightInfo = NULL;
3128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3129 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
3131 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
3133 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3134 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3135 if(lightInfo->OriginalIndex == Index) break;
3139 if (lightInfo == NULL) {
3140 TRACE("Light information requested but light not defined\n");
3141 return WINED3DERR_INVALIDCALL;
3144 *pLight = lightInfo->OriginalParms;
3149 * Get / Set Light Enable
3150 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3152 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
3153 PLIGHTINFOEL *lightInfo = NULL;
3154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3155 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3157 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
3159 /* Tests show true = 128...not clear why */
3160 Enable = Enable? 128: 0;
3162 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3163 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3164 if(lightInfo->OriginalIndex == Index) break;
3167 TRACE("Found light: %p\n", lightInfo);
3169 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3170 if (lightInfo == NULL) {
3172 TRACE("Light enabled requested but light not defined, so defining one!\n");
3173 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3175 /* Search for it again! Should be fairly quick as near head of list */
3176 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3177 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3178 if(lightInfo->OriginalIndex == Index) break;
3181 if (lightInfo == NULL) {
3182 FIXME("Adding default lights has failed dismally\n");
3183 return WINED3DERR_INVALIDCALL;
3187 lightInfo->enabledChanged = TRUE;
3189 if(lightInfo->glIndex != -1) {
3190 if(!This->isRecordingState) {
3191 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3194 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3195 lightInfo->glIndex = -1;
3197 TRACE("Light already disabled, nothing to do\n");
3199 lightInfo->enabled = FALSE;
3201 lightInfo->enabled = TRUE;
3202 if (lightInfo->glIndex != -1) {
3204 TRACE("Nothing to do as light was enabled\n");
3207 /* Find a free gl light */
3208 for(i = 0; i < This->maxConcurrentLights; i++) {
3209 if(This->updateStateBlock->activeLights[i] == NULL) {
3210 This->updateStateBlock->activeLights[i] = lightInfo;
3211 lightInfo->glIndex = i;
3215 if(lightInfo->glIndex == -1) {
3216 /* Our tests show that Windows returns D3D_OK in this situation, even with
3217 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3218 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3219 * as well for those lights.
3221 * TODO: Test how this affects rendering
3223 WARN("Too many concurrently active lights\n");
3227 /* i == lightInfo->glIndex */
3228 if(!This->isRecordingState) {
3229 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3237 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3239 PLIGHTINFOEL *lightInfo = NULL;
3240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3242 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3243 TRACE("(%p) : for idx(%d)\n", This, Index);
3245 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3246 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3247 if(lightInfo->OriginalIndex == Index) break;
3251 if (lightInfo == NULL) {
3252 TRACE("Light enabled state requested but light not defined\n");
3253 return WINED3DERR_INVALIDCALL;
3255 /* true is 128 according to SetLightEnable */
3256 *pEnable = lightInfo->enabled ? 128 : 0;
3261 * Get / Set Clip Planes
3263 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3265 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3267 /* Validate Index */
3268 if (Index >= GL_LIMITS(clipplanes)) {
3269 TRACE("Application has requested clipplane this device doesn't support\n");
3270 return WINED3DERR_INVALIDCALL;
3273 This->updateStateBlock->changed.clipplane |= 1 << Index;
3275 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3276 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3277 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3278 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3279 TRACE("Application is setting old values over, nothing to do\n");
3283 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3284 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3285 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3286 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3288 /* Handle recording of state blocks */
3289 if (This->isRecordingState) {
3290 TRACE("Recording... not performing anything\n");
3294 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3299 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3301 TRACE("(%p) : for idx %d\n", This, Index);
3303 /* Validate Index */
3304 if (Index >= GL_LIMITS(clipplanes)) {
3305 TRACE("Application has requested clipplane this device doesn't support\n");
3306 return WINED3DERR_INVALIDCALL;
3309 pPlane[0] = This->stateBlock->clipplane[Index][0];
3310 pPlane[1] = This->stateBlock->clipplane[Index][1];
3311 pPlane[2] = This->stateBlock->clipplane[Index][2];
3312 pPlane[3] = This->stateBlock->clipplane[Index][3];
3317 * Get / Set Clip Plane Status
3318 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3320 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3322 FIXME("(%p) : stub\n", This);
3323 if (NULL == pClipStatus) {
3324 return WINED3DERR_INVALIDCALL;
3326 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3327 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3331 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3333 FIXME("(%p) : stub\n", This);
3334 if (NULL == pClipStatus) {
3335 return WINED3DERR_INVALIDCALL;
3337 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3338 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3343 * Get / Set Material
3345 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3348 This->updateStateBlock->changed.material = TRUE;
3349 This->updateStateBlock->material = *pMaterial;
3351 /* Handle recording of state blocks */
3352 if (This->isRecordingState) {
3353 TRACE("Recording... not performing anything\n");
3357 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3361 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3363 *pMaterial = This->updateStateBlock->material;
3364 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3365 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3366 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3367 pMaterial->Ambient.b, pMaterial->Ambient.a);
3368 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3369 pMaterial->Specular.b, pMaterial->Specular.a);
3370 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3371 pMaterial->Emissive.b, pMaterial->Emissive.a);
3372 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3380 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DBuffer* pIndexData, WINED3DFORMAT fmt) {
3381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3382 IWineD3DBuffer *oldIdxs;
3384 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3385 oldIdxs = This->updateStateBlock->pIndexData;
3387 This->updateStateBlock->changed.indices = TRUE;
3388 This->updateStateBlock->pIndexData = pIndexData;
3389 This->updateStateBlock->IndexFmt = fmt;
3391 /* Handle recording of state blocks */
3392 if (This->isRecordingState) {
3393 TRACE("Recording... not performing anything\n");
3394 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3395 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3399 if(oldIdxs != pIndexData) {
3400 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3402 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3403 IWineD3DBuffer_AddRef(pIndexData);
3406 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3407 IWineD3DBuffer_Release(oldIdxs);
3414 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DBuffer** ppIndexData) {
3415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3417 *ppIndexData = This->stateBlock->pIndexData;
3419 /* up ref count on ppindexdata */
3421 IWineD3DBuffer_AddRef(*ppIndexData);
3422 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3424 TRACE("(%p) No index data set\n", This);
3426 TRACE("Returning %p\n", *ppIndexData);
3431 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3432 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3434 TRACE("(%p)->(%d)\n", This, BaseIndex);
3436 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3437 TRACE("Application is setting the old value over, nothing to do\n");
3441 This->updateStateBlock->baseVertexIndex = BaseIndex;
3443 if (This->isRecordingState) {
3444 TRACE("Recording... not performing anything\n");
3447 /* The base vertex index affects the stream sources */
3448 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3452 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3454 TRACE("(%p) : base_index %p\n", This, base_index);
3456 *base_index = This->stateBlock->baseVertexIndex;
3458 TRACE("Returning %u\n", *base_index);
3464 * Get / Set Viewports
3466 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3467 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3469 TRACE("(%p)\n", This);
3470 This->updateStateBlock->changed.viewport = TRUE;
3471 This->updateStateBlock->viewport = *pViewport;
3473 /* Handle recording of state blocks */
3474 if (This->isRecordingState) {
3475 TRACE("Recording... not performing anything\n");
3479 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3480 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3482 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3487 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3489 TRACE("(%p)\n", This);
3490 *pViewport = This->stateBlock->viewport;
3495 * Get / Set Render States
3496 * TODO: Verify against dx9 definitions
3498 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3500 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3501 DWORD oldValue = This->stateBlock->renderState[State];
3503 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3505 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3506 This->updateStateBlock->renderState[State] = Value;
3508 /* Handle recording of state blocks */
3509 if (This->isRecordingState) {
3510 TRACE("Recording... not performing anything\n");
3514 /* Compared here and not before the assignment to allow proper stateblock recording */
3515 if(Value == oldValue) {
3516 TRACE("Application is setting the old value over, nothing to do\n");
3518 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3524 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3525 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3526 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3527 *pValue = This->stateBlock->renderState[State];
3532 * Get / Set Sampler States
3533 * TODO: Verify against dx9 definitions
3536 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3540 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3541 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3543 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3544 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3547 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3548 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3549 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3552 * SetSampler is designed to allow for more than the standard up to 8 textures
3553 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3554 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3556 * http://developer.nvidia.com/object/General_FAQ.html#t6
3558 * There are two new settings for GForce
3560 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3561 * and the texture one:
3562 * GL_MAX_TEXTURE_COORDS_ARB.
3563 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3566 oldValue = This->stateBlock->samplerState[Sampler][Type];
3567 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3568 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3570 /* Handle recording of state blocks */
3571 if (This->isRecordingState) {
3572 TRACE("Recording... not performing anything\n");
3576 if(oldValue == Value) {
3577 TRACE("Application is setting the old value over, nothing to do\n");
3581 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3586 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3589 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3590 This, Sampler, debug_d3dsamplerstate(Type), Type);
3592 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3593 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3596 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3597 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3598 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3600 *Value = This->stateBlock->samplerState[Sampler][Type];
3601 TRACE("(%p) : Returning %#x\n", This, *Value);
3606 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3609 This->updateStateBlock->changed.scissorRect = TRUE;
3610 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3611 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3614 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3616 if(This->isRecordingState) {
3617 TRACE("Recording... not performing anything\n");
3621 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3626 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3629 *pRect = This->updateStateBlock->scissorRect;
3630 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3634 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3636 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3638 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3640 This->updateStateBlock->vertexDecl = pDecl;
3641 This->updateStateBlock->changed.vertexDecl = TRUE;
3643 if (This->isRecordingState) {
3644 TRACE("Recording... not performing anything\n");
3646 } else if(pDecl == oldDecl) {
3647 /* Checked after the assignment to allow proper stateblock recording */
3648 TRACE("Application is setting the old declaration over, nothing to do\n");
3652 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3656 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3659 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3661 *ppDecl = This->stateBlock->vertexDecl;
3662 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3666 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3668 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3670 This->updateStateBlock->vertexShader = pShader;
3671 This->updateStateBlock->changed.vertexShader = TRUE;
3673 if (This->isRecordingState) {
3674 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3675 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3676 TRACE("Recording... not performing anything\n");
3678 } else if(oldShader == pShader) {
3679 /* Checked here to allow proper stateblock recording */
3680 TRACE("App is setting the old shader over, nothing to do\n");
3684 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3685 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3686 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3688 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3693 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3696 if (NULL == ppShader) {
3697 return WINED3DERR_INVALIDCALL;
3699 *ppShader = This->stateBlock->vertexShader;
3700 if( NULL != *ppShader)
3701 IWineD3DVertexShader_AddRef(*ppShader);
3703 TRACE("(%p) : returning %p\n", This, *ppShader);
3707 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3708 IWineD3DDevice *iface,
3710 CONST BOOL *srcData,
3713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3714 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3716 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3717 iface, srcData, start, count);
3719 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3721 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3722 for (i = 0; i < cnt; i++)
3723 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3725 for (i = start; i < cnt + start; ++i) {
3726 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3729 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3734 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3735 IWineD3DDevice *iface,
3740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3741 int cnt = min(count, MAX_CONST_B - start);
3743 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3744 iface, dstData, start, count);
3746 if (dstData == NULL || cnt < 0)
3747 return WINED3DERR_INVALIDCALL;
3749 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3753 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3754 IWineD3DDevice *iface,
3759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3760 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3762 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3763 iface, srcData, start, count);
3765 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3767 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3768 for (i = 0; i < cnt; i++)
3769 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3770 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3772 for (i = start; i < cnt + start; ++i) {
3773 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3776 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3781 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3782 IWineD3DDevice *iface,
3787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3788 int cnt = min(count, MAX_CONST_I - start);
3790 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3791 iface, dstData, start, count);
3793 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3794 return WINED3DERR_INVALIDCALL;
3796 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3800 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3801 IWineD3DDevice *iface,
3803 CONST float *srcData,
3806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3809 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3810 iface, srcData, start, count);
3812 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3813 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3814 return WINED3DERR_INVALIDCALL;
3816 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3818 for (i = 0; i < count; i++)
3819 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3820 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3823 if (!This->isRecordingState)
3825 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3826 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3829 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3830 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3835 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3836 IWineD3DDevice *iface,
3841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3842 int cnt = min(count, This->d3d_vshader_constantF - start);
3844 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3845 iface, dstData, start, count);
3847 if (dstData == NULL || cnt < 0)
3848 return WINED3DERR_INVALIDCALL;
3850 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3854 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3856 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3858 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3862 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3863 int i = This->rev_tex_unit_map[unit];
3864 int j = This->texUnitMap[stage];
3866 This->texUnitMap[stage] = unit;
3867 if (i != -1 && i != stage) {
3868 This->texUnitMap[i] = -1;
3871 This->rev_tex_unit_map[unit] = stage;
3872 if (j != -1 && j != unit) {
3873 This->rev_tex_unit_map[j] = -1;
3877 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3880 This->fixed_function_usage_map = 0;
3881 for (i = 0; i < MAX_TEXTURES; ++i) {
3882 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3883 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3884 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3885 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3886 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3887 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3888 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3889 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3891 if (color_op == WINED3DTOP_DISABLE) {
3892 /* Not used, and disable higher stages */
3896 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3897 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3898 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3899 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3900 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3901 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3902 This->fixed_function_usage_map |= (1 << i);
3905 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3906 This->fixed_function_usage_map |= (1 << (i + 1));
3911 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3912 unsigned int i, tex;
3915 device_update_fixed_function_usage_map(This);
3916 ffu_map = This->fixed_function_usage_map;
3918 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3919 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3920 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3922 if (!(ffu_map & 1)) continue;
3924 if (This->texUnitMap[i] != i) {
3925 device_map_stage(This, i, i);
3926 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3927 markTextureStagesDirty(This, i);
3933 /* Now work out the mapping */
3935 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3937 if (!(ffu_map & 1)) continue;
3939 if (This->texUnitMap[i] != tex) {
3940 device_map_stage(This, i, tex);
3941 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3942 markTextureStagesDirty(This, i);
3949 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3950 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3951 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3954 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3955 if (sampler_type[i] && This->texUnitMap[i] != i)
3957 device_map_stage(This, i, i);
3958 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3959 if (i < MAX_TEXTURES) {
3960 markTextureStagesDirty(This, i);
3966 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3967 const DWORD *vshader_sampler_tokens, int unit)
3969 int current_mapping = This->rev_tex_unit_map[unit];
3971 if (current_mapping == -1) {
3972 /* Not currently used */
3976 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3977 /* Used by a fragment sampler */
3979 if (!pshader_sampler_tokens) {
3980 /* No pixel shader, check fixed function */
3981 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3984 /* Pixel shader, check the shader's sampler map */
3985 return !pshader_sampler_tokens[current_mapping];
3988 /* Used by a vertex sampler */
3989 return !vshader_sampler_tokens[current_mapping];
3992 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3993 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3994 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3995 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3996 int start = GL_LIMITS(combined_samplers) - 1;
4000 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
4002 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
4003 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
4004 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
4007 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
4008 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
4009 if (vshader_sampler_type[i])
4011 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
4013 /* Already mapped somewhere */
4017 while (start >= 0) {
4018 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
4020 device_map_stage(This, vsampler_idx, start);
4021 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
4033 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
4034 BOOL vs = use_vs(This->stateBlock);
4035 BOOL ps = use_ps(This->stateBlock);
4038 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
4039 * that would be really messy and require shader recompilation
4040 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
4041 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
4044 device_map_psamplers(This);
4046 device_map_fixed_function_samplers(This);
4050 device_map_vsamplers(This, ps);
4054 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4056 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4057 This->updateStateBlock->pixelShader = pShader;
4058 This->updateStateBlock->changed.pixelShader = TRUE;
4060 /* Handle recording of state blocks */
4061 if (This->isRecordingState) {
4062 TRACE("Recording... not performing anything\n");
4065 if (This->isRecordingState) {
4066 TRACE("Recording... not performing anything\n");
4067 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4068 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4072 if(pShader == oldShader) {
4073 TRACE("App is setting the old pixel shader over, nothing to do\n");
4077 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4078 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4080 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4081 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4086 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4089 if (NULL == ppShader) {
4090 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4091 return WINED3DERR_INVALIDCALL;
4094 *ppShader = This->stateBlock->pixelShader;
4095 if (NULL != *ppShader) {
4096 IWineD3DPixelShader_AddRef(*ppShader);
4098 TRACE("(%p) : returning %p\n", This, *ppShader);
4102 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4103 IWineD3DDevice *iface,
4105 CONST BOOL *srcData,
4108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4109 unsigned int i, cnt = min(count, MAX_CONST_B - start);
4111 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4112 iface, srcData, start, count);
4114 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
4116 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4117 for (i = 0; i < cnt; i++)
4118 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4120 for (i = start; i < cnt + start; ++i) {
4121 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
4124 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4129 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4130 IWineD3DDevice *iface,
4135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4136 int cnt = min(count, MAX_CONST_B - start);
4138 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4139 iface, dstData, start, count);
4141 if (dstData == NULL || cnt < 0)
4142 return WINED3DERR_INVALIDCALL;
4144 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4148 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4149 IWineD3DDevice *iface,
4154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4155 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4157 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4158 iface, srcData, start, count);
4160 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4162 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4163 for (i = 0; i < cnt; i++)
4164 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4165 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4167 for (i = start; i < cnt + start; ++i) {
4168 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4171 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4176 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4177 IWineD3DDevice *iface,
4182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4183 int cnt = min(count, MAX_CONST_I - start);
4185 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4186 iface, dstData, start, count);
4188 if (dstData == NULL || cnt < 0)
4189 return WINED3DERR_INVALIDCALL;
4191 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4195 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4196 IWineD3DDevice *iface,
4198 CONST float *srcData,
4201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4204 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4205 iface, srcData, start, count);
4207 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4208 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
4209 return WINED3DERR_INVALIDCALL;
4211 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4213 for (i = 0; i < count; i++)
4214 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4215 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4218 if (!This->isRecordingState)
4220 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4221 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4224 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4225 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4230 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4231 IWineD3DDevice *iface,
4236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4237 int cnt = min(count, This->d3d_pshader_constantF - start);
4239 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4240 iface, dstData, start, count);
4242 if (dstData == NULL || cnt < 0)
4243 return WINED3DERR_INVALIDCALL;
4245 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4249 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4250 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4251 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
4254 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4257 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4261 if (stream_info->elements[WINED3D_FFP_NORMAL].data)
4263 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4266 if (!stream_info->elements[WINED3D_FFP_POSITION].data)
4268 ERR("Source has no position mask\n");
4269 return WINED3DERR_INVALIDCALL;
4272 /* We might access VBOs from this code, so hold the lock */
4275 if (dest->resource.allocatedMemory == NULL) {
4276 buffer_get_sysmem(dest);
4279 /* Get a pointer into the destination vbo(create one if none exists) and
4280 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4282 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4284 dest->flags |= WINED3D_BUFFER_CREATEBO;
4285 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4288 if (dest->buffer_object)
4290 unsigned char extrabytes = 0;
4291 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4292 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4293 * this may write 4 extra bytes beyond the area that should be written
4295 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4296 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4297 if(!dest_conv_addr) {
4298 ERR("Out of memory\n");
4299 /* Continue without storing converted vertices */
4301 dest_conv = dest_conv_addr;
4305 * a) WINED3DRS_CLIPPING is enabled
4306 * b) WINED3DVOP_CLIP is passed
4308 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4309 static BOOL warned = FALSE;
4311 * The clipping code is not quite correct. Some things need
4312 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4313 * so disable clipping for now.
4314 * (The graphics in Half-Life are broken, and my processvertices
4315 * test crashes with IDirect3DDevice3)
4321 FIXME("Clipping is broken and disabled for now\n");
4323 } else doClip = FALSE;
4324 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4326 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4329 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4330 WINED3DTS_PROJECTION,
4332 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4333 WINED3DTS_WORLDMATRIX(0),
4336 TRACE("View mat:\n");
4337 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);
4338 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);
4339 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);
4340 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);
4342 TRACE("Proj mat:\n");
4343 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);
4344 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);
4345 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);
4346 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);
4348 TRACE("World mat:\n");
4349 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);
4350 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);
4351 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);
4352 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);
4354 /* Get the viewport */
4355 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4356 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4357 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4359 multiply_matrix(&mat,&view_mat,&world_mat);
4360 multiply_matrix(&mat,&proj_mat,&mat);
4362 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4364 for (i = 0; i < dwCount; i+= 1) {
4365 unsigned int tex_index;
4367 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4368 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4369 /* The position first */
4370 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4371 const float *p = (const float *)(element->data + i * element->stride);
4373 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4375 /* Multiplication with world, view and projection matrix */
4376 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);
4377 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);
4378 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);
4379 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);
4381 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4383 /* WARNING: The following things are taken from d3d7 and were not yet checked
4384 * against d3d8 or d3d9!
4387 /* Clipping conditions: From msdn
4389 * A vertex is clipped if it does not match the following requirements
4393 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4395 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4396 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4401 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4402 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4405 /* "Normal" viewport transformation (not clipped)
4406 * 1) The values are divided by rhw
4407 * 2) The y axis is negative, so multiply it with -1
4408 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4409 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4410 * 4) Multiply x with Width/2 and add Width/2
4411 * 5) The same for the height
4412 * 6) Add the viewpoint X and Y to the 2D coordinates and
4413 * The minimum Z value to z
4414 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4416 * Well, basically it's simply a linear transformation into viewport
4428 z *= vp.MaxZ - vp.MinZ;
4430 x += vp.Width / 2 + vp.X;
4431 y += vp.Height / 2 + vp.Y;
4436 /* That vertex got clipped
4437 * Contrary to OpenGL it is not dropped completely, it just
4438 * undergoes a different calculation.
4440 TRACE("Vertex got clipped\n");
4447 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4448 * outside of the main vertex buffer memory. That needs some more
4453 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4456 ( (float *) dest_ptr)[0] = x;
4457 ( (float *) dest_ptr)[1] = y;
4458 ( (float *) dest_ptr)[2] = z;
4459 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4461 dest_ptr += 3 * sizeof(float);
4463 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4464 dest_ptr += sizeof(float);
4469 ( (float *) dest_conv)[0] = x * w;
4470 ( (float *) dest_conv)[1] = y * w;
4471 ( (float *) dest_conv)[2] = z * w;
4472 ( (float *) dest_conv)[3] = w;
4474 dest_conv += 3 * sizeof(float);
4476 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4477 dest_conv += sizeof(float);
4481 if (DestFVF & WINED3DFVF_PSIZE) {
4482 dest_ptr += sizeof(DWORD);
4483 if(dest_conv) dest_conv += sizeof(DWORD);
4485 if (DestFVF & WINED3DFVF_NORMAL) {
4486 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4487 const float *normal = (const float *)(element->data + i * element->stride);
4488 /* AFAIK this should go into the lighting information */
4489 FIXME("Didn't expect the destination to have a normal\n");
4490 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4492 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4496 if (DestFVF & WINED3DFVF_DIFFUSE) {
4497 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4498 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4500 static BOOL warned = FALSE;
4503 ERR("No diffuse color in source, but destination has one\n");
4507 *( (DWORD *) dest_ptr) = 0xffffffff;
4508 dest_ptr += sizeof(DWORD);
4511 *( (DWORD *) dest_conv) = 0xffffffff;
4512 dest_conv += sizeof(DWORD);
4516 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4518 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4519 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4520 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4521 dest_conv += sizeof(DWORD);
4526 if (DestFVF & WINED3DFVF_SPECULAR) {
4527 /* What's the color value in the feedback buffer? */
4528 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4529 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4531 static BOOL warned = FALSE;
4534 ERR("No specular color in source, but destination has one\n");
4538 *( (DWORD *) dest_ptr) = 0xFF000000;
4539 dest_ptr += sizeof(DWORD);
4542 *( (DWORD *) dest_conv) = 0xFF000000;
4543 dest_conv += sizeof(DWORD);
4547 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4549 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4550 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4551 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4552 dest_conv += sizeof(DWORD);
4557 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4558 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4559 const float *tex_coord = (const float *)(element->data + i * element->stride);
4561 ERR("No source texture, but destination requests one\n");
4562 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4563 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4566 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4568 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4575 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4576 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4577 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4578 dwCount * get_flexible_vertex_size(DestFVF),
4580 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4581 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4588 #undef copy_and_next
4590 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4591 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4595 struct wined3d_stream_info stream_info;
4596 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4597 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4600 ERR("Output vertex declaration not implemented yet\n");
4603 /* Need any context to write to the vbo. */
4604 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4606 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4607 * control the streamIsUP flag, thus restore it afterwards.
4609 This->stateBlock->streamIsUP = FALSE;
4610 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4611 This->stateBlock->streamIsUP = streamWasUP;
4613 if(vbo || SrcStartIndex) {
4615 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4616 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4618 * Also get the start index in, but only loop over all elements if there's something to add at all.
4620 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4622 struct wined3d_stream_info_element *e = &stream_info.elements[i];
4623 if (e->buffer_object)
4625 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4626 e->buffer_object = 0;
4627 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4629 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4630 vb->buffer_object = 0;
4633 if (e->data) e->data += e->stride * SrcStartIndex;
4637 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4638 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4642 * Get / Set Texture Stage States
4643 * TODO: Verify against dx9 definitions
4645 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4647 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4649 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4651 if (Stage >= MAX_TEXTURES) {
4652 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4656 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4657 This->updateStateBlock->textureState[Stage][Type] = Value;
4659 if (This->isRecordingState) {
4660 TRACE("Recording... not performing anything\n");
4664 /* Checked after the assignments to allow proper stateblock recording */
4665 if(oldValue == Value) {
4666 TRACE("App is setting the old value over, nothing to do\n");
4670 if(Stage > This->stateBlock->lowest_disabled_stage &&
4671 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4672 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4673 * Changes in other states are important on disabled stages too
4678 if(Type == WINED3DTSS_COLOROP) {
4681 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4682 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4683 * they have to be disabled
4685 * The current stage is dirtified below.
4687 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4688 TRACE("Additionally dirtifying stage %u\n", i);
4689 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4691 This->stateBlock->lowest_disabled_stage = Stage;
4692 TRACE("New lowest disabled: %u\n", Stage);
4693 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4694 /* Previously disabled stage enabled. Stages above it may need enabling
4695 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4696 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4698 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4701 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4702 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4705 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4706 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4708 This->stateBlock->lowest_disabled_stage = i;
4709 TRACE("New lowest disabled: %u\n", i);
4713 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4718 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4719 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4720 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4721 *pValue = This->updateStateBlock->textureState[Stage][Type];
4728 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4730 IWineD3DBaseTexture *oldTexture;
4732 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4734 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4735 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4738 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4739 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4740 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4743 oldTexture = This->updateStateBlock->textures[Stage];
4745 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4746 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4748 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4749 return WINED3DERR_INVALIDCALL;
4752 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4753 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4755 This->updateStateBlock->changed.textures |= 1 << Stage;
4756 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4757 This->updateStateBlock->textures[Stage] = pTexture;
4759 /* Handle recording of state blocks */
4760 if (This->isRecordingState) {
4761 TRACE("Recording... not performing anything\n");
4765 if(oldTexture == pTexture) {
4766 TRACE("App is setting the same texture again, nothing to do\n");
4770 /** NOTE: MSDN says that setTexture increases the reference count,
4771 * and that the application must set the texture back to null (or have a leaky application),
4772 * This means we should pass the refcount up to the parent
4773 *******************************/
4774 if (NULL != This->updateStateBlock->textures[Stage]) {
4775 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4776 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4777 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4779 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4781 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4783 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4786 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4787 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4788 * so the COLOROP and ALPHAOP have to be dirtified.
4790 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4791 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4793 if(bindCount == 1) {
4794 new->baseTexture.sampler = Stage;
4796 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4800 if (NULL != oldTexture) {
4801 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4802 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4804 IWineD3DBaseTexture_Release(oldTexture);
4805 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4806 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4807 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4810 if(bindCount && old->baseTexture.sampler == Stage) {
4812 /* Have to do a search for the other sampler(s) where the texture is bound to
4813 * Shouldn't happen as long as apps bind a texture only to one stage
4815 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4816 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4817 if(This->updateStateBlock->textures[i] == oldTexture) {
4818 old->baseTexture.sampler = i;
4825 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4830 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4833 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4835 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4836 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4839 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4840 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4841 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4844 *ppTexture=This->stateBlock->textures[Stage];
4846 IWineD3DBaseTexture_AddRef(*ppTexture);
4848 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4856 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4857 IWineD3DSurface **ppBackBuffer) {
4858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4859 IWineD3DSwapChain *swapChain;
4862 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4864 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4865 if (hr == WINED3D_OK) {
4866 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4867 IWineD3DSwapChain_Release(swapChain);
4869 *ppBackBuffer = NULL;
4874 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4876 WARN("(%p) : stub, calling idirect3d for now\n", This);
4877 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4880 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4882 IWineD3DSwapChain *swapChain;
4885 if(iSwapChain > 0) {
4886 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4887 if (hr == WINED3D_OK) {
4888 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4889 IWineD3DSwapChain_Release(swapChain);
4891 FIXME("(%p) Error getting display mode\n", This);
4894 /* Don't read the real display mode,
4895 but return the stored mode instead. X11 can't change the color
4896 depth, and some apps are pretty angry if they SetDisplayMode from
4897 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4899 Also don't relay to the swapchain because with ddraw it's possible
4900 that there isn't a swapchain at all */
4901 pMode->Width = This->ddraw_width;
4902 pMode->Height = This->ddraw_height;
4903 pMode->Format = This->ddraw_format;
4904 pMode->RefreshRate = 0;
4912 * Stateblock related functions
4915 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4917 IWineD3DStateBlock *stateblock;
4920 TRACE("(%p)\n", This);
4922 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4924 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4925 if (FAILED(hr)) return hr;
4927 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4928 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4929 This->isRecordingState = TRUE;
4931 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4936 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4939 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4941 if (!This->isRecordingState) {
4942 WARN("(%p) not recording! returning error\n", This);
4943 *ppStateBlock = NULL;
4944 return WINED3DERR_INVALIDCALL;
4947 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
4949 DWORD map = object->changed.renderState[i];
4950 for (j = 0; map; map >>= 1, ++j)
4952 if (!(map & 1)) continue;
4954 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
4958 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
4960 DWORD map = object->changed.transform[i];
4961 for (j = 0; map; map >>= 1, ++j)
4963 if (!(map & 1)) continue;
4965 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
4968 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4969 if(object->changed.vertexShaderConstantsF[i]) {
4970 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4971 object->num_contained_vs_consts_f++;
4974 for(i = 0; i < MAX_CONST_I; i++) {
4975 if (object->changed.vertexShaderConstantsI & (1 << i))
4977 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4978 object->num_contained_vs_consts_i++;
4981 for(i = 0; i < MAX_CONST_B; i++) {
4982 if (object->changed.vertexShaderConstantsB & (1 << i))
4984 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4985 object->num_contained_vs_consts_b++;
4988 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4990 if (object->changed.pixelShaderConstantsF[i])
4992 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4993 ++object->num_contained_ps_consts_f;
4996 for(i = 0; i < MAX_CONST_I; i++) {
4997 if (object->changed.pixelShaderConstantsI & (1 << i))
4999 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
5000 object->num_contained_ps_consts_i++;
5003 for(i = 0; i < MAX_CONST_B; i++) {
5004 if (object->changed.pixelShaderConstantsB & (1 << i))
5006 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
5007 object->num_contained_ps_consts_b++;
5010 for(i = 0; i < MAX_TEXTURES; i++) {
5011 DWORD map = object->changed.textureState[i];
5013 for(j = 0; map; map >>= 1, ++j)
5015 if (!(map & 1)) continue;
5017 object->contained_tss_states[object->num_contained_tss_states].stage = i;
5018 object->contained_tss_states[object->num_contained_tss_states].state = j;
5019 ++object->num_contained_tss_states;
5022 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
5023 DWORD map = object->changed.samplerState[i];
5025 for (j = 0; map; map >>= 1, ++j)
5027 if (!(map & 1)) continue;
5029 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
5030 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
5031 ++object->num_contained_sampler_states;
5035 *ppStateBlock = (IWineD3DStateBlock*) object;
5036 This->isRecordingState = FALSE;
5037 This->updateStateBlock = This->stateBlock;
5038 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5039 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5040 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5045 * Scene related functions
5047 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5048 /* At the moment we have no need for any functionality at the beginning
5050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5051 TRACE("(%p)\n", This);
5054 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
5055 return WINED3DERR_INVALIDCALL;
5057 This->inScene = TRUE;
5061 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5063 TRACE("(%p)\n", This);
5065 if(!This->inScene) {
5066 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
5067 return WINED3DERR_INVALIDCALL;
5070 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5071 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5073 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
5077 This->inScene = FALSE;
5081 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5082 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5083 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5085 IWineD3DSwapChain *swapChain = NULL;
5087 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5089 TRACE("(%p) Presenting the frame\n", This);
5091 for(i = 0 ; i < swapchains ; i ++) {
5093 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5094 TRACE("presentinng chain %d, %p\n", i, swapChain);
5095 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5096 IWineD3DSwapChain_Release(swapChain);
5102 /* Not called from the VTable (internal subroutine) */
5103 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5104 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5105 float Z, DWORD Stencil) {
5106 GLbitfield glMask = 0;
5108 WINED3DRECT curRect;
5110 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5111 UINT drawable_width, drawable_height;
5112 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5113 IWineD3DSwapChainImpl *swapchain = NULL;
5115 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5116 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5117 * for the cleared parts, and the untouched parts.
5119 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5120 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5121 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5122 * checking all this if the dest surface is in the drawable anyway.
5124 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5126 if(vp->X != 0 || vp->Y != 0 ||
5127 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5128 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5131 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5132 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5133 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5134 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5135 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5138 if(Count > 0 && pRects && (
5139 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5140 pRects[0].x2 < target->currentDesc.Width ||
5141 pRects[0].y2 < target->currentDesc.Height)) {
5142 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5149 target->get_drawable_size(target, &drawable_width, &drawable_height);
5151 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5154 /* Only set the values up once, as they are not changing */
5155 if (Flags & WINED3DCLEAR_STENCIL) {
5156 glClearStencil(Stencil);
5157 checkGLcall("glClearStencil");
5158 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5159 glStencilMask(0xFFFFFFFF);
5162 if (Flags & WINED3DCLEAR_ZBUFFER) {
5163 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5164 glDepthMask(GL_TRUE);
5166 checkGLcall("glClearDepth");
5167 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5168 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5170 if (vp->X != 0 || vp->Y != 0 ||
5171 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5172 surface_load_ds_location(This->stencilBufferTarget, location);
5174 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5175 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5176 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5177 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5178 surface_load_ds_location(This->stencilBufferTarget, location);
5180 else if (Count > 0 && pRects && (
5181 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5182 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5183 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5184 surface_load_ds_location(This->stencilBufferTarget, location);
5188 if (Flags & WINED3DCLEAR_TARGET) {
5189 TRACE("Clearing screen with glClear to color %x\n", Color);
5190 glClearColor(D3DCOLOR_R(Color),
5194 checkGLcall("glClearColor");
5196 /* Clear ALL colors! */
5197 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5198 glMask = glMask | GL_COLOR_BUFFER_BIT;
5201 vp_rect.left = vp->X;
5202 vp_rect.top = vp->Y;
5203 vp_rect.right = vp->X + vp->Width;
5204 vp_rect.bottom = vp->Y + vp->Height;
5205 if (!(Count > 0 && pRects)) {
5206 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5207 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5209 if(This->render_offscreen) {
5210 glScissor(vp_rect.left, vp_rect.top,
5211 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5213 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5214 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5216 checkGLcall("glScissor");
5218 checkGLcall("glClear");
5220 /* Now process each rect in turn */
5221 for (i = 0; i < Count; i++) {
5222 /* Note gl uses lower left, width/height */
5223 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5224 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5225 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5227 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5228 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5229 curRect.x1, (target->currentDesc.Height - curRect.y2),
5230 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5232 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5233 * The rectangle is not cleared, no error is returned, but further rectanlges are
5234 * still cleared if they are valid
5236 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5237 TRACE("Rectangle with negative dimensions, ignoring\n");
5241 if(This->render_offscreen) {
5242 glScissor(curRect.x1, curRect.y1,
5243 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5245 glScissor(curRect.x1, drawable_height - curRect.y2,
5246 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5248 checkGLcall("glScissor");
5251 checkGLcall("glClear");
5255 /* Restore the old values (why..?) */
5256 if (Flags & WINED3DCLEAR_STENCIL) {
5257 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5259 if (Flags & WINED3DCLEAR_TARGET) {
5260 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5261 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5262 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5263 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5264 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5266 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5267 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5269 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5271 if (Flags & WINED3DCLEAR_ZBUFFER) {
5272 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5273 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5274 surface_modify_ds_location(This->stencilBufferTarget, location);
5279 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5280 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5283 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5289 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5290 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5292 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5294 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5295 Count, pRects, Flags, Color, Z, Stencil);
5297 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5298 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5299 /* TODO: What about depth stencil buffers without stencil bits? */
5300 return WINED3DERR_INVALIDCALL;
5303 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5310 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5311 WINED3DPRIMITIVETYPE primitive_type)
5313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5315 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5317 This->updateStateBlock->changed.primitive_type = TRUE;
5318 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5321 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5322 WINED3DPRIMITIVETYPE *primitive_type)
5324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5326 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5328 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5330 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5333 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5337 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5339 if(!This->stateBlock->vertexDecl) {
5340 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5341 return WINED3DERR_INVALIDCALL;
5344 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5345 if(This->stateBlock->streamIsUP) {
5346 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5347 This->stateBlock->streamIsUP = FALSE;
5350 if(This->stateBlock->loadBaseVertexIndex != 0) {
5351 This->stateBlock->loadBaseVertexIndex = 0;
5352 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5354 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5355 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5356 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5360 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5361 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5365 IWineD3DBuffer *pIB;
5368 pIB = This->stateBlock->pIndexData;
5370 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5371 * without an index buffer set. (The first time at least...)
5372 * D3D8 simply dies, but I doubt it can do much harm to return
5373 * D3DERR_INVALIDCALL there as well. */
5374 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5375 return WINED3DERR_INVALIDCALL;
5378 if(!This->stateBlock->vertexDecl) {
5379 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5380 return WINED3DERR_INVALIDCALL;
5383 if(This->stateBlock->streamIsUP) {
5384 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5385 This->stateBlock->streamIsUP = FALSE;
5387 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
5389 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5390 This, minIndex, NumVertices, startIndex, index_count);
5392 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
5398 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5399 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5400 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5403 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5404 vbo ? NULL : ((struct wined3d_buffer *) pIB)->resource.allocatedMemory, minIndex);
5409 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5410 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5415 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5416 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5418 if(!This->stateBlock->vertexDecl) {
5419 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5420 return WINED3DERR_INVALIDCALL;
5423 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5424 vb = This->stateBlock->streamSource[0];
5425 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5426 if (vb) IWineD3DBuffer_Release(vb);
5427 This->stateBlock->streamOffset[0] = 0;
5428 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5429 This->stateBlock->streamIsUP = TRUE;
5430 This->stateBlock->loadBaseVertexIndex = 0;
5432 /* TODO: Only mark dirty if drawing from a different UP address */
5433 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5435 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5436 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5438 /* MSDN specifies stream zero settings must be set to NULL */
5439 This->stateBlock->streamStride[0] = 0;
5440 This->stateBlock->streamSource[0] = NULL;
5442 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5443 * the new stream sources or use UP drawing again
5448 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5449 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5450 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5457 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5458 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5459 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5461 if(!This->stateBlock->vertexDecl) {
5462 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5463 return WINED3DERR_INVALIDCALL;
5466 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5472 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5473 vb = This->stateBlock->streamSource[0];
5474 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5475 if (vb) IWineD3DBuffer_Release(vb);
5476 This->stateBlock->streamIsUP = TRUE;
5477 This->stateBlock->streamOffset[0] = 0;
5478 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5480 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5481 This->stateBlock->baseVertexIndex = 0;
5482 This->stateBlock->loadBaseVertexIndex = 0;
5483 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5484 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5485 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5487 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5488 idxStride, pIndexData, MinVertexIndex);
5490 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5491 This->stateBlock->streamSource[0] = NULL;
5492 This->stateBlock->streamStride[0] = 0;
5493 ib = This->stateBlock->pIndexData;
5495 IWineD3DBuffer_Release(ib);
5496 This->stateBlock->pIndexData = NULL;
5498 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5499 * SetStreamSource to specify a vertex buffer
5505 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5506 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5510 /* Mark the state dirty until we have nicer tracking
5511 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5514 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5515 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5516 This->stateBlock->baseVertexIndex = 0;
5517 This->up_strided = DrawPrimStrideData;
5518 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5519 This->up_strided = NULL;
5523 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5524 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5525 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5528 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5530 /* Mark the state dirty until we have nicer tracking
5531 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5534 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5535 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5536 This->stateBlock->streamIsUP = TRUE;
5537 This->stateBlock->baseVertexIndex = 0;
5538 This->up_strided = DrawPrimStrideData;
5539 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5540 This->up_strided = NULL;
5544 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5545 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5546 * not callable by the app directly no parameter validation checks are needed here.
5548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5549 WINED3DLOCKED_BOX src;
5550 WINED3DLOCKED_BOX dst;
5552 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5554 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5555 * dirtification to improve loading performance.
5557 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5558 if(FAILED(hr)) return hr;
5559 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5561 IWineD3DVolume_UnlockBox(pSourceVolume);
5565 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5567 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5569 IWineD3DVolume_UnlockBox(pSourceVolume);
5571 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5576 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5577 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5579 HRESULT hr = WINED3D_OK;
5580 WINED3DRESOURCETYPE sourceType;
5581 WINED3DRESOURCETYPE destinationType;
5584 /* TODO: think about moving the code into IWineD3DBaseTexture */
5586 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5588 /* verify that the source and destination textures aren't NULL */
5589 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5590 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5591 This, pSourceTexture, pDestinationTexture);
5592 hr = WINED3DERR_INVALIDCALL;
5595 if (pSourceTexture == pDestinationTexture) {
5596 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5597 This, pSourceTexture, pDestinationTexture);
5598 hr = WINED3DERR_INVALIDCALL;
5600 /* Verify that the source and destination textures are the same type */
5601 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5602 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5604 if (sourceType != destinationType) {
5605 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5607 hr = WINED3DERR_INVALIDCALL;
5610 /* check that both textures have the identical numbers of levels */
5611 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5612 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5613 hr = WINED3DERR_INVALIDCALL;
5616 if (WINED3D_OK == hr) {
5617 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5619 /* Make sure that the destination texture is loaded */
5620 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5622 /* Update every surface level of the texture */
5623 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5625 switch (sourceType) {
5626 case WINED3DRTYPE_TEXTURE:
5628 IWineD3DSurface *srcSurface;
5629 IWineD3DSurface *destSurface;
5631 for (i = 0 ; i < levels ; ++i) {
5632 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5633 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5634 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5635 IWineD3DSurface_Release(srcSurface);
5636 IWineD3DSurface_Release(destSurface);
5637 if (WINED3D_OK != hr) {
5638 WARN("(%p) : Call to update surface failed\n", This);
5644 case WINED3DRTYPE_CUBETEXTURE:
5646 IWineD3DSurface *srcSurface;
5647 IWineD3DSurface *destSurface;
5648 WINED3DCUBEMAP_FACES faceType;
5650 for (i = 0 ; i < levels ; ++i) {
5651 /* Update each cube face */
5652 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5653 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5654 if (WINED3D_OK != hr) {
5655 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5657 TRACE("Got srcSurface %p\n", srcSurface);
5659 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5660 if (WINED3D_OK != hr) {
5661 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5663 TRACE("Got desrSurface %p\n", destSurface);
5665 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5666 IWineD3DSurface_Release(srcSurface);
5667 IWineD3DSurface_Release(destSurface);
5668 if (WINED3D_OK != hr) {
5669 WARN("(%p) : Call to update surface failed\n", This);
5677 case WINED3DRTYPE_VOLUMETEXTURE:
5679 IWineD3DVolume *srcVolume = NULL;
5680 IWineD3DVolume *destVolume = NULL;
5682 for (i = 0 ; i < levels ; ++i) {
5683 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5684 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5685 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5686 IWineD3DVolume_Release(srcVolume);
5687 IWineD3DVolume_Release(destVolume);
5688 if (WINED3D_OK != hr) {
5689 WARN("(%p) : Call to update volume failed\n", This);
5697 FIXME("(%p) : Unsupported source and destination type\n", This);
5698 hr = WINED3DERR_INVALIDCALL;
5705 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5706 IWineD3DSwapChain *swapChain;
5708 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5709 if(hr == WINED3D_OK) {
5710 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5711 IWineD3DSwapChain_Release(swapChain);
5716 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5718 IWineD3DBaseTextureImpl *texture;
5721 TRACE("(%p) : %p\n", This, pNumPasses);
5723 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5724 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5725 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5726 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5728 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5729 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5730 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5733 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5734 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5736 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5737 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5740 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5741 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5744 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5745 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5746 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5751 /* return a sensible default */
5754 TRACE("returning D3D_OK\n");
5758 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5762 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5763 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5764 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
5765 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
5767 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5772 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5776 PALETTEENTRY **palettes;
5778 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5780 if (PaletteNumber >= MAX_PALETTES) {
5781 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5782 return WINED3DERR_INVALIDCALL;
5785 if (PaletteNumber >= This->NumberOfPalettes) {
5786 NewSize = This->NumberOfPalettes;
5789 } while(PaletteNumber >= NewSize);
5790 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5792 ERR("Out of memory!\n");
5793 return E_OUTOFMEMORY;
5795 This->palettes = palettes;
5796 This->NumberOfPalettes = NewSize;
5799 if (!This->palettes[PaletteNumber]) {
5800 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5801 if (!This->palettes[PaletteNumber]) {
5802 ERR("Out of memory!\n");
5803 return E_OUTOFMEMORY;
5807 for (j = 0; j < 256; ++j) {
5808 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5809 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5810 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5811 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5813 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5814 TRACE("(%p) : returning\n", This);
5818 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5821 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5822 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5823 /* What happens in such situation isn't documented; Native seems to silently abort
5824 on such conditions. Return Invalid Call. */
5825 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5826 return WINED3DERR_INVALIDCALL;
5828 for (j = 0; j < 256; ++j) {
5829 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5830 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5831 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5832 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5834 TRACE("(%p) : returning\n", This);
5838 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5840 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5841 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5842 (tested with reference rasterizer). Return Invalid Call. */
5843 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5844 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5845 return WINED3DERR_INVALIDCALL;
5847 /*TODO: stateblocks */
5848 if (This->currentPalette != PaletteNumber) {
5849 This->currentPalette = PaletteNumber;
5850 dirtify_p8_texture_samplers(This);
5852 TRACE("(%p) : returning\n", This);
5856 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5858 if (PaletteNumber == NULL) {
5859 WARN("(%p) : returning Invalid Call\n", This);
5860 return WINED3DERR_INVALIDCALL;
5862 /*TODO: stateblocks */
5863 *PaletteNumber = This->currentPalette;
5864 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5868 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5873 FIXME("(%p) : stub\n", This);
5877 This->softwareVertexProcessing = bSoftware;
5882 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5887 FIXME("(%p) : stub\n", This);
5890 return This->softwareVertexProcessing;
5894 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5896 IWineD3DSwapChain *swapChain;
5899 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5901 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5902 if(hr == WINED3D_OK){
5903 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5904 IWineD3DSwapChain_Release(swapChain);
5906 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5912 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5915 if(nSegments != 0.0f) {
5918 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5925 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5930 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5936 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5938 /** TODO: remove casts to IWineD3DSurfaceImpl
5939 * NOTE: move code to surface to accomplish this
5940 ****************************************/
5941 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5942 int srcWidth, srcHeight;
5943 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5944 WINED3DFORMAT destFormat, srcFormat;
5946 int srcLeft, destLeft, destTop;
5947 WINED3DPOOL srcPool, destPool;
5949 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5950 glDescriptor *glDescription = NULL;
5951 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5955 CONVERT_TYPES convert = NO_CONVERSION;
5957 WINED3DSURFACE_DESC winedesc;
5959 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5960 memset(&winedesc, 0, sizeof(winedesc));
5961 winedesc.Width = &srcSurfaceWidth;
5962 winedesc.Height = &srcSurfaceHeight;
5963 winedesc.Pool = &srcPool;
5964 winedesc.Format = &srcFormat;
5966 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5968 winedesc.Width = &destSurfaceWidth;
5969 winedesc.Height = &destSurfaceHeight;
5970 winedesc.Pool = &destPool;
5971 winedesc.Format = &destFormat;
5972 winedesc.Size = &destSize;
5974 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5976 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5977 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5978 return WINED3DERR_INVALIDCALL;
5981 /* This call loads the opengl surface directly, instead of copying the surface to the
5982 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5983 * copy in sysmem and use regular surface loading.
5985 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5986 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5987 if(convert != NO_CONVERSION) {
5988 return IWineD3DSurface_BltFast(pDestinationSurface,
5989 pDestPoint ? pDestPoint->x : 0,
5990 pDestPoint ? pDestPoint->y : 0,
5991 pSourceSurface, pSourceRect, 0);
5994 if (destFormat == WINED3DFMT_UNKNOWN) {
5995 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5996 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5998 /* Get the update surface description */
5999 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6002 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6005 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6006 checkGLcall("glActiveTextureARB");
6009 /* Make sure the surface is loaded and up to date */
6010 surface_internal_preload(pDestinationSurface, SRGB_RGB);
6011 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
6013 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6015 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
6016 dst_format_desc = ((IWineD3DSurfaceImpl *)pDestinationSurface)->resource.format_desc;
6018 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6019 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6020 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
6021 srcLeft = pSourceRect ? pSourceRect->left : 0;
6022 destLeft = pDestPoint ? pDestPoint->x : 0;
6023 destTop = pDestPoint ? pDestPoint->y : 0;
6026 /* This function doesn't support compressed textures
6027 the pitch is just bytesPerPixel * width */
6028 if(srcWidth != srcSurfaceWidth || srcLeft ){
6029 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
6030 offset += srcLeft * src_format_desc->byte_count;
6031 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6033 /* TODO DXT formats */
6035 if(pSourceRect != NULL && pSourceRect->top != 0){
6036 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
6038 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
6039 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
6040 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
6043 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6045 /* need to lock the surface to get the data */
6046 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6051 /* TODO: Cube and volume support */
6053 /* not a whole row so we have to do it a line at a time */
6056 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
6057 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6059 for (j = destTop; j < (srcHeight + destTop); ++j)
6061 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, j,
6062 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
6066 } else { /* Full width, so just write out the whole texture */
6067 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6069 if (WINED3DFMT_DXT1 == destFormat ||
6070 WINED3DFMT_DXT2 == destFormat ||
6071 WINED3DFMT_DXT3 == destFormat ||
6072 WINED3DFMT_DXT4 == destFormat ||
6073 WINED3DFMT_DXT5 == destFormat) {
6074 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6075 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6076 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6077 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6078 } if (destFormat != srcFormat) {
6079 FIXME("Updating mixed format compressed texture is not curretly support\n");
6081 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6082 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
6085 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6090 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6091 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
6094 checkGLcall("glTexSubImage2D");
6098 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6099 sampler = This->rev_tex_unit_map[0];
6100 if (sampler != -1) {
6101 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6107 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6109 struct WineD3DRectPatch *patch;
6110 GLenum old_primitive_type;
6114 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6116 if(!(Handle || pRectPatchInfo)) {
6117 /* TODO: Write a test for the return value, thus the FIXME */
6118 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6119 return WINED3DERR_INVALIDCALL;
6123 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) {
6134 TRACE("Patch does not exist. Creating a new one\n");
6135 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6136 patch->Handle = Handle;
6137 list_add_head(&This->patches[i], &patch->entry);
6139 TRACE("Found existing patch %p\n", patch);
6142 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6143 * attributes we have to tesselate, read back, and draw. This needs a patch
6144 * management structure instance. Create one.
6146 * A possible improvement is to check if a vertex shader is used, and if not directly
6149 FIXME("Drawing an uncached patch. This is slow\n");
6150 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6153 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6154 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6155 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6157 TRACE("Tesselation density or patch info changed, retesselating\n");
6159 if(pRectPatchInfo) {
6160 patch->RectPatchInfo = *pRectPatchInfo;
6162 patch->numSegs[0] = pNumSegs[0];
6163 patch->numSegs[1] = pNumSegs[1];
6164 patch->numSegs[2] = pNumSegs[2];
6165 patch->numSegs[3] = pNumSegs[3];
6167 hr = tesselate_rectpatch(This, patch);
6169 WARN("Patch tesselation failed\n");
6171 /* Do not release the handle to store the params of the patch */
6173 HeapFree(GetProcessHeap(), 0, patch);
6179 This->currentPatch = patch;
6180 old_primitive_type = This->stateBlock->gl_primitive_type;
6181 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
6182 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
6183 This->stateBlock->gl_primitive_type = old_primitive_type;
6184 This->currentPatch = NULL;
6186 /* Destroy uncached patches */
6188 HeapFree(GetProcessHeap(), 0, patch->mem);
6189 HeapFree(GetProcessHeap(), 0, patch);
6194 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6195 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6196 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6197 FIXME("(%p) : Stub\n", This);
6201 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6204 struct WineD3DRectPatch *patch;
6206 TRACE("(%p) Handle(%d)\n", This, Handle);
6208 i = PATCHMAP_HASHFUNC(Handle);
6209 LIST_FOR_EACH(e, &This->patches[i]) {
6210 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6211 if(patch->Handle == Handle) {
6212 TRACE("Deleting patch %p\n", patch);
6213 list_remove(&patch->entry);
6214 HeapFree(GetProcessHeap(), 0, patch->mem);
6215 HeapFree(GetProcessHeap(), 0, patch);
6220 /* TODO: Write a test for the return value */
6221 FIXME("Attempt to destroy nonexistent patch\n");
6222 return WINED3DERR_INVALIDCALL;
6225 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6227 IWineD3DSwapChain *swapchain;
6229 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6230 if (SUCCEEDED(hr)) {
6231 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6238 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6239 const WINED3DRECT *rect, const float color[4])
6241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6242 IWineD3DSwapChain *swapchain;
6244 swapchain = get_swapchain(surface);
6248 TRACE("Surface %p is onscreen\n", surface);
6250 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6252 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6253 buffer = surface_get_gl_buffer(surface, swapchain);
6254 glDrawBuffer(buffer);
6255 checkGLcall("glDrawBuffer()");
6257 TRACE("Surface %p is offscreen\n", surface);
6259 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6261 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6262 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6263 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6264 checkGLcall("glFramebufferRenderbufferEXT");
6268 glEnable(GL_SCISSOR_TEST);
6270 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6272 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6273 rect->x2 - rect->x1, rect->y2 - rect->y1);
6275 checkGLcall("glScissor");
6276 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6278 glDisable(GL_SCISSOR_TEST);
6280 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6282 glDisable(GL_BLEND);
6283 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6285 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6286 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6288 glClearColor(color[0], color[1], color[2], color[3]);
6289 glClear(GL_COLOR_BUFFER_BIT);
6290 checkGLcall("glClear");
6292 if (This->activeContext->current_fbo) {
6293 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6295 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6296 checkGLcall("glBindFramebuffer()");
6299 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6300 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6301 glDrawBuffer(GL_BACK);
6302 checkGLcall("glDrawBuffer()");
6308 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6309 unsigned int r, g, b, a;
6312 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6313 destfmt == WINED3DFMT_R8G8B8)
6316 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6318 a = (color & 0xff000000) >> 24;
6319 r = (color & 0x00ff0000) >> 16;
6320 g = (color & 0x0000ff00) >> 8;
6321 b = (color & 0x000000ff) >> 0;
6325 case WINED3DFMT_R5G6B5:
6326 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6333 TRACE("Returning %08x\n", ret);
6336 case WINED3DFMT_X1R5G5B5:
6337 case WINED3DFMT_A1R5G5B5:
6346 TRACE("Returning %08x\n", ret);
6349 case WINED3DFMT_A8_UNORM:
6350 TRACE("Returning %08x\n", a);
6353 case WINED3DFMT_X4R4G4B4:
6354 case WINED3DFMT_A4R4G4B4:
6363 TRACE("Returning %08x\n", ret);
6366 case WINED3DFMT_R3G3B2:
6373 TRACE("Returning %08x\n", ret);
6376 case WINED3DFMT_X8B8G8R8:
6377 case WINED3DFMT_R8G8B8A8_UNORM:
6382 TRACE("Returning %08x\n", ret);
6385 case WINED3DFMT_A2R10G10B10:
6387 r = (r * 1024) / 256;
6388 g = (g * 1024) / 256;
6389 b = (b * 1024) / 256;
6394 TRACE("Returning %08x\n", ret);
6397 case WINED3DFMT_R10G10B10A2_UNORM:
6399 r = (r * 1024) / 256;
6400 g = (g * 1024) / 256;
6401 b = (b * 1024) / 256;
6406 TRACE("Returning %08x\n", ret);
6410 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6415 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6417 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6419 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6421 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6422 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6423 return WINED3DERR_INVALIDCALL;
6426 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6427 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6428 color_fill_fbo(iface, pSurface, pRect, c);
6431 /* Just forward this to the DirectDraw blitting engine */
6432 memset(&BltFx, 0, sizeof(BltFx));
6433 BltFx.dwSize = sizeof(BltFx);
6434 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6435 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6436 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6440 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6441 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6443 IWineD3DResource *resource;
6444 IWineD3DSurface *surface;
6447 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6450 ERR("Failed to get resource, hr %#x\n", hr);
6454 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6456 FIXME("Only supported on surface resources\n");
6457 IWineD3DResource_Release(resource);
6461 surface = (IWineD3DSurface *)resource;
6463 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6465 color_fill_fbo(iface, surface, NULL, color);
6472 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6474 c = ((DWORD)(color[2] * 255.0));
6475 c |= ((DWORD)(color[1] * 255.0)) << 8;
6476 c |= ((DWORD)(color[0] * 255.0)) << 16;
6477 c |= ((DWORD)(color[3] * 255.0)) << 24;
6479 /* Just forward this to the DirectDraw blitting engine */
6480 memset(&BltFx, 0, sizeof(BltFx));
6481 BltFx.dwSize = sizeof(BltFx);
6482 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6483 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6486 ERR("Blt failed, hr %#x\n", hr);
6490 IWineD3DResource_Release(resource);
6493 /* rendertarget and depth stencil functions */
6494 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6497 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6498 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6499 return WINED3DERR_INVALIDCALL;
6502 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6503 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6504 /* Note inc ref on returned surface */
6505 if(*ppRenderTarget != NULL)
6506 IWineD3DSurface_AddRef(*ppRenderTarget);
6510 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6511 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6512 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6513 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6514 IWineD3DSwapChainImpl *Swapchain;
6517 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6519 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6520 if(hr != WINED3D_OK) {
6521 ERR("Can't get the swapchain\n");
6525 /* Make sure to release the swapchain */
6526 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6528 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6529 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6530 return WINED3DERR_INVALIDCALL;
6532 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6533 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6534 return WINED3DERR_INVALIDCALL;
6537 if(Swapchain->frontBuffer != Front) {
6538 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6540 if(Swapchain->frontBuffer)
6542 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6543 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6545 Swapchain->frontBuffer = Front;
6547 if(Swapchain->frontBuffer) {
6548 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6549 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6553 if(Back && !Swapchain->backBuffer) {
6554 /* We need memory for the back buffer array - only one back buffer this way */
6555 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6556 if(!Swapchain->backBuffer) {
6557 ERR("Out of memory\n");
6558 return E_OUTOFMEMORY;
6562 if(Swapchain->backBuffer[0] != Back) {
6563 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6565 /* What to do about the context here in the case of multithreading? Not sure.
6566 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6569 if(!Swapchain->backBuffer[0]) {
6570 /* GL was told to draw to the front buffer at creation,
6573 glDrawBuffer(GL_BACK);
6574 checkGLcall("glDrawBuffer(GL_BACK)");
6575 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6576 Swapchain->presentParms.BackBufferCount = 1;
6578 /* That makes problems - disable for now */
6579 /* glDrawBuffer(GL_FRONT); */
6580 checkGLcall("glDrawBuffer(GL_FRONT)");
6581 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6582 Swapchain->presentParms.BackBufferCount = 0;
6586 if(Swapchain->backBuffer[0])
6588 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6589 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6591 Swapchain->backBuffer[0] = Back;
6593 if(Swapchain->backBuffer[0]) {
6594 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6595 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6597 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6598 Swapchain->backBuffer = NULL;
6606 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6608 *ppZStencilSurface = This->stencilBufferTarget;
6609 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6611 if(*ppZStencilSurface != NULL) {
6612 /* Note inc ref on returned surface */
6613 IWineD3DSurface_AddRef(*ppZStencilSurface);
6616 return WINED3DERR_NOTFOUND;
6620 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6621 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6624 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6625 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6627 POINT offset = {0, 0};
6629 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6630 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6631 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6632 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6635 case WINED3DTEXF_LINEAR:
6636 gl_filter = GL_LINEAR;
6640 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6641 case WINED3DTEXF_NONE:
6642 case WINED3DTEXF_POINT:
6643 gl_filter = GL_NEAREST;
6647 /* Attach src surface to src fbo */
6648 src_swapchain = get_swapchain(src_surface);
6649 if (src_swapchain) {
6650 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6652 TRACE("Source surface %p is onscreen\n", src_surface);
6653 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6654 /* Make sure the drawable is up to date. In the offscreen case
6655 * attach_surface_fbo() implicitly takes care of this. */
6656 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6658 if(buffer == GL_FRONT) {
6661 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6662 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6663 h = windowsize.bottom - windowsize.top;
6664 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6665 src_rect->y1 = offset.y + h - src_rect->y1;
6666 src_rect->y2 = offset.y + h - src_rect->y2;
6668 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6669 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6673 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6674 glReadBuffer(buffer);
6675 checkGLcall("glReadBuffer()");
6677 TRACE("Source surface %p is offscreen\n", src_surface);
6679 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6680 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6681 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6682 checkGLcall("glReadBuffer()");
6683 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6684 checkGLcall("glFramebufferRenderbufferEXT");
6688 /* Attach dst surface to dst fbo */
6689 dst_swapchain = get_swapchain(dst_surface);
6690 if (dst_swapchain) {
6691 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6693 TRACE("Destination surface %p is onscreen\n", dst_surface);
6694 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6695 /* Make sure the drawable is up to date. In the offscreen case
6696 * attach_surface_fbo() implicitly takes care of this. */
6697 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6699 if(buffer == GL_FRONT) {
6702 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6703 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6704 h = windowsize.bottom - windowsize.top;
6705 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6706 dst_rect->y1 = offset.y + h - dst_rect->y1;
6707 dst_rect->y2 = offset.y + h - dst_rect->y2;
6709 /* Screen coords = window coords, surface height = window height */
6710 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6711 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6715 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6716 glDrawBuffer(buffer);
6717 checkGLcall("glDrawBuffer()");
6719 TRACE("Destination surface %p is offscreen\n", dst_surface);
6721 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6722 if(!src_swapchain) {
6723 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6727 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6728 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6729 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6730 checkGLcall("glDrawBuffer()");
6731 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6732 checkGLcall("glFramebufferRenderbufferEXT");
6734 glDisable(GL_SCISSOR_TEST);
6735 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6738 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6739 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6740 checkGLcall("glBlitFramebuffer()");
6742 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6743 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6744 checkGLcall("glBlitFramebuffer()");
6747 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6749 if (This->activeContext->current_fbo) {
6750 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6752 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6753 checkGLcall("glBindFramebuffer()");
6756 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6757 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6758 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6759 glDrawBuffer(GL_BACK);
6760 checkGLcall("glDrawBuffer()");
6765 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6767 WINED3DVIEWPORT viewport;
6769 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6771 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6772 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6773 This, RenderTargetIndex, GL_LIMITS(buffers));
6774 return WINED3DERR_INVALIDCALL;
6777 /* MSDN says that null disables the render target
6778 but a device must always be associated with a render target
6779 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6781 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6782 FIXME("Trying to set render target 0 to NULL\n");
6783 return WINED3DERR_INVALIDCALL;
6785 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6786 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);
6787 return WINED3DERR_INVALIDCALL;
6790 /* If we are trying to set what we already have, don't bother */
6791 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6792 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6795 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6796 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6797 This->render_targets[RenderTargetIndex] = pRenderTarget;
6799 /* Render target 0 is special */
6800 if(RenderTargetIndex == 0) {
6801 /* Finally, reset the viewport as the MSDN states. */
6802 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6803 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6806 viewport.MaxZ = 1.0f;
6807 viewport.MinZ = 0.0f;
6808 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6809 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6810 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6812 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6817 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6819 HRESULT hr = WINED3D_OK;
6820 IWineD3DSurface *tmp;
6822 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6824 if (pNewZStencil == This->stencilBufferTarget) {
6825 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6827 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6828 * depending on the renter target implementation being used.
6829 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6830 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6831 * stencil buffer and incur an extra memory overhead
6832 ******************************************************/
6834 if (This->stencilBufferTarget) {
6835 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6836 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6837 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6839 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6840 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6841 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6845 tmp = This->stencilBufferTarget;
6846 This->stencilBufferTarget = pNewZStencil;
6847 /* should we be calling the parent or the wined3d surface? */
6848 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6849 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6852 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6853 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6854 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6855 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6856 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6863 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6864 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6866 /* TODO: the use of Impl is deprecated. */
6867 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6868 WINED3DLOCKED_RECT lockedRect;
6870 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6872 /* some basic validation checks */
6873 if(This->cursorTexture) {
6874 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6876 glDeleteTextures(1, &This->cursorTexture);
6878 This->cursorTexture = 0;
6881 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6882 This->haveHardwareCursor = TRUE;
6884 This->haveHardwareCursor = FALSE;
6887 WINED3DLOCKED_RECT rect;
6889 /* MSDN: Cursor must be A8R8G8B8 */
6890 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
6892 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6893 return WINED3DERR_INVALIDCALL;
6896 /* MSDN: Cursor must be smaller than the display mode */
6897 if(pSur->currentDesc.Width > This->ddraw_width ||
6898 pSur->currentDesc.Height > This->ddraw_height) {
6899 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);
6900 return WINED3DERR_INVALIDCALL;
6903 if (!This->haveHardwareCursor) {
6904 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6906 /* Do not store the surface's pointer because the application may
6907 * release it after setting the cursor image. Windows doesn't
6908 * addref the set surface, so we can't do this either without
6909 * creating circular refcount dependencies. Copy out the gl texture
6912 This->cursorWidth = pSur->currentDesc.Width;
6913 This->cursorHeight = pSur->currentDesc.Height;
6914 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6916 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
6917 char *mem, *bits = rect.pBits;
6918 GLint intfmt = glDesc->glInternal;
6919 GLint format = glDesc->glFormat;
6920 GLint type = glDesc->glType;
6921 INT height = This->cursorHeight;
6922 INT width = This->cursorWidth;
6923 INT bpp = glDesc->byte_count;
6926 /* Reformat the texture memory (pitch and width can be
6928 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6929 for(i = 0; i < height; i++)
6930 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6931 IWineD3DSurface_UnlockRect(pCursorBitmap);
6934 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6935 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6936 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6939 /* Make sure that a proper texture unit is selected */
6940 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6941 checkGLcall("glActiveTextureARB");
6942 sampler = This->rev_tex_unit_map[0];
6943 if (sampler != -1) {
6944 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6946 /* Create a new cursor texture */
6947 glGenTextures(1, &This->cursorTexture);
6948 checkGLcall("glGenTextures");
6949 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6950 checkGLcall("glBindTexture");
6951 /* Copy the bitmap memory into the cursor texture */
6952 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6953 HeapFree(GetProcessHeap(), 0, mem);
6954 checkGLcall("glTexImage2D");
6956 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6957 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6958 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6965 FIXME("A cursor texture was not returned.\n");
6966 This->cursorTexture = 0;
6971 /* Draw a hardware cursor */
6972 ICONINFO cursorInfo;
6974 /* Create and clear maskBits because it is not needed for
6975 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6977 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6978 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6979 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6980 WINED3DLOCK_NO_DIRTY_UPDATE |
6981 WINED3DLOCK_READONLY
6983 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6984 pSur->currentDesc.Height);
6986 cursorInfo.fIcon = FALSE;
6987 cursorInfo.xHotspot = XHotSpot;
6988 cursorInfo.yHotspot = YHotSpot;
6989 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6990 pSur->currentDesc.Height, 1,
6992 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6993 pSur->currentDesc.Height, 1,
6994 32, lockedRect.pBits);
6995 IWineD3DSurface_UnlockRect(pCursorBitmap);
6996 /* Create our cursor and clean up. */
6997 cursor = CreateIconIndirect(&cursorInfo);
6999 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
7000 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
7001 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
7002 This->hardwareCursor = cursor;
7003 HeapFree(GetProcessHeap(), 0, maskBits);
7007 This->xHotSpot = XHotSpot;
7008 This->yHotSpot = YHotSpot;
7012 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7014 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7016 This->xScreenSpace = XScreenSpace;
7017 This->yScreenSpace = YScreenSpace;
7023 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7025 BOOL oldVisible = This->bCursorVisible;
7028 TRACE("(%p) : visible(%d)\n", This, bShow);
7031 * When ShowCursor is first called it should make the cursor appear at the OS's last
7032 * known cursor position. Because of this, some applications just repetitively call
7033 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7036 This->xScreenSpace = pt.x;
7037 This->yScreenSpace = pt.y;
7039 if (This->haveHardwareCursor) {
7040 This->bCursorVisible = bShow;
7042 SetCursor(This->hardwareCursor);
7048 if (This->cursorTexture)
7049 This->bCursorVisible = bShow;
7055 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7057 IWineD3DResourceImpl *resource;
7058 TRACE("(%p) : state (%u)\n", This, This->state);
7060 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7061 switch (This->state) {
7064 case WINED3DERR_DEVICELOST:
7066 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7067 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7068 return WINED3DERR_DEVICENOTRESET;
7070 return WINED3DERR_DEVICELOST;
7072 case WINED3DERR_DRIVERINTERNALERROR:
7073 return WINED3DERR_DRIVERINTERNALERROR;
7077 return WINED3DERR_DRIVERINTERNALERROR;
7081 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7083 /** FIXME: Resource tracking needs to be done,
7084 * The closes we can do to this is set the priorities of all managed textures low
7085 * and then reset them.
7086 ***********************************************************/
7087 FIXME("(%p) : stub\n", This);
7091 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
7093 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7095 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7096 if(surface->Flags & SFLAG_DIBSECTION) {
7097 /* Release the DC */
7098 SelectObject(surface->hDC, surface->dib.holdbitmap);
7099 DeleteDC(surface->hDC);
7100 /* Release the DIB section */
7101 DeleteObject(surface->dib.DIBsection);
7102 surface->dib.bitmap_data = NULL;
7103 surface->resource.allocatedMemory = NULL;
7104 surface->Flags &= ~SFLAG_DIBSECTION;
7106 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7107 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7108 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7109 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7110 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7111 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7113 surface->pow2Width = surface->pow2Height = 1;
7114 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7115 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7117 surface->glRect.left = 0;
7118 surface->glRect.top = 0;
7119 surface->glRect.right = surface->pow2Width;
7120 surface->glRect.bottom = surface->pow2Height;
7122 if(surface->glDescription.textureName) {
7123 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7125 glDeleteTextures(1, &surface->glDescription.textureName);
7127 surface->glDescription.textureName = 0;
7128 surface->Flags &= ~SFLAG_CLIENT;
7130 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7131 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7132 surface->Flags |= SFLAG_NONPOW2;
7134 surface->Flags &= ~SFLAG_NONPOW2;
7136 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7137 surface->resource.allocatedMemory = NULL;
7138 surface->resource.heapMemory = NULL;
7139 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7140 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7141 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7142 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7144 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7148 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7149 TRACE("Unloading resource %p\n", resource);
7150 IWineD3DResource_UnLoad(resource);
7151 IWineD3DResource_Release(resource);
7155 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7158 WINED3DDISPLAYMODE m;
7161 /* All Windowed modes are supported, as is leaving the current mode */
7162 if(pp->Windowed) return TRUE;
7163 if(!pp->BackBufferWidth) return TRUE;
7164 if(!pp->BackBufferHeight) return TRUE;
7166 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7167 for(i = 0; i < count; i++) {
7168 memset(&m, 0, sizeof(m));
7169 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7171 ERR("EnumAdapterModes failed\n");
7173 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7174 /* Mode found, it is supported */
7178 /* Mode not found -> not supported */
7182 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7184 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7186 IWineD3DBaseShaderImpl *shader;
7188 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7189 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7190 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7194 if(This->depth_blt_texture) {
7195 glDeleteTextures(1, &This->depth_blt_texture);
7196 This->depth_blt_texture = 0;
7198 if (This->depth_blt_rb) {
7199 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7200 This->depth_blt_rb = 0;
7201 This->depth_blt_rb_w = 0;
7202 This->depth_blt_rb_h = 0;
7206 This->blitter->free_private(iface);
7207 This->frag_pipe->free_private(iface);
7208 This->shader_backend->shader_free_private(iface);
7211 for (i = 0; i < GL_LIMITS(textures); i++) {
7212 /* Textures are recreated below */
7213 glDeleteTextures(1, &This->dummyTextureName[i]);
7214 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7215 This->dummyTextureName[i] = 0;
7219 while(This->numContexts) {
7220 DestroyContext(This, This->contexts[0]);
7222 This->activeContext = NULL;
7223 HeapFree(GetProcessHeap(), 0, swapchain->context);
7224 swapchain->context = NULL;
7225 swapchain->num_contexts = 0;
7228 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7230 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7232 IWineD3DSurfaceImpl *target;
7234 /* Recreate the primary swapchain's context */
7235 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7236 if(swapchain->backBuffer) {
7237 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7239 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7241 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7242 &swapchain->presentParms);
7243 swapchain->num_contexts = 1;
7244 This->activeContext = swapchain->context[0];
7246 create_dummy_textures(This);
7248 hr = This->shader_backend->shader_alloc_private(iface);
7250 ERR("Failed to recreate shader private data\n");
7253 hr = This->frag_pipe->alloc_private(iface);
7255 TRACE("Fragment pipeline private data couldn't be allocated\n");
7258 hr = This->blitter->alloc_private(iface);
7260 TRACE("Blitter private data couldn't be allocated\n");
7267 This->blitter->free_private(iface);
7268 This->frag_pipe->free_private(iface);
7269 This->shader_backend->shader_free_private(iface);
7273 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7275 IWineD3DSwapChainImpl *swapchain;
7277 BOOL DisplayModeChanged = FALSE;
7278 WINED3DDISPLAYMODE mode;
7279 TRACE("(%p)\n", This);
7281 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7283 ERR("Failed to get the first implicit swapchain\n");
7287 if(!is_display_mode_supported(This, pPresentationParameters)) {
7288 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7289 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7290 pPresentationParameters->BackBufferHeight);
7291 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7292 return WINED3DERR_INVALIDCALL;
7295 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7296 * on an existing gl context, so there's no real need for recreation.
7298 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7300 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7302 TRACE("New params:\n");
7303 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7304 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7305 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7306 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7307 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7308 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7309 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7310 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7311 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7312 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7313 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7314 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7315 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7317 /* No special treatment of these parameters. Just store them */
7318 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7319 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7320 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7321 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7323 /* What to do about these? */
7324 if(pPresentationParameters->BackBufferCount != 0 &&
7325 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7326 ERR("Cannot change the back buffer count yet\n");
7328 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7329 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7330 ERR("Cannot change the back buffer format yet\n");
7332 if(pPresentationParameters->hDeviceWindow != NULL &&
7333 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7334 ERR("Cannot change the device window yet\n");
7336 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7339 TRACE("Creating the depth stencil buffer\n");
7341 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
7343 pPresentationParameters->BackBufferWidth,
7344 pPresentationParameters->BackBufferHeight,
7345 pPresentationParameters->AutoDepthStencilFormat,
7346 pPresentationParameters->MultiSampleType,
7347 pPresentationParameters->MultiSampleQuality,
7349 &This->auto_depth_stencil_buffer);
7352 ERR("Failed to create the depth stencil buffer\n");
7353 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7354 return WINED3DERR_INVALIDCALL;
7358 /* Reset the depth stencil */
7359 if (pPresentationParameters->EnableAutoDepthStencil)
7360 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7362 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7364 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7366 if(pPresentationParameters->Windowed) {
7367 mode.Width = swapchain->orig_width;
7368 mode.Height = swapchain->orig_height;
7369 mode.RefreshRate = 0;
7370 mode.Format = swapchain->presentParms.BackBufferFormat;
7372 mode.Width = pPresentationParameters->BackBufferWidth;
7373 mode.Height = pPresentationParameters->BackBufferHeight;
7374 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7375 mode.Format = swapchain->presentParms.BackBufferFormat;
7378 /* Should Width == 800 && Height == 0 set 800x600? */
7379 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7380 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7381 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7385 if(!pPresentationParameters->Windowed) {
7386 DisplayModeChanged = TRUE;
7388 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7389 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7391 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7392 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7393 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7395 if(This->auto_depth_stencil_buffer) {
7396 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7400 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7401 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7402 DisplayModeChanged) {
7404 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7406 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7407 if(swapchain->presentParms.Windowed) {
7408 /* switch from windowed to fs */
7409 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7410 pPresentationParameters->BackBufferWidth,
7411 pPresentationParameters->BackBufferHeight);
7413 /* Fullscreen -> fullscreen mode change */
7414 MoveWindow(swapchain->win_handle, 0, 0,
7415 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7418 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7419 /* Fullscreen -> windowed switch */
7420 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7422 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7423 } else if(!pPresentationParameters->Windowed) {
7424 DWORD style = This->style, exStyle = This->exStyle;
7425 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7426 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7427 * Reset to clear up their mess. Guild Wars also loses the device during that.
7431 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7432 pPresentationParameters->BackBufferWidth,
7433 pPresentationParameters->BackBufferHeight);
7434 This->style = style;
7435 This->exStyle = exStyle;
7438 TRACE("Resetting stateblock\n");
7439 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7440 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7442 /* Note: No parent needed for initial internal stateblock */
7443 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7444 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7445 else TRACE("Created stateblock %p\n", This->stateBlock);
7446 This->updateStateBlock = This->stateBlock;
7447 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7449 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7451 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7454 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7455 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7457 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7463 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7465 /** FIXME: always true at the moment **/
7466 if(!bEnableDialogs) {
7467 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7473 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7474 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7475 TRACE("(%p) : pParameters %p\n", This, pParameters);
7477 *pParameters = This->createParms;
7481 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7482 IWineD3DSwapChain *swapchain;
7484 TRACE("Relaying to swapchain\n");
7486 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7487 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7488 IWineD3DSwapChain_Release(swapchain);
7493 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7494 IWineD3DSwapChain *swapchain;
7496 TRACE("Relaying to swapchain\n");
7498 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7499 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7500 IWineD3DSwapChain_Release(swapchain);
7506 /** ********************************************************
7507 * Notification functions
7508 ** ********************************************************/
7509 /** This function must be called in the release of a resource when ref == 0,
7510 * the contents of resource must still be correct,
7511 * any handles to other resource held by the caller must be closed
7512 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7513 *****************************************************/
7514 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7516 TRACE("(%p) : Adding resource %p\n", This, resource);
7518 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7521 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7523 TRACE("(%p) : Removing resource %p\n", This, resource);
7525 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7528 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7530 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7533 TRACE("(%p) : resource %p\n", This, resource);
7535 context_resource_released((IWineD3DDevice *)This, resource, type);
7538 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7539 case WINED3DRTYPE_SURFACE: {
7542 /* Cleanup any FBO attachments if d3d is enabled */
7543 if(This->d3d_initialized) {
7544 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7545 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7547 TRACE("Last active render target destroyed\n");
7548 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7549 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7550 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7551 * and the lastActiveRenderTarget member shouldn't matter
7554 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7555 TRACE("Activating primary back buffer\n");
7556 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7557 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7558 /* Single buffering environment */
7559 TRACE("Activating primary front buffer\n");
7560 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7562 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7563 /* Implicit render target destroyed, that means the device is being destroyed
7564 * whatever we set here, it shouldn't matter
7566 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7569 /* May happen during ddraw uninitialization */
7570 TRACE("Render target set, but swapchain does not exist!\n");
7571 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7575 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7576 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7577 This->render_targets[i] = NULL;
7580 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7581 This->stencilBufferTarget = NULL;
7587 case WINED3DRTYPE_TEXTURE:
7588 case WINED3DRTYPE_CUBETEXTURE:
7589 case WINED3DRTYPE_VOLUMETEXTURE:
7590 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7591 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7592 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7593 This->stateBlock->textures[counter] = NULL;
7595 if (This->updateStateBlock != This->stateBlock ){
7596 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7597 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7598 This->updateStateBlock->textures[counter] = NULL;
7603 case WINED3DRTYPE_VOLUME:
7604 /* TODO: nothing really? */
7606 case WINED3DRTYPE_BUFFER:
7609 TRACE("Cleaning up stream pointers\n");
7611 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7612 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7613 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7615 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7616 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7617 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7618 This->updateStateBlock->streamSource[streamNumber] = 0;
7619 /* Set changed flag? */
7622 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) */
7623 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7624 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7625 This->stateBlock->streamSource[streamNumber] = 0;
7630 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7631 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7632 This->updateStateBlock->pIndexData = NULL;
7635 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7636 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7637 This->stateBlock->pIndexData = NULL;
7644 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7649 /* Remove the resource from the resourceStore */
7650 device_resource_remove(This, resource);
7652 TRACE("Resource released\n");
7656 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7658 IWineD3DResourceImpl *resource, *cursor;
7660 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7662 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7663 TRACE("enumerating resource %p\n", resource);
7664 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7665 ret = pCallback((IWineD3DResource *) resource, pData);
7666 if(ret == S_FALSE) {
7667 TRACE("Canceling enumeration\n");
7674 /**********************************************************
7675 * IWineD3DDevice VTbl follows
7676 **********************************************************/
7678 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7680 /*** IUnknown methods ***/
7681 IWineD3DDeviceImpl_QueryInterface,
7682 IWineD3DDeviceImpl_AddRef,
7683 IWineD3DDeviceImpl_Release,
7684 /*** IWineD3DDevice methods ***/
7685 IWineD3DDeviceImpl_GetParent,
7686 /*** Creation methods**/
7687 IWineD3DDeviceImpl_CreateBuffer,
7688 IWineD3DDeviceImpl_CreateVertexBuffer,
7689 IWineD3DDeviceImpl_CreateIndexBuffer,
7690 IWineD3DDeviceImpl_CreateStateBlock,
7691 IWineD3DDeviceImpl_CreateSurface,
7692 IWineD3DDeviceImpl_CreateRendertargetView,
7693 IWineD3DDeviceImpl_CreateTexture,
7694 IWineD3DDeviceImpl_CreateVolumeTexture,
7695 IWineD3DDeviceImpl_CreateVolume,
7696 IWineD3DDeviceImpl_CreateCubeTexture,
7697 IWineD3DDeviceImpl_CreateQuery,
7698 IWineD3DDeviceImpl_CreateSwapChain,
7699 IWineD3DDeviceImpl_CreateVertexDeclaration,
7700 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7701 IWineD3DDeviceImpl_CreateVertexShader,
7702 IWineD3DDeviceImpl_CreatePixelShader,
7703 IWineD3DDeviceImpl_CreatePalette,
7704 /*** Odd functions **/
7705 IWineD3DDeviceImpl_Init3D,
7706 IWineD3DDeviceImpl_InitGDI,
7707 IWineD3DDeviceImpl_Uninit3D,
7708 IWineD3DDeviceImpl_UninitGDI,
7709 IWineD3DDeviceImpl_SetMultithreaded,
7710 IWineD3DDeviceImpl_EvictManagedResources,
7711 IWineD3DDeviceImpl_GetAvailableTextureMem,
7712 IWineD3DDeviceImpl_GetBackBuffer,
7713 IWineD3DDeviceImpl_GetCreationParameters,
7714 IWineD3DDeviceImpl_GetDeviceCaps,
7715 IWineD3DDeviceImpl_GetDirect3D,
7716 IWineD3DDeviceImpl_GetDisplayMode,
7717 IWineD3DDeviceImpl_SetDisplayMode,
7718 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7719 IWineD3DDeviceImpl_GetRasterStatus,
7720 IWineD3DDeviceImpl_GetSwapChain,
7721 IWineD3DDeviceImpl_Reset,
7722 IWineD3DDeviceImpl_SetDialogBoxMode,
7723 IWineD3DDeviceImpl_SetCursorProperties,
7724 IWineD3DDeviceImpl_SetCursorPosition,
7725 IWineD3DDeviceImpl_ShowCursor,
7726 IWineD3DDeviceImpl_TestCooperativeLevel,
7727 /*** Getters and setters **/
7728 IWineD3DDeviceImpl_SetClipPlane,
7729 IWineD3DDeviceImpl_GetClipPlane,
7730 IWineD3DDeviceImpl_SetClipStatus,
7731 IWineD3DDeviceImpl_GetClipStatus,
7732 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7733 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7734 IWineD3DDeviceImpl_SetDepthStencilSurface,
7735 IWineD3DDeviceImpl_GetDepthStencilSurface,
7736 IWineD3DDeviceImpl_SetGammaRamp,
7737 IWineD3DDeviceImpl_GetGammaRamp,
7738 IWineD3DDeviceImpl_SetIndices,
7739 IWineD3DDeviceImpl_GetIndices,
7740 IWineD3DDeviceImpl_SetBaseVertexIndex,
7741 IWineD3DDeviceImpl_GetBaseVertexIndex,
7742 IWineD3DDeviceImpl_SetLight,
7743 IWineD3DDeviceImpl_GetLight,
7744 IWineD3DDeviceImpl_SetLightEnable,
7745 IWineD3DDeviceImpl_GetLightEnable,
7746 IWineD3DDeviceImpl_SetMaterial,
7747 IWineD3DDeviceImpl_GetMaterial,
7748 IWineD3DDeviceImpl_SetNPatchMode,
7749 IWineD3DDeviceImpl_GetNPatchMode,
7750 IWineD3DDeviceImpl_SetPaletteEntries,
7751 IWineD3DDeviceImpl_GetPaletteEntries,
7752 IWineD3DDeviceImpl_SetPixelShader,
7753 IWineD3DDeviceImpl_GetPixelShader,
7754 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7755 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7756 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7757 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7758 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7759 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7760 IWineD3DDeviceImpl_SetRenderState,
7761 IWineD3DDeviceImpl_GetRenderState,
7762 IWineD3DDeviceImpl_SetRenderTarget,
7763 IWineD3DDeviceImpl_GetRenderTarget,
7764 IWineD3DDeviceImpl_SetFrontBackBuffers,
7765 IWineD3DDeviceImpl_SetSamplerState,
7766 IWineD3DDeviceImpl_GetSamplerState,
7767 IWineD3DDeviceImpl_SetScissorRect,
7768 IWineD3DDeviceImpl_GetScissorRect,
7769 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7770 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7771 IWineD3DDeviceImpl_SetStreamSource,
7772 IWineD3DDeviceImpl_GetStreamSource,
7773 IWineD3DDeviceImpl_SetStreamSourceFreq,
7774 IWineD3DDeviceImpl_GetStreamSourceFreq,
7775 IWineD3DDeviceImpl_SetTexture,
7776 IWineD3DDeviceImpl_GetTexture,
7777 IWineD3DDeviceImpl_SetTextureStageState,
7778 IWineD3DDeviceImpl_GetTextureStageState,
7779 IWineD3DDeviceImpl_SetTransform,
7780 IWineD3DDeviceImpl_GetTransform,
7781 IWineD3DDeviceImpl_SetVertexDeclaration,
7782 IWineD3DDeviceImpl_GetVertexDeclaration,
7783 IWineD3DDeviceImpl_SetVertexShader,
7784 IWineD3DDeviceImpl_GetVertexShader,
7785 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7786 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7787 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7788 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7789 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7790 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7791 IWineD3DDeviceImpl_SetViewport,
7792 IWineD3DDeviceImpl_GetViewport,
7793 IWineD3DDeviceImpl_MultiplyTransform,
7794 IWineD3DDeviceImpl_ValidateDevice,
7795 IWineD3DDeviceImpl_ProcessVertices,
7796 /*** State block ***/
7797 IWineD3DDeviceImpl_BeginStateBlock,
7798 IWineD3DDeviceImpl_EndStateBlock,
7799 /*** Scene management ***/
7800 IWineD3DDeviceImpl_BeginScene,
7801 IWineD3DDeviceImpl_EndScene,
7802 IWineD3DDeviceImpl_Present,
7803 IWineD3DDeviceImpl_Clear,
7804 IWineD3DDeviceImpl_ClearRendertargetView,
7806 IWineD3DDeviceImpl_SetPrimitiveType,
7807 IWineD3DDeviceImpl_GetPrimitiveType,
7808 IWineD3DDeviceImpl_DrawPrimitive,
7809 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7810 IWineD3DDeviceImpl_DrawPrimitiveUP,
7811 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7812 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7813 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7814 IWineD3DDeviceImpl_DrawRectPatch,
7815 IWineD3DDeviceImpl_DrawTriPatch,
7816 IWineD3DDeviceImpl_DeletePatch,
7817 IWineD3DDeviceImpl_ColorFill,
7818 IWineD3DDeviceImpl_UpdateTexture,
7819 IWineD3DDeviceImpl_UpdateSurface,
7820 IWineD3DDeviceImpl_GetFrontBufferData,
7821 /*** object tracking ***/
7822 IWineD3DDeviceImpl_EnumResources
7825 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7826 WINED3DRS_ALPHABLENDENABLE ,
7827 WINED3DRS_ALPHAFUNC ,
7828 WINED3DRS_ALPHAREF ,
7829 WINED3DRS_ALPHATESTENABLE ,
7831 WINED3DRS_COLORWRITEENABLE ,
7832 WINED3DRS_DESTBLEND ,
7833 WINED3DRS_DITHERENABLE ,
7834 WINED3DRS_FILLMODE ,
7835 WINED3DRS_FOGDENSITY ,
7837 WINED3DRS_FOGSTART ,
7838 WINED3DRS_LASTPIXEL ,
7839 WINED3DRS_SHADEMODE ,
7840 WINED3DRS_SRCBLEND ,
7841 WINED3DRS_STENCILENABLE ,
7842 WINED3DRS_STENCILFAIL ,
7843 WINED3DRS_STENCILFUNC ,
7844 WINED3DRS_STENCILMASK ,
7845 WINED3DRS_STENCILPASS ,
7846 WINED3DRS_STENCILREF ,
7847 WINED3DRS_STENCILWRITEMASK ,
7848 WINED3DRS_STENCILZFAIL ,
7849 WINED3DRS_TEXTUREFACTOR ,
7860 WINED3DRS_ZWRITEENABLE
7863 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7864 WINED3DTSS_ALPHAARG0 ,
7865 WINED3DTSS_ALPHAARG1 ,
7866 WINED3DTSS_ALPHAARG2 ,
7867 WINED3DTSS_ALPHAOP ,
7868 WINED3DTSS_BUMPENVLOFFSET ,
7869 WINED3DTSS_BUMPENVLSCALE ,
7870 WINED3DTSS_BUMPENVMAT00 ,
7871 WINED3DTSS_BUMPENVMAT01 ,
7872 WINED3DTSS_BUMPENVMAT10 ,
7873 WINED3DTSS_BUMPENVMAT11 ,
7874 WINED3DTSS_COLORARG0 ,
7875 WINED3DTSS_COLORARG1 ,
7876 WINED3DTSS_COLORARG2 ,
7877 WINED3DTSS_COLOROP ,
7878 WINED3DTSS_RESULTARG ,
7879 WINED3DTSS_TEXCOORDINDEX ,
7880 WINED3DTSS_TEXTURETRANSFORMFLAGS
7883 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7884 WINED3DSAMP_ADDRESSU ,
7885 WINED3DSAMP_ADDRESSV ,
7886 WINED3DSAMP_ADDRESSW ,
7887 WINED3DSAMP_BORDERCOLOR ,
7888 WINED3DSAMP_MAGFILTER ,
7889 WINED3DSAMP_MINFILTER ,
7890 WINED3DSAMP_MIPFILTER ,
7891 WINED3DSAMP_MIPMAPLODBIAS ,
7892 WINED3DSAMP_MAXMIPLEVEL ,
7893 WINED3DSAMP_MAXANISOTROPY ,
7894 WINED3DSAMP_SRGBTEXTURE ,
7895 WINED3DSAMP_ELEMENTINDEX
7898 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7900 WINED3DRS_AMBIENTMATERIALSOURCE ,
7901 WINED3DRS_CLIPPING ,
7902 WINED3DRS_CLIPPLANEENABLE ,
7903 WINED3DRS_COLORVERTEX ,
7904 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7905 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7906 WINED3DRS_FOGDENSITY ,
7908 WINED3DRS_FOGSTART ,
7909 WINED3DRS_FOGTABLEMODE ,
7910 WINED3DRS_FOGVERTEXMODE ,
7911 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7912 WINED3DRS_LIGHTING ,
7913 WINED3DRS_LOCALVIEWER ,
7914 WINED3DRS_MULTISAMPLEANTIALIAS ,
7915 WINED3DRS_MULTISAMPLEMASK ,
7916 WINED3DRS_NORMALIZENORMALS ,
7917 WINED3DRS_PATCHEDGESTYLE ,
7918 WINED3DRS_POINTSCALE_A ,
7919 WINED3DRS_POINTSCALE_B ,
7920 WINED3DRS_POINTSCALE_C ,
7921 WINED3DRS_POINTSCALEENABLE ,
7922 WINED3DRS_POINTSIZE ,
7923 WINED3DRS_POINTSIZE_MAX ,
7924 WINED3DRS_POINTSIZE_MIN ,
7925 WINED3DRS_POINTSPRITEENABLE ,
7926 WINED3DRS_RANGEFOGENABLE ,
7927 WINED3DRS_SPECULARMATERIALSOURCE ,
7928 WINED3DRS_TWEENFACTOR ,
7929 WINED3DRS_VERTEXBLEND ,
7930 WINED3DRS_CULLMODE ,
7934 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7935 WINED3DTSS_TEXCOORDINDEX ,
7936 WINED3DTSS_TEXTURETRANSFORMFLAGS
7939 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7940 WINED3DSAMP_DMAPOFFSET
7943 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7944 DWORD rep = This->StateTable[state].representative;
7948 WineD3DContext *context;
7951 for(i = 0; i < This->numContexts; i++) {
7952 context = This->contexts[i];
7953 if(isStateDirty(context, rep)) continue;
7955 context->dirtyArray[context->numDirtyEntries++] = rep;
7958 context->isStateDirty[idx] |= (1 << shift);
7962 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7963 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7964 /* The drawable size of a pbuffer render target is the current pbuffer size
7966 *width = dev->pbufferWidth;
7967 *height = dev->pbufferHeight;
7970 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7971 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7973 *width = This->pow2Width;
7974 *height = This->pow2Height;
7977 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7978 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7979 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7980 * current context's drawable, which is the size of the back buffer of the swapchain
7981 * the active context belongs to. The back buffer of the swapchain is stored as the
7982 * surface the context belongs to.
7984 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7985 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;