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, UINT Width, UINT Height,
893 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
894 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
895 WINED3DSURFTYPE Impl, IUnknown *parent)
897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
898 IWineD3DSurfaceImpl *object;
901 TRACE("(%p) Create surface\n",This);
903 if (Impl == SURFACE_OPENGL && !This->adapter)
905 ERR("OpenGL surfaces are not available without OpenGL.\n");
906 return WINED3DERR_NOTAVAILABLE;
909 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
912 ERR("Failed to allocate surface memory.\n");
914 return WINED3DERR_OUTOFVIDEOMEMORY;
917 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
918 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent);
921 WARN("Failed to initialize surface, returning %#x.\n", hr);
922 HeapFree(GetProcessHeap(), 0, object);
927 TRACE("(%p) : Created surface %p\n", This, object);
929 *ppSurface = (IWineD3DSurface *)object;
934 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
935 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
937 struct wined3d_rendertarget_view *object;
939 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
942 ERR("Failed to allocate memory\n");
943 return E_OUTOFMEMORY;
946 object->vtbl = &wined3d_rendertarget_view_vtbl;
947 object->refcount = 1;
948 IWineD3DResource_AddRef(resource);
949 object->resource = resource;
950 object->parent = parent;
952 *rendertarget_view = (IWineD3DRendertargetView *)object;
957 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
958 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
959 WINED3DPOOL Pool, IWineD3DTexture **ppTexture, IUnknown *parent)
961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
962 IWineD3DTextureImpl *object;
965 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
966 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
967 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
969 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
972 ERR("Out of memory\n");
974 return WINED3DERR_OUTOFVIDEOMEMORY;
977 object->lpVtbl = &IWineD3DTexture_Vtbl;
979 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent);
982 WARN("Failed to initialize texture, returning %#x\n", hr);
983 HeapFree(GetProcessHeap(), 0, object);
988 *ppTexture = (IWineD3DTexture *)object;
990 TRACE("(%p) : Created texture %p\n", This, object);
995 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
996 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
997 WINED3DPOOL Pool, IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent)
999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1000 IWineD3DVolumeTextureImpl *object;
1003 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1004 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1006 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1009 ERR("Out of memory\n");
1010 *ppVolumeTexture = NULL;
1011 return WINED3DERR_OUTOFVIDEOMEMORY;
1014 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1015 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent);
1018 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1019 HeapFree(GetProcessHeap(), 0, object);
1020 *ppVolumeTexture = NULL;
1024 TRACE("(%p) : Created volume texture %p.\n", This, object);
1025 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1030 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1031 UINT Width, UINT Height, UINT Depth, DWORD Usage, WINED3DFORMAT Format,
1032 WINED3DPOOL Pool, IWineD3DVolume **ppVolume, IUnknown *parent)
1034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1035 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1036 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &GLINFO_LOCATION);
1039 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1040 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1041 return WINED3DERR_INVALIDCALL;
1044 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1047 ERR("Out of memory\n");
1049 return WINED3DERR_OUTOFVIDEOMEMORY;
1052 object->lpVtbl = &IWineD3DVolume_Vtbl;
1053 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_VOLUME, This,
1054 Width * Height * Depth * format_desc->byte_count, Usage, format_desc, Pool, parent);
1057 WARN("Failed to initialize resource, returning %#x\n", hr);
1058 HeapFree(GetProcessHeap(), 0, object);
1063 TRACE("(%p) : Created resource %p\n", This, object);
1065 *ppVolume = (IWineD3DVolume *)object;
1067 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1068 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1070 object->currentDesc.Width = Width;
1071 object->currentDesc.Height = Height;
1072 object->currentDesc.Depth = Depth;
1074 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1075 object->lockable = TRUE;
1076 object->locked = FALSE;
1077 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1078 object->dirty = TRUE;
1080 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1085 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1086 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1087 WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture, IUnknown *parent)
1089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1090 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1093 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1096 ERR("Out of memory\n");
1097 *ppCubeTexture = NULL;
1098 return WINED3DERR_OUTOFVIDEOMEMORY;
1101 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1102 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent);
1105 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1106 HeapFree(GetProcessHeap(), 0, object);
1107 *ppCubeTexture = NULL;
1111 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1112 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1117 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1119 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1120 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1121 const IWineD3DQueryVtbl *vtable;
1123 /* Just a check to see if we support this type of query */
1125 case WINED3DQUERYTYPE_OCCLUSION:
1126 TRACE("(%p) occlusion query\n", This);
1127 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1130 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1132 vtable = &IWineD3DOcclusionQuery_Vtbl;
1135 case WINED3DQUERYTYPE_EVENT:
1136 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1137 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1138 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1140 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1142 vtable = &IWineD3DEventQuery_Vtbl;
1146 case WINED3DQUERYTYPE_VCACHE:
1147 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1148 case WINED3DQUERYTYPE_VERTEXSTATS:
1149 case WINED3DQUERYTYPE_TIMESTAMP:
1150 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1151 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1152 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1153 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1154 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1155 case WINED3DQUERYTYPE_PIXELTIMINGS:
1156 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1157 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1159 /* Use the base Query vtable until we have a special one for each query */
1160 vtable = &IWineD3DQuery_Vtbl;
1161 FIXME("(%p) Unhandled query type %d\n", This, Type);
1163 if(NULL == ppQuery || hr != WINED3D_OK) {
1167 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1170 ERR("Out of memory\n");
1172 return WINED3DERR_OUTOFVIDEOMEMORY;
1175 object->lpVtbl = vtable;
1176 object->type = Type;
1177 object->state = QUERY_CREATED;
1178 object->wineD3DDevice = This;
1179 object->parent = parent;
1182 *ppQuery = (IWineD3DQuery *)object;
1184 /* allocated the 'extended' data based on the type of query requested */
1186 case WINED3DQUERYTYPE_OCCLUSION:
1187 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1188 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1190 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1191 TRACE("(%p) Allocating data for an occlusion query\n", This);
1193 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1195 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1199 case WINED3DQUERYTYPE_EVENT:
1200 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1201 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1203 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1205 if(GL_SUPPORT(APPLE_FENCE)) {
1206 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1207 checkGLcall("glGenFencesAPPLE");
1208 } else if(GL_SUPPORT(NV_FENCE)) {
1209 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1210 checkGLcall("glGenFencesNV");
1215 case WINED3DQUERYTYPE_VCACHE:
1216 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1217 case WINED3DQUERYTYPE_VERTEXSTATS:
1218 case WINED3DQUERYTYPE_TIMESTAMP:
1219 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1220 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1221 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1222 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1223 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1224 case WINED3DQUERYTYPE_PIXELTIMINGS:
1225 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1226 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1228 object->extendedData = 0;
1229 FIXME("(%p) Unhandled query type %d\n",This , Type);
1231 TRACE("(%p) : Created Query %p\n", This, object);
1235 /*****************************************************************************
1236 * IWineD3DDeviceImpl_SetupFullscreenWindow
1238 * Helper function that modifies a HWND's Style and ExStyle for proper
1242 * iface: Pointer to the IWineD3DDevice interface
1243 * window: Window to setup
1245 *****************************************************************************/
1246 static LONG fullscreen_style(LONG orig_style) {
1247 LONG style = orig_style;
1248 style &= ~WS_CAPTION;
1249 style &= ~WS_THICKFRAME;
1251 /* Make sure the window is managed, otherwise we won't get keyboard input */
1252 style |= WS_POPUP | WS_SYSMENU;
1257 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1258 LONG exStyle = orig_exStyle;
1260 /* Filter out window decorations */
1261 exStyle &= ~WS_EX_WINDOWEDGE;
1262 exStyle &= ~WS_EX_CLIENTEDGE;
1267 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1270 LONG style, exStyle;
1271 /* Don't do anything if an original style is stored.
1272 * That shouldn't happen
1274 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1275 if (This->style || This->exStyle) {
1276 ERR("(%p): Want to change the window parameters of HWND %p, but "
1277 "another style is stored for restoration afterwards\n", This, window);
1280 /* Get the parameters and save them */
1281 style = GetWindowLongW(window, GWL_STYLE);
1282 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1283 This->style = style;
1284 This->exStyle = exStyle;
1286 style = fullscreen_style(style);
1287 exStyle = fullscreen_exStyle(exStyle);
1289 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1290 This->style, This->exStyle, style, exStyle);
1292 SetWindowLongW(window, GWL_STYLE, style);
1293 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1295 /* Inform the window about the update. */
1296 SetWindowPos(window, HWND_TOP, 0, 0,
1297 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1300 /*****************************************************************************
1301 * IWineD3DDeviceImpl_RestoreWindow
1303 * Helper function that restores a windows' properties when taking it out
1304 * of fullscreen mode
1307 * iface: Pointer to the IWineD3DDevice interface
1308 * window: Window to setup
1310 *****************************************************************************/
1311 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1313 LONG style, exStyle;
1315 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1316 * switch, do nothing
1318 if (!This->style && !This->exStyle) return;
1320 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1321 This, window, This->style, This->exStyle);
1323 style = GetWindowLongW(window, GWL_STYLE);
1324 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1326 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1327 * Some applications change it before calling Reset() when switching between windowed and
1328 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1330 if(style == fullscreen_style(This->style) &&
1331 exStyle == fullscreen_style(This->exStyle)) {
1332 SetWindowLongW(window, GWL_STYLE, This->style);
1333 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1336 /* Delete the old values */
1340 /* Inform the window about the update */
1341 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1342 0, 0, 0, 0, /* Pos, Size, ignored */
1343 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1346 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1347 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1348 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1349 IUnknown *parent, WINED3DSURFTYPE surface_type)
1351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1354 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1356 IUnknown *bufferParent;
1357 BOOL displaymode_set = FALSE;
1358 WINED3DDISPLAYMODE Mode;
1359 const struct GlPixelFormatDesc *format_desc;
1361 TRACE("(%p) : Created Additional Swap Chain\n", This);
1363 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1364 * does a device hold a reference to a swap chain giving them a lifetime of the device
1365 * or does the swap chain notify the device of its destruction.
1366 *******************************/
1368 /* Check the params */
1369 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1370 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1371 return WINED3DERR_INVALIDCALL;
1372 } else if (pPresentationParameters->BackBufferCount > 1) {
1373 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");
1376 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1379 ERR("Out of memory\n");
1380 *ppSwapChain = NULL;
1381 return WINED3DERR_OUTOFVIDEOMEMORY;
1384 switch(surface_type) {
1386 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1388 case SURFACE_OPENGL:
1389 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1391 case SURFACE_UNKNOWN:
1392 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1393 HeapFree(GetProcessHeap(), 0, object);
1394 return WINED3DERR_INVALIDCALL;
1396 object->wineD3DDevice = This;
1397 object->parent = parent;
1400 *ppSwapChain = (IWineD3DSwapChain *)object;
1402 /*********************
1403 * Lookup the window Handle and the relating X window handle
1404 ********************/
1406 /* Setup hwnd we are using, plus which display this equates to */
1407 object->win_handle = pPresentationParameters->hDeviceWindow;
1408 if (!object->win_handle) {
1409 object->win_handle = This->createParms.hFocusWindow;
1411 if(!pPresentationParameters->Windowed && object->win_handle) {
1412 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1413 pPresentationParameters->BackBufferWidth,
1414 pPresentationParameters->BackBufferHeight);
1417 hDc = GetDC(object->win_handle);
1418 TRACE("Using hDc %p\n", hDc);
1421 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1422 return WINED3DERR_NOTAVAILABLE;
1425 /* Get info on the current display setup */
1426 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1427 object->orig_width = Mode.Width;
1428 object->orig_height = Mode.Height;
1429 object->orig_fmt = Mode.Format;
1430 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1432 if (pPresentationParameters->Windowed &&
1433 ((pPresentationParameters->BackBufferWidth == 0) ||
1434 (pPresentationParameters->BackBufferHeight == 0) ||
1435 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1438 GetClientRect(object->win_handle, &Rect);
1440 if (pPresentationParameters->BackBufferWidth == 0) {
1441 pPresentationParameters->BackBufferWidth = Rect.right;
1442 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1444 if (pPresentationParameters->BackBufferHeight == 0) {
1445 pPresentationParameters->BackBufferHeight = Rect.bottom;
1446 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1448 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1449 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1450 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1454 /* Put the correct figures in the presentation parameters */
1455 TRACE("Copying across presentation parameters\n");
1456 object->presentParms = *pPresentationParameters;
1458 TRACE("calling rendertarget CB\n");
1459 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1460 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1461 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1462 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1463 if (SUCCEEDED(hr)) {
1464 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1465 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1466 if(surface_type == SURFACE_OPENGL) {
1467 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1470 ERR("Failed to create the front buffer\n");
1474 /*********************
1475 * Windowed / Fullscreen
1476 *******************/
1479 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1480 * so we should really check to see if there is a fullscreen swapchain already
1481 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1482 **************************************/
1484 if (!pPresentationParameters->Windowed) {
1485 WINED3DDISPLAYMODE mode;
1488 /* Change the display settings */
1489 mode.Width = pPresentationParameters->BackBufferWidth;
1490 mode.Height = pPresentationParameters->BackBufferHeight;
1491 mode.Format = pPresentationParameters->BackBufferFormat;
1492 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1494 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1495 displaymode_set = TRUE;
1499 * Create an opengl context for the display visual
1500 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1501 * use different properties after that point in time. FIXME: How to handle when requested format
1502 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1503 * it chooses is identical to the one already being used!
1504 **********************************/
1505 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1507 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1508 if(!object->context) {
1509 ERR("Failed to create the context array\n");
1513 object->num_contexts = 1;
1515 if(surface_type == SURFACE_OPENGL) {
1516 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1517 if (!object->context[0]) {
1518 ERR("Failed to create a new context\n");
1519 hr = WINED3DERR_NOTAVAILABLE;
1522 TRACE("Context created (HWND=%p, glContext=%p)\n",
1523 object->win_handle, object->context[0]->glCtx);
1527 /*********************
1528 * Create the back, front and stencil buffers
1529 *******************/
1530 if(object->presentParms.BackBufferCount > 0) {
1533 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1534 if(!object->backBuffer) {
1535 ERR("Out of memory\n");
1540 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1541 TRACE("calling rendertarget CB\n");
1542 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1543 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1544 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1545 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1547 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1548 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1550 ERR("Cannot create new back buffer\n");
1553 if(surface_type == SURFACE_OPENGL) {
1555 glDrawBuffer(GL_BACK);
1556 checkGLcall("glDrawBuffer(GL_BACK)");
1561 object->backBuffer = NULL;
1563 /* Single buffering - draw to front buffer */
1564 if(surface_type == SURFACE_OPENGL) {
1566 glDrawBuffer(GL_FRONT);
1567 checkGLcall("glDrawBuffer(GL_FRONT)");
1572 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1573 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1574 TRACE("Creating depth stencil buffer\n");
1575 if (This->auto_depth_stencil_buffer == NULL ) {
1576 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1577 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1578 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1579 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1580 &This->auto_depth_stencil_buffer);
1581 if (SUCCEEDED(hr)) {
1582 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1584 ERR("Failed to create the auto depth stencil\n");
1590 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1592 TRACE("Created swapchain %p\n", object);
1593 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1597 if (displaymode_set) {
1601 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1604 /* Change the display settings */
1605 memset(&devmode, 0, sizeof(devmode));
1606 devmode.dmSize = sizeof(devmode);
1607 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1608 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1609 devmode.dmPelsWidth = object->orig_width;
1610 devmode.dmPelsHeight = object->orig_height;
1611 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1614 if (object->backBuffer) {
1616 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1617 if(object->backBuffer[i]) {
1618 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1619 IUnknown_Release(bufferParent); /* once for the get parent */
1620 if (IUnknown_Release(bufferParent) > 0) {
1621 FIXME("(%p) Something's still holding the back buffer\n",This);
1625 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1626 object->backBuffer = NULL;
1628 if(object->context && object->context[0])
1629 DestroyContext(This, object->context[0]);
1630 if(object->frontBuffer) {
1631 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1632 IUnknown_Release(bufferParent); /* once for the get parent */
1633 if (IUnknown_Release(bufferParent) > 0) {
1634 FIXME("(%p) Something's still holding the front buffer\n",This);
1637 HeapFree(GetProcessHeap(), 0, object);
1641 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1642 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1644 TRACE("(%p)\n", This);
1646 return This->NumberOfSwapChains;
1649 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1651 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1653 if(iSwapChain < This->NumberOfSwapChains) {
1654 *pSwapChain = This->swapchains[iSwapChain];
1655 IWineD3DSwapChain_AddRef(*pSwapChain);
1656 TRACE("(%p) returning %p\n", This, *pSwapChain);
1659 TRACE("Swapchain out of range\n");
1661 return WINED3DERR_INVALIDCALL;
1666 * Vertex Declaration
1668 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1669 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1670 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1671 IWineD3DVertexDeclarationImpl *object = NULL;
1672 HRESULT hr = WINED3D_OK;
1674 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1675 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1677 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1680 ERR("Out of memory\n");
1681 *ppVertexDeclaration = NULL;
1682 return WINED3DERR_OUTOFVIDEOMEMORY;
1685 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
1686 object->wineD3DDevice = This;
1687 object->parent = parent;
1690 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1692 hr = vertexdeclaration_init(object, elements, element_count);
1695 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1696 *ppVertexDeclaration = NULL;
1702 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1703 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1705 unsigned int idx, idx2;
1706 unsigned int offset;
1707 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1708 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1709 BOOL has_blend_idx = has_blend &&
1710 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1711 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1712 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1713 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1714 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1715 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1716 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1718 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1719 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1720 WINED3DVERTEXELEMENT *elements = NULL;
1723 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1724 if (has_blend_idx) num_blends--;
1726 /* Compute declaration size */
1727 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1728 has_psize + has_diffuse + has_specular + num_textures;
1730 /* convert the declaration */
1731 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1732 if (!elements) return ~0U;
1736 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1737 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1738 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1740 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1741 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1742 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1745 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1746 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1748 elements[idx].usage_idx = 0;
1751 if (has_blend && (num_blends > 0)) {
1752 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1753 elements[idx].format = WINED3DFMT_A8R8G8B8;
1755 switch(num_blends) {
1756 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1757 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1758 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1759 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1761 ERR("Unexpected amount of blend values: %u\n", num_blends);
1764 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1765 elements[idx].usage_idx = 0;
1768 if (has_blend_idx) {
1769 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1770 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1771 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1772 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1773 elements[idx].format = WINED3DFMT_A8R8G8B8;
1775 elements[idx].format = WINED3DFMT_R32_FLOAT;
1776 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1777 elements[idx].usage_idx = 0;
1781 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1782 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1783 elements[idx].usage_idx = 0;
1787 elements[idx].format = WINED3DFMT_R32_FLOAT;
1788 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1789 elements[idx].usage_idx = 0;
1793 elements[idx].format = WINED3DFMT_A8R8G8B8;
1794 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1795 elements[idx].usage_idx = 0;
1799 elements[idx].format = WINED3DFMT_A8R8G8B8;
1800 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1801 elements[idx].usage_idx = 1;
1804 for (idx2 = 0; idx2 < num_textures; idx2++) {
1805 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1806 switch (numcoords) {
1807 case WINED3DFVF_TEXTUREFORMAT1:
1808 elements[idx].format = WINED3DFMT_R32_FLOAT;
1810 case WINED3DFVF_TEXTUREFORMAT2:
1811 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1813 case WINED3DFVF_TEXTUREFORMAT3:
1814 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1816 case WINED3DFVF_TEXTUREFORMAT4:
1817 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1820 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1821 elements[idx].usage_idx = idx2;
1825 /* Now compute offsets, and initialize the rest of the fields */
1826 for (idx = 0, offset = 0; idx < size; ++idx)
1828 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1829 elements[idx].input_slot = 0;
1830 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1831 elements[idx].offset = offset;
1832 offset += format_desc->component_count * format_desc->component_size;
1835 *ppVertexElements = elements;
1839 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1840 WINED3DVERTEXELEMENT* elements = NULL;
1841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1845 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1846 if (size == ~0U) return WINED3DERR_OUTOFVIDEOMEMORY;
1848 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1849 HeapFree(GetProcessHeap(), 0, elements);
1850 if (hr != S_OK) return hr;
1855 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1856 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1857 IWineD3DVertexShader **ppVertexShader, IUnknown *parent)
1859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1860 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1861 HRESULT hr = WINED3D_OK;
1863 if (!pFunction) return WINED3DERR_INVALIDCALL;
1865 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1868 ERR("Out of memory\n");
1869 *ppVertexShader = NULL;
1870 return WINED3DERR_OUTOFVIDEOMEMORY;
1873 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
1874 object->parent = parent;
1875 shader_init(&object->baseShader, iface);
1876 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1877 *ppVertexShader = (IWineD3DVertexShader *)object;
1879 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
1881 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction, output_signature);
1884 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
1885 IWineD3DVertexShader_Release(*ppVertexShader);
1886 *ppVertexShader = NULL;
1893 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1894 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1895 IWineD3DPixelShader **ppPixelShader, IUnknown *parent)
1897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1898 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1899 HRESULT hr = WINED3D_OK;
1901 if (!pFunction) return WINED3DERR_INVALIDCALL;
1903 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1906 ERR("Out of memory\n");
1907 *ppPixelShader = NULL;
1908 return WINED3DERR_OUTOFVIDEOMEMORY;
1911 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
1912 object->parent = parent;
1913 shader_init(&object->baseShader, iface);
1914 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1915 *ppPixelShader = (IWineD3DPixelShader *)object;
1917 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
1919 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction, output_signature);
1922 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
1923 IWineD3DPixelShader_Release(*ppPixelShader);
1924 *ppPixelShader = NULL;
1931 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1932 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1935 IWineD3DPaletteImpl *object;
1937 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1939 /* Create the new object */
1940 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1942 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1943 return E_OUTOFMEMORY;
1946 object->lpVtbl = &IWineD3DPalette_Vtbl;
1948 object->Flags = Flags;
1949 object->parent = Parent;
1950 object->wineD3DDevice = This;
1951 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1952 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1955 HeapFree( GetProcessHeap(), 0, object);
1956 return E_OUTOFMEMORY;
1959 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1961 IWineD3DPalette_Release((IWineD3DPalette *) object);
1965 *Palette = (IWineD3DPalette *) object;
1970 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1974 HDC dcb = NULL, dcs = NULL;
1975 WINEDDCOLORKEY colorkey;
1977 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1980 GetObjectA(hbm, sizeof(BITMAP), &bm);
1981 dcb = CreateCompatibleDC(NULL);
1983 SelectObject(dcb, hbm);
1987 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1988 * couldn't be loaded
1990 memset(&bm, 0, sizeof(bm));
1995 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5, TRUE,
1996 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL);
1998 ERR("Wine logo requested, but failed to create surface\n");
2003 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2004 if(FAILED(hr)) goto out;
2005 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2006 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2008 colorkey.dwColorSpaceLowValue = 0;
2009 colorkey.dwColorSpaceHighValue = 0;
2010 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2012 /* Fill the surface with a white color to show that wined3d is there */
2013 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2026 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2028 /* Under DirectX you can have texture stage operations even if no texture is
2029 bound, whereas opengl will only do texture operations when a valid texture is
2030 bound. We emulate this by creating dummy textures and binding them to each
2031 texture stage, but disable all stages by default. Hence if a stage is enabled
2032 then the default texture will kick in until replaced by a SetTexture call */
2035 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2036 /* The dummy texture does not have client storage backing */
2037 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2038 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2040 for (i = 0; i < GL_LIMITS(textures); i++) {
2041 GLubyte white = 255;
2043 /* Make appropriate texture active */
2044 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2045 checkGLcall("glActiveTextureARB");
2047 /* Generate an opengl texture name */
2048 glGenTextures(1, &This->dummyTextureName[i]);
2049 checkGLcall("glGenTextures");
2050 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2052 /* Generate a dummy 2d texture (not using 1d because they cause many
2053 * DRI drivers fall back to sw) */
2054 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2055 checkGLcall("glBindTexture");
2057 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2058 checkGLcall("glTexImage2D");
2060 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2061 /* Reenable because if supported it is enabled by default */
2062 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2063 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2069 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2070 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2072 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2073 IWineD3DSwapChainImpl *swapchain = NULL;
2078 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2080 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2081 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2083 /* TODO: Test if OpenGL is compiled in and loaded */
2085 TRACE("(%p) : Creating stateblock\n", This);
2086 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2087 hr = IWineD3DDevice_CreateStateBlock(iface,
2089 (IWineD3DStateBlock **)&This->stateBlock,
2091 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2092 WARN("Failed to create stateblock\n");
2095 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2096 This->updateStateBlock = This->stateBlock;
2097 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2099 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2100 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2102 This->NumberOfPalettes = 1;
2103 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2104 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2105 ERR("Out of memory!\n");
2108 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2109 if(!This->palettes[0]) {
2110 ERR("Out of memory!\n");
2113 for (i = 0; i < 256; ++i) {
2114 This->palettes[0][i].peRed = 0xFF;
2115 This->palettes[0][i].peGreen = 0xFF;
2116 This->palettes[0][i].peBlue = 0xFF;
2117 This->palettes[0][i].peFlags = 0xFF;
2119 This->currentPalette = 0;
2121 /* Initialize the texture unit mapping to a 1:1 mapping */
2122 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2123 if (state < GL_LIMITS(fragment_samplers)) {
2124 This->texUnitMap[state] = state;
2125 This->rev_tex_unit_map[state] = state;
2127 This->texUnitMap[state] = -1;
2128 This->rev_tex_unit_map[state] = -1;
2132 /* Setup the implicit swapchain */
2133 TRACE("Creating implicit swapchain\n");
2134 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2135 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2138 WARN("Failed to create implicit swapchain\n");
2142 This->NumberOfSwapChains = 1;
2143 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2144 if(!This->swapchains) {
2145 ERR("Out of memory!\n");
2148 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2150 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2151 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2152 This->render_targets[0] = swapchain->backBuffer[0];
2153 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2156 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2157 This->render_targets[0] = swapchain->frontBuffer;
2158 This->lastActiveRenderTarget = swapchain->frontBuffer;
2160 IWineD3DSurface_AddRef(This->render_targets[0]);
2161 This->activeContext = swapchain->context[0];
2162 This->lastThread = GetCurrentThreadId();
2164 /* Depth Stencil support */
2165 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2166 if (NULL != This->stencilBufferTarget) {
2167 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2170 hr = This->shader_backend->shader_alloc_private(iface);
2172 TRACE("Shader private data couldn't be allocated\n");
2175 hr = This->frag_pipe->alloc_private(iface);
2177 TRACE("Fragment pipeline private data couldn't be allocated\n");
2180 hr = This->blitter->alloc_private(iface);
2182 TRACE("Blitter private data couldn't be allocated\n");
2186 /* Set up some starting GL setup */
2188 /* Setup all the devices defaults */
2189 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2190 create_dummy_textures(This);
2194 /* Initialize the current view state */
2195 This->view_ident = 1;
2196 This->contexts[0]->last_was_rhw = 0;
2197 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2198 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2200 switch(wined3d_settings.offscreen_rendering_mode) {
2203 This->offscreenBuffer = GL_BACK;
2206 case ORM_BACKBUFFER:
2208 if(This->activeContext->aux_buffers > 0) {
2209 TRACE("Using auxilliary buffer for offscreen rendering\n");
2210 This->offscreenBuffer = GL_AUX0;
2212 TRACE("Using back buffer for offscreen rendering\n");
2213 This->offscreenBuffer = GL_BACK;
2218 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2221 /* Clear the screen */
2222 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2223 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2226 This->d3d_initialized = TRUE;
2228 if(wined3d_settings.logo) {
2229 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2231 This->highest_dirty_ps_const = 0;
2232 This->highest_dirty_vs_const = 0;
2236 HeapFree(GetProcessHeap(), 0, This->render_targets);
2237 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2238 HeapFree(GetProcessHeap(), 0, This->swapchains);
2239 This->NumberOfSwapChains = 0;
2240 if(This->palettes) {
2241 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2242 HeapFree(GetProcessHeap(), 0, This->palettes);
2244 This->NumberOfPalettes = 0;
2246 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2248 if(This->stateBlock) {
2249 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2250 This->stateBlock = NULL;
2252 if (This->blit_priv) {
2253 This->blitter->free_private(iface);
2255 if (This->fragment_priv) {
2256 This->frag_pipe->free_private(iface);
2258 if (This->shader_priv) {
2259 This->shader_backend->shader_free_private(iface);
2264 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2265 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2268 IWineD3DSwapChainImpl *swapchain = NULL;
2271 /* Setup the implicit swapchain */
2272 TRACE("Creating implicit swapchain\n");
2273 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2274 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2277 WARN("Failed to create implicit swapchain\n");
2281 This->NumberOfSwapChains = 1;
2282 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2283 if(!This->swapchains) {
2284 ERR("Out of memory!\n");
2287 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2291 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2295 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2297 IWineD3DResource_UnLoad(resource);
2298 IWineD3DResource_Release(resource);
2302 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2306 TRACE("(%p)\n", This);
2308 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2310 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2311 * it was created. Thus make sure a context is active for the glDelete* calls
2313 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2315 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2317 /* Unload resources */
2318 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2320 TRACE("Deleting high order patches\n");
2321 for(i = 0; i < PATCHMAP_SIZE; i++) {
2322 struct list *e1, *e2;
2323 struct WineD3DRectPatch *patch;
2324 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2325 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2326 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2330 /* Delete the palette conversion shader if it is around */
2331 if(This->paletteConversionShader) {
2333 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2335 This->paletteConversionShader = 0;
2338 /* Delete the pbuffer context if there is any */
2339 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2341 /* Delete the mouse cursor texture */
2342 if(This->cursorTexture) {
2344 glDeleteTextures(1, &This->cursorTexture);
2346 This->cursorTexture = 0;
2349 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2350 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2352 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2353 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2356 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2357 * private data, it might contain opengl pointers
2359 if(This->depth_blt_texture) {
2361 glDeleteTextures(1, &This->depth_blt_texture);
2363 This->depth_blt_texture = 0;
2365 if (This->depth_blt_rb) {
2367 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2369 This->depth_blt_rb = 0;
2370 This->depth_blt_rb_w = 0;
2371 This->depth_blt_rb_h = 0;
2374 /* Release the update stateblock */
2375 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2376 if(This->updateStateBlock != This->stateBlock)
2377 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2379 This->updateStateBlock = NULL;
2381 { /* because were not doing proper internal refcounts releasing the primary state block
2382 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2383 to set this->stateBlock = NULL; first */
2384 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2385 This->stateBlock = NULL;
2387 /* Release the stateblock */
2388 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2389 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2393 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2394 This->blitter->free_private(iface);
2395 This->frag_pipe->free_private(iface);
2396 This->shader_backend->shader_free_private(iface);
2398 /* Release the buffers (with sanity checks)*/
2399 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2400 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2401 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2402 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2404 This->stencilBufferTarget = NULL;
2406 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2407 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2408 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2410 TRACE("Setting rendertarget to NULL\n");
2411 This->render_targets[0] = NULL;
2413 if (This->auto_depth_stencil_buffer) {
2414 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2415 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2417 This->auto_depth_stencil_buffer = NULL;
2420 for(i=0; i < This->NumberOfSwapChains; i++) {
2421 TRACE("Releasing the implicit swapchain %d\n", i);
2422 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2423 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2427 HeapFree(GetProcessHeap(), 0, This->swapchains);
2428 This->swapchains = NULL;
2429 This->NumberOfSwapChains = 0;
2431 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2432 HeapFree(GetProcessHeap(), 0, This->palettes);
2433 This->palettes = NULL;
2434 This->NumberOfPalettes = 0;
2436 HeapFree(GetProcessHeap(), 0, This->render_targets);
2437 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2438 This->render_targets = NULL;
2439 This->draw_buffers = NULL;
2441 This->d3d_initialized = FALSE;
2445 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2446 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2449 for(i=0; i < This->NumberOfSwapChains; i++) {
2450 TRACE("Releasing the implicit swapchain %d\n", i);
2451 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2452 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2456 HeapFree(GetProcessHeap(), 0, This->swapchains);
2457 This->swapchains = NULL;
2458 This->NumberOfSwapChains = 0;
2462 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2463 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2464 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2466 * There is no way to deactivate thread safety once it is enabled.
2468 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2471 /*For now just store the flag(needed in case of ddraw) */
2472 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2477 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2478 const WINED3DDISPLAYMODE* pMode) {
2480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2482 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2485 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2487 /* Resize the screen even without a window:
2488 * The app could have unset it with SetCooperativeLevel, but not called
2489 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2490 * but we don't have any hwnd
2493 memset(&devmode, 0, sizeof(devmode));
2494 devmode.dmSize = sizeof(devmode);
2495 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2496 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2497 devmode.dmPelsWidth = pMode->Width;
2498 devmode.dmPelsHeight = pMode->Height;
2500 devmode.dmDisplayFrequency = pMode->RefreshRate;
2501 if (pMode->RefreshRate != 0) {
2502 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2505 /* Only change the mode if necessary */
2506 if( (This->ddraw_width == pMode->Width) &&
2507 (This->ddraw_height == pMode->Height) &&
2508 (This->ddraw_format == pMode->Format) &&
2509 (pMode->RefreshRate == 0) ) {
2513 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2514 if (ret != DISP_CHANGE_SUCCESSFUL) {
2515 if(devmode.dmDisplayFrequency != 0) {
2516 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2517 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2518 devmode.dmDisplayFrequency = 0;
2519 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2521 if(ret != DISP_CHANGE_SUCCESSFUL) {
2522 return WINED3DERR_NOTAVAILABLE;
2526 /* Store the new values */
2527 This->ddraw_width = pMode->Width;
2528 This->ddraw_height = pMode->Height;
2529 This->ddraw_format = pMode->Format;
2531 /* And finally clip mouse to our screen */
2532 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2533 ClipCursor(&clip_rc);
2538 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2540 *ppD3D= This->wineD3D;
2541 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2542 IWineD3D_AddRef(*ppD3D);
2546 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2549 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2550 (This->adapter->TextureRam/(1024*1024)),
2551 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2552 /* return simulated texture memory left */
2553 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2557 * Get / Set Stream Source
2559 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2560 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2563 IWineD3DBuffer *oldSrc;
2565 if (StreamNumber >= MAX_STREAMS) {
2566 WARN("Stream out of range %d\n", StreamNumber);
2567 return WINED3DERR_INVALIDCALL;
2568 } else if(OffsetInBytes & 0x3) {
2569 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2570 return WINED3DERR_INVALIDCALL;
2573 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2574 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2576 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2578 if(oldSrc == pStreamData &&
2579 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2580 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2581 TRACE("Application is setting the old values over, nothing to do\n");
2585 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2587 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2588 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2591 /* Handle recording of state blocks */
2592 if (This->isRecordingState) {
2593 TRACE("Recording... not performing anything\n");
2594 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2595 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2599 if (pStreamData != NULL) {
2600 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2601 IWineD3DBuffer_AddRef(pStreamData);
2603 if (oldSrc != NULL) {
2604 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2605 IWineD3DBuffer_Release(oldSrc);
2608 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2613 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2614 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2618 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2619 This->stateBlock->streamSource[StreamNumber],
2620 This->stateBlock->streamOffset[StreamNumber],
2621 This->stateBlock->streamStride[StreamNumber]);
2623 if (StreamNumber >= MAX_STREAMS) {
2624 WARN("Stream out of range %d\n", StreamNumber);
2625 return WINED3DERR_INVALIDCALL;
2627 *pStream = This->stateBlock->streamSource[StreamNumber];
2628 *pStride = This->stateBlock->streamStride[StreamNumber];
2630 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2633 if (*pStream != NULL) {
2634 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2639 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2641 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2642 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2644 /* Verify input at least in d3d9 this is invalid*/
2645 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2646 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2647 return WINED3DERR_INVALIDCALL;
2649 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2650 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2651 return WINED3DERR_INVALIDCALL;
2654 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2655 return WINED3DERR_INVALIDCALL;
2658 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2659 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2661 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2662 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2664 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2665 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2666 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2672 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2675 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2676 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2678 TRACE("(%p) : returning %d\n", This, *Divider);
2684 * Get / Set & Multiply Transform
2686 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2689 /* Most of this routine, comments included copied from ddraw tree initially: */
2690 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2692 /* Handle recording of state blocks */
2693 if (This->isRecordingState) {
2694 TRACE("Recording... not performing anything\n");
2695 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2696 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2701 * If the new matrix is the same as the current one,
2702 * we cut off any further processing. this seems to be a reasonable
2703 * optimization because as was noticed, some apps (warcraft3 for example)
2704 * tend towards setting the same matrix repeatedly for some reason.
2706 * From here on we assume that the new matrix is different, wherever it matters.
2708 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2709 TRACE("The app is setting the same matrix over again\n");
2712 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2716 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2717 where ViewMat = Camera space, WorldMat = world space.
2719 In OpenGL, camera and world space is combined into GL_MODELVIEW
2720 matrix. The Projection matrix stay projection matrix.
2723 /* Capture the times we can just ignore the change for now */
2724 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2725 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2726 /* Handled by the state manager */
2729 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2733 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2735 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2736 *pMatrix = This->stateBlock->transforms[State];
2740 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2741 const WINED3DMATRIX *mat = NULL;
2744 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2745 * below means it will be recorded in a state block change, but it
2746 * works regardless where it is recorded.
2747 * If this is found to be wrong, change to StateBlock.
2749 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2750 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2752 if (State <= HIGHEST_TRANSFORMSTATE)
2754 mat = &This->updateStateBlock->transforms[State];
2756 FIXME("Unhandled transform state!!\n");
2759 multiply_matrix(&temp, mat, pMatrix);
2761 /* Apply change via set transform - will reapply to eg. lights this way */
2762 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2768 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2769 you can reference any indexes you want as long as that number max are enabled at any
2770 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2771 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2772 but when recording, just build a chain pretty much of commands to be replayed. */
2774 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2776 PLIGHTINFOEL *object = NULL;
2777 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2781 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2783 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2787 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2788 return WINED3DERR_INVALIDCALL;
2791 switch(pLight->Type) {
2792 case WINED3DLIGHT_POINT:
2793 case WINED3DLIGHT_SPOT:
2794 case WINED3DLIGHT_PARALLELPOINT:
2795 case WINED3DLIGHT_GLSPOT:
2796 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2799 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2800 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2801 return WINED3DERR_INVALIDCALL;
2805 case WINED3DLIGHT_DIRECTIONAL:
2806 /* Ignores attenuation */
2810 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2811 return WINED3DERR_INVALIDCALL;
2814 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2815 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2816 if(object->OriginalIndex == Index) break;
2821 TRACE("Adding new light\n");
2822 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2824 ERR("Out of memory error when allocating a light\n");
2825 return E_OUTOFMEMORY;
2827 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2828 object->glIndex = -1;
2829 object->OriginalIndex = Index;
2830 object->changed = TRUE;
2833 /* Initialize the object */
2834 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,
2835 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2836 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2837 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2838 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2839 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2840 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2842 /* Save away the information */
2843 object->OriginalParms = *pLight;
2845 switch (pLight->Type) {
2846 case WINED3DLIGHT_POINT:
2848 object->lightPosn[0] = pLight->Position.x;
2849 object->lightPosn[1] = pLight->Position.y;
2850 object->lightPosn[2] = pLight->Position.z;
2851 object->lightPosn[3] = 1.0f;
2852 object->cutoff = 180.0f;
2856 case WINED3DLIGHT_DIRECTIONAL:
2858 object->lightPosn[0] = -pLight->Direction.x;
2859 object->lightPosn[1] = -pLight->Direction.y;
2860 object->lightPosn[2] = -pLight->Direction.z;
2861 object->lightPosn[3] = 0.0;
2862 object->exponent = 0.0f;
2863 object->cutoff = 180.0f;
2866 case WINED3DLIGHT_SPOT:
2868 object->lightPosn[0] = pLight->Position.x;
2869 object->lightPosn[1] = pLight->Position.y;
2870 object->lightPosn[2] = pLight->Position.z;
2871 object->lightPosn[3] = 1.0;
2874 object->lightDirn[0] = pLight->Direction.x;
2875 object->lightDirn[1] = pLight->Direction.y;
2876 object->lightDirn[2] = pLight->Direction.z;
2877 object->lightDirn[3] = 1.0;
2880 * opengl-ish and d3d-ish spot lights use too different models for the
2881 * light "intensity" as a function of the angle towards the main light direction,
2882 * so we only can approximate very roughly.
2883 * however spot lights are rather rarely used in games (if ever used at all).
2884 * furthermore if still used, probably nobody pays attention to such details.
2886 if (pLight->Falloff == 0) {
2887 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2888 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2889 * will always be 1.0 for both of them, and we don't have to care for the
2890 * rest of the rather complex calculation
2892 object->exponent = 0;
2894 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2895 if (rho < 0.0001) rho = 0.0001f;
2896 object->exponent = -0.3/log(cos(rho/2));
2898 if (object->exponent > 128.0) {
2899 object->exponent = 128.0;
2901 object->cutoff = pLight->Phi*90/M_PI;
2907 FIXME("Unrecognized light type %d\n", pLight->Type);
2910 /* Update the live definitions if the light is currently assigned a glIndex */
2911 if (object->glIndex != -1 && !This->isRecordingState) {
2912 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2917 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2918 PLIGHTINFOEL *lightInfo = NULL;
2919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2920 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2922 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2924 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2925 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2926 if(lightInfo->OriginalIndex == Index) break;
2930 if (lightInfo == NULL) {
2931 TRACE("Light information requested but light not defined\n");
2932 return WINED3DERR_INVALIDCALL;
2935 *pLight = lightInfo->OriginalParms;
2940 * Get / Set Light Enable
2941 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2943 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2944 PLIGHTINFOEL *lightInfo = NULL;
2945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2946 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2948 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2950 /* Tests show true = 128...not clear why */
2951 Enable = Enable? 128: 0;
2953 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2954 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2955 if(lightInfo->OriginalIndex == Index) break;
2958 TRACE("Found light: %p\n", lightInfo);
2960 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2961 if (lightInfo == NULL) {
2963 TRACE("Light enabled requested but light not defined, so defining one!\n");
2964 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2966 /* Search for it again! Should be fairly quick as near head of list */
2967 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2968 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2969 if(lightInfo->OriginalIndex == Index) break;
2972 if (lightInfo == NULL) {
2973 FIXME("Adding default lights has failed dismally\n");
2974 return WINED3DERR_INVALIDCALL;
2978 lightInfo->enabledChanged = TRUE;
2980 if(lightInfo->glIndex != -1) {
2981 if(!This->isRecordingState) {
2982 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2985 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2986 lightInfo->glIndex = -1;
2988 TRACE("Light already disabled, nothing to do\n");
2990 lightInfo->enabled = FALSE;
2992 lightInfo->enabled = TRUE;
2993 if (lightInfo->glIndex != -1) {
2995 TRACE("Nothing to do as light was enabled\n");
2998 /* Find a free gl light */
2999 for(i = 0; i < This->maxConcurrentLights; i++) {
3000 if(This->updateStateBlock->activeLights[i] == NULL) {
3001 This->updateStateBlock->activeLights[i] = lightInfo;
3002 lightInfo->glIndex = i;
3006 if(lightInfo->glIndex == -1) {
3007 /* Our tests show that Windows returns D3D_OK in this situation, even with
3008 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3009 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3010 * as well for those lights.
3012 * TODO: Test how this affects rendering
3014 WARN("Too many concurrently active lights\n");
3018 /* i == lightInfo->glIndex */
3019 if(!This->isRecordingState) {
3020 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3028 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3030 PLIGHTINFOEL *lightInfo = NULL;
3031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3033 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3034 TRACE("(%p) : for idx(%d)\n", This, Index);
3036 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3037 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3038 if(lightInfo->OriginalIndex == Index) break;
3042 if (lightInfo == NULL) {
3043 TRACE("Light enabled state requested but light not defined\n");
3044 return WINED3DERR_INVALIDCALL;
3046 /* true is 128 according to SetLightEnable */
3047 *pEnable = lightInfo->enabled ? 128 : 0;
3052 * Get / Set Clip Planes
3054 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3056 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3058 /* Validate Index */
3059 if (Index >= GL_LIMITS(clipplanes)) {
3060 TRACE("Application has requested clipplane this device doesn't support\n");
3061 return WINED3DERR_INVALIDCALL;
3064 This->updateStateBlock->changed.clipplane |= 1 << Index;
3066 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3067 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3068 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3069 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3070 TRACE("Application is setting old values over, nothing to do\n");
3074 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3075 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3076 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3077 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3079 /* Handle recording of state blocks */
3080 if (This->isRecordingState) {
3081 TRACE("Recording... not performing anything\n");
3085 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3090 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3092 TRACE("(%p) : for idx %d\n", This, Index);
3094 /* Validate Index */
3095 if (Index >= GL_LIMITS(clipplanes)) {
3096 TRACE("Application has requested clipplane this device doesn't support\n");
3097 return WINED3DERR_INVALIDCALL;
3100 pPlane[0] = This->stateBlock->clipplane[Index][0];
3101 pPlane[1] = This->stateBlock->clipplane[Index][1];
3102 pPlane[2] = This->stateBlock->clipplane[Index][2];
3103 pPlane[3] = This->stateBlock->clipplane[Index][3];
3108 * Get / Set Clip Plane Status
3109 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3111 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3113 FIXME("(%p) : stub\n", This);
3114 if (NULL == pClipStatus) {
3115 return WINED3DERR_INVALIDCALL;
3117 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3118 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3122 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3124 FIXME("(%p) : stub\n", This);
3125 if (NULL == pClipStatus) {
3126 return WINED3DERR_INVALIDCALL;
3128 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3129 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3134 * Get / Set Material
3136 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3139 This->updateStateBlock->changed.material = TRUE;
3140 This->updateStateBlock->material = *pMaterial;
3142 /* Handle recording of state blocks */
3143 if (This->isRecordingState) {
3144 TRACE("Recording... not performing anything\n");
3148 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3152 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3154 *pMaterial = This->updateStateBlock->material;
3155 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3156 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3157 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3158 pMaterial->Ambient.b, pMaterial->Ambient.a);
3159 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3160 pMaterial->Specular.b, pMaterial->Specular.a);
3161 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3162 pMaterial->Emissive.b, pMaterial->Emissive.a);
3163 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3171 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DBuffer* pIndexData, WINED3DFORMAT fmt) {
3172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3173 IWineD3DBuffer *oldIdxs;
3175 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3176 oldIdxs = This->updateStateBlock->pIndexData;
3178 This->updateStateBlock->changed.indices = TRUE;
3179 This->updateStateBlock->pIndexData = pIndexData;
3180 This->updateStateBlock->IndexFmt = fmt;
3182 /* Handle recording of state blocks */
3183 if (This->isRecordingState) {
3184 TRACE("Recording... not performing anything\n");
3185 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3186 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3190 if(oldIdxs != pIndexData) {
3191 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3193 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3194 IWineD3DBuffer_AddRef(pIndexData);
3197 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3198 IWineD3DBuffer_Release(oldIdxs);
3205 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DBuffer** ppIndexData) {
3206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3208 *ppIndexData = This->stateBlock->pIndexData;
3210 /* up ref count on ppindexdata */
3212 IWineD3DBuffer_AddRef(*ppIndexData);
3213 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3215 TRACE("(%p) No index data set\n", This);
3217 TRACE("Returning %p\n", *ppIndexData);
3222 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3223 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3225 TRACE("(%p)->(%d)\n", This, BaseIndex);
3227 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3228 TRACE("Application is setting the old value over, nothing to do\n");
3232 This->updateStateBlock->baseVertexIndex = BaseIndex;
3234 if (This->isRecordingState) {
3235 TRACE("Recording... not performing anything\n");
3238 /* The base vertex index affects the stream sources */
3239 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3243 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3245 TRACE("(%p) : base_index %p\n", This, base_index);
3247 *base_index = This->stateBlock->baseVertexIndex;
3249 TRACE("Returning %u\n", *base_index);
3255 * Get / Set Viewports
3257 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3260 TRACE("(%p)\n", This);
3261 This->updateStateBlock->changed.viewport = TRUE;
3262 This->updateStateBlock->viewport = *pViewport;
3264 /* Handle recording of state blocks */
3265 if (This->isRecordingState) {
3266 TRACE("Recording... not performing anything\n");
3270 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3271 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3273 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3278 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3280 TRACE("(%p)\n", This);
3281 *pViewport = This->stateBlock->viewport;
3286 * Get / Set Render States
3287 * TODO: Verify against dx9 definitions
3289 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3292 DWORD oldValue = This->stateBlock->renderState[State];
3294 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3296 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3297 This->updateStateBlock->renderState[State] = Value;
3299 /* Handle recording of state blocks */
3300 if (This->isRecordingState) {
3301 TRACE("Recording... not performing anything\n");
3305 /* Compared here and not before the assignment to allow proper stateblock recording */
3306 if(Value == oldValue) {
3307 TRACE("Application is setting the old value over, nothing to do\n");
3309 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3315 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3317 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3318 *pValue = This->stateBlock->renderState[State];
3323 * Get / Set Sampler States
3324 * TODO: Verify against dx9 definitions
3327 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3331 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3332 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3334 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3335 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3338 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3339 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3340 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3343 * SetSampler is designed to allow for more than the standard up to 8 textures
3344 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3345 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3347 * http://developer.nvidia.com/object/General_FAQ.html#t6
3349 * There are two new settings for GForce
3351 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3352 * and the texture one:
3353 * GL_MAX_TEXTURE_COORDS_ARB.
3354 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3357 oldValue = This->stateBlock->samplerState[Sampler][Type];
3358 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3359 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3361 /* Handle recording of state blocks */
3362 if (This->isRecordingState) {
3363 TRACE("Recording... not performing anything\n");
3367 if(oldValue == Value) {
3368 TRACE("Application is setting the old value over, nothing to do\n");
3372 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3377 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3380 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3381 This, Sampler, debug_d3dsamplerstate(Type), Type);
3383 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3384 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3387 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3388 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3389 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3391 *Value = This->stateBlock->samplerState[Sampler][Type];
3392 TRACE("(%p) : Returning %#x\n", This, *Value);
3397 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3400 This->updateStateBlock->changed.scissorRect = TRUE;
3401 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3402 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3405 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3407 if(This->isRecordingState) {
3408 TRACE("Recording... not performing anything\n");
3412 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3417 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3420 *pRect = This->updateStateBlock->scissorRect;
3421 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3425 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3427 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3429 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3431 This->updateStateBlock->vertexDecl = pDecl;
3432 This->updateStateBlock->changed.vertexDecl = TRUE;
3434 if (This->isRecordingState) {
3435 TRACE("Recording... not performing anything\n");
3437 } else if(pDecl == oldDecl) {
3438 /* Checked after the assignment to allow proper stateblock recording */
3439 TRACE("Application is setting the old declaration over, nothing to do\n");
3443 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3447 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3450 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3452 *ppDecl = This->stateBlock->vertexDecl;
3453 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3457 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3459 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3461 This->updateStateBlock->vertexShader = pShader;
3462 This->updateStateBlock->changed.vertexShader = TRUE;
3464 if (This->isRecordingState) {
3465 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3466 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3467 TRACE("Recording... not performing anything\n");
3469 } else if(oldShader == pShader) {
3470 /* Checked here to allow proper stateblock recording */
3471 TRACE("App is setting the old shader over, nothing to do\n");
3475 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3476 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3477 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3479 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3484 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3487 if (NULL == ppShader) {
3488 return WINED3DERR_INVALIDCALL;
3490 *ppShader = This->stateBlock->vertexShader;
3491 if( NULL != *ppShader)
3492 IWineD3DVertexShader_AddRef(*ppShader);
3494 TRACE("(%p) : returning %p\n", This, *ppShader);
3498 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3499 IWineD3DDevice *iface,
3501 CONST BOOL *srcData,
3504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3505 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3507 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3508 iface, srcData, start, count);
3510 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3512 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3513 for (i = 0; i < cnt; i++)
3514 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3516 for (i = start; i < cnt + start; ++i) {
3517 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3520 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3525 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3526 IWineD3DDevice *iface,
3531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3532 int cnt = min(count, MAX_CONST_B - start);
3534 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3535 iface, dstData, start, count);
3537 if (dstData == NULL || cnt < 0)
3538 return WINED3DERR_INVALIDCALL;
3540 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3544 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3545 IWineD3DDevice *iface,
3550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3551 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3553 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3554 iface, srcData, start, count);
3556 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3558 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3559 for (i = 0; i < cnt; i++)
3560 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3561 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3563 for (i = start; i < cnt + start; ++i) {
3564 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3567 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3572 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3573 IWineD3DDevice *iface,
3578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3579 int cnt = min(count, MAX_CONST_I - start);
3581 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3582 iface, dstData, start, count);
3584 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3585 return WINED3DERR_INVALIDCALL;
3587 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3591 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3592 IWineD3DDevice *iface,
3594 CONST float *srcData,
3597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3600 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3601 iface, srcData, start, count);
3603 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3604 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3605 return WINED3DERR_INVALIDCALL;
3607 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3609 for (i = 0; i < count; i++)
3610 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3611 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3614 if (!This->isRecordingState)
3616 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3617 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3620 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3621 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3626 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3627 IWineD3DDevice *iface,
3632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3633 int cnt = min(count, This->d3d_vshader_constantF - start);
3635 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3636 iface, dstData, start, count);
3638 if (dstData == NULL || cnt < 0)
3639 return WINED3DERR_INVALIDCALL;
3641 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3645 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3647 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3649 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3653 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3654 int i = This->rev_tex_unit_map[unit];
3655 int j = This->texUnitMap[stage];
3657 This->texUnitMap[stage] = unit;
3658 if (i != -1 && i != stage) {
3659 This->texUnitMap[i] = -1;
3662 This->rev_tex_unit_map[unit] = stage;
3663 if (j != -1 && j != unit) {
3664 This->rev_tex_unit_map[j] = -1;
3668 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3671 This->fixed_function_usage_map = 0;
3672 for (i = 0; i < MAX_TEXTURES; ++i) {
3673 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3674 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3675 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3676 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3677 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3678 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3679 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3680 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3682 if (color_op == WINED3DTOP_DISABLE) {
3683 /* Not used, and disable higher stages */
3687 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3688 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3689 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3690 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3691 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3692 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3693 This->fixed_function_usage_map |= (1 << i);
3696 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3697 This->fixed_function_usage_map |= (1 << (i + 1));
3702 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3703 unsigned int i, tex;
3706 device_update_fixed_function_usage_map(This);
3707 ffu_map = This->fixed_function_usage_map;
3709 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3710 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3711 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3713 if (!(ffu_map & 1)) continue;
3715 if (This->texUnitMap[i] != i) {
3716 device_map_stage(This, i, i);
3717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3718 markTextureStagesDirty(This, i);
3724 /* Now work out the mapping */
3726 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3728 if (!(ffu_map & 1)) continue;
3730 if (This->texUnitMap[i] != tex) {
3731 device_map_stage(This, i, tex);
3732 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3733 markTextureStagesDirty(This, i);
3740 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3741 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3742 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3745 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3746 if (sampler_type[i] && This->texUnitMap[i] != i)
3748 device_map_stage(This, i, i);
3749 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3750 if (i < MAX_TEXTURES) {
3751 markTextureStagesDirty(This, i);
3757 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3758 const DWORD *vshader_sampler_tokens, int unit)
3760 int current_mapping = This->rev_tex_unit_map[unit];
3762 if (current_mapping == -1) {
3763 /* Not currently used */
3767 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3768 /* Used by a fragment sampler */
3770 if (!pshader_sampler_tokens) {
3771 /* No pixel shader, check fixed function */
3772 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3775 /* Pixel shader, check the shader's sampler map */
3776 return !pshader_sampler_tokens[current_mapping];
3779 /* Used by a vertex sampler */
3780 return !vshader_sampler_tokens[current_mapping];
3783 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3784 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3785 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3786 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3787 int start = GL_LIMITS(combined_samplers) - 1;
3791 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3793 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3794 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3795 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3798 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3799 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3800 if (vshader_sampler_type[i])
3802 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3804 /* Already mapped somewhere */
3808 while (start >= 0) {
3809 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3811 device_map_stage(This, vsampler_idx, start);
3812 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3824 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3825 BOOL vs = use_vs(This->stateBlock);
3826 BOOL ps = use_ps(This->stateBlock);
3829 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3830 * that would be really messy and require shader recompilation
3831 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3832 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3835 device_map_psamplers(This);
3837 device_map_fixed_function_samplers(This);
3841 device_map_vsamplers(This, ps);
3845 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3847 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3848 This->updateStateBlock->pixelShader = pShader;
3849 This->updateStateBlock->changed.pixelShader = TRUE;
3851 /* Handle recording of state blocks */
3852 if (This->isRecordingState) {
3853 TRACE("Recording... not performing anything\n");
3856 if (This->isRecordingState) {
3857 TRACE("Recording... not performing anything\n");
3858 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3859 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3863 if(pShader == oldShader) {
3864 TRACE("App is setting the old pixel shader over, nothing to do\n");
3868 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3869 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3871 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3872 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3877 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3880 if (NULL == ppShader) {
3881 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3882 return WINED3DERR_INVALIDCALL;
3885 *ppShader = This->stateBlock->pixelShader;
3886 if (NULL != *ppShader) {
3887 IWineD3DPixelShader_AddRef(*ppShader);
3889 TRACE("(%p) : returning %p\n", This, *ppShader);
3893 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3894 IWineD3DDevice *iface,
3896 CONST BOOL *srcData,
3899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3900 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3902 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3903 iface, srcData, start, count);
3905 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3907 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3908 for (i = 0; i < cnt; i++)
3909 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3911 for (i = start; i < cnt + start; ++i) {
3912 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3915 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3920 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3921 IWineD3DDevice *iface,
3926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3927 int cnt = min(count, MAX_CONST_B - start);
3929 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3930 iface, dstData, start, count);
3932 if (dstData == NULL || cnt < 0)
3933 return WINED3DERR_INVALIDCALL;
3935 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3939 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3940 IWineD3DDevice *iface,
3945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3946 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3948 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3949 iface, srcData, start, count);
3951 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3953 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3954 for (i = 0; i < cnt; i++)
3955 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3956 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3958 for (i = start; i < cnt + start; ++i) {
3959 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3962 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3967 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3968 IWineD3DDevice *iface,
3973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3974 int cnt = min(count, MAX_CONST_I - start);
3976 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3977 iface, dstData, start, count);
3979 if (dstData == NULL || cnt < 0)
3980 return WINED3DERR_INVALIDCALL;
3982 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3986 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3987 IWineD3DDevice *iface,
3989 CONST float *srcData,
3992 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3995 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3996 iface, srcData, start, count);
3998 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3999 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
4000 return WINED3DERR_INVALIDCALL;
4002 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4004 for (i = 0; i < count; i++)
4005 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4006 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4009 if (!This->isRecordingState)
4011 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4012 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4015 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4016 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4021 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4022 IWineD3DDevice *iface,
4027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4028 int cnt = min(count, This->d3d_pshader_constantF - start);
4030 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4031 iface, dstData, start, count);
4033 if (dstData == NULL || cnt < 0)
4034 return WINED3DERR_INVALIDCALL;
4036 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4040 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4041 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4042 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
4045 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4048 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4052 if (stream_info->elements[WINED3D_FFP_NORMAL].data)
4054 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4057 if (!stream_info->elements[WINED3D_FFP_POSITION].data)
4059 ERR("Source has no position mask\n");
4060 return WINED3DERR_INVALIDCALL;
4063 /* We might access VBOs from this code, so hold the lock */
4066 if (dest->resource.allocatedMemory == NULL) {
4067 buffer_get_sysmem(dest);
4070 /* Get a pointer into the destination vbo(create one if none exists) and
4071 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4073 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4075 dest->flags |= WINED3D_BUFFER_CREATEBO;
4076 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4079 if (dest->buffer_object)
4081 unsigned char extrabytes = 0;
4082 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4083 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4084 * this may write 4 extra bytes beyond the area that should be written
4086 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4087 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4088 if(!dest_conv_addr) {
4089 ERR("Out of memory\n");
4090 /* Continue without storing converted vertices */
4092 dest_conv = dest_conv_addr;
4096 * a) WINED3DRS_CLIPPING is enabled
4097 * b) WINED3DVOP_CLIP is passed
4099 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4100 static BOOL warned = FALSE;
4102 * The clipping code is not quite correct. Some things need
4103 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4104 * so disable clipping for now.
4105 * (The graphics in Half-Life are broken, and my processvertices
4106 * test crashes with IDirect3DDevice3)
4112 FIXME("Clipping is broken and disabled for now\n");
4114 } else doClip = FALSE;
4115 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4117 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4120 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4121 WINED3DTS_PROJECTION,
4123 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4124 WINED3DTS_WORLDMATRIX(0),
4127 TRACE("View mat:\n");
4128 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);
4129 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);
4130 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);
4131 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);
4133 TRACE("Proj mat:\n");
4134 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);
4135 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);
4136 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);
4137 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);
4139 TRACE("World mat:\n");
4140 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);
4141 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);
4142 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);
4143 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);
4145 /* Get the viewport */
4146 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4147 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4148 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4150 multiply_matrix(&mat,&view_mat,&world_mat);
4151 multiply_matrix(&mat,&proj_mat,&mat);
4153 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4155 for (i = 0; i < dwCount; i+= 1) {
4156 unsigned int tex_index;
4158 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4159 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4160 /* The position first */
4161 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4162 const float *p = (const float *)(element->data + i * element->stride);
4164 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4166 /* Multiplication with world, view and projection matrix */
4167 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);
4168 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);
4169 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);
4170 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);
4172 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4174 /* WARNING: The following things are taken from d3d7 and were not yet checked
4175 * against d3d8 or d3d9!
4178 /* Clipping conditions: From msdn
4180 * A vertex is clipped if it does not match the following requirements
4184 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4186 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4187 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4192 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4193 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4196 /* "Normal" viewport transformation (not clipped)
4197 * 1) The values are divided by rhw
4198 * 2) The y axis is negative, so multiply it with -1
4199 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4200 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4201 * 4) Multiply x with Width/2 and add Width/2
4202 * 5) The same for the height
4203 * 6) Add the viewpoint X and Y to the 2D coordinates and
4204 * The minimum Z value to z
4205 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4207 * Well, basically it's simply a linear transformation into viewport
4219 z *= vp.MaxZ - vp.MinZ;
4221 x += vp.Width / 2 + vp.X;
4222 y += vp.Height / 2 + vp.Y;
4227 /* That vertex got clipped
4228 * Contrary to OpenGL it is not dropped completely, it just
4229 * undergoes a different calculation.
4231 TRACE("Vertex got clipped\n");
4238 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4239 * outside of the main vertex buffer memory. That needs some more
4244 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4247 ( (float *) dest_ptr)[0] = x;
4248 ( (float *) dest_ptr)[1] = y;
4249 ( (float *) dest_ptr)[2] = z;
4250 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4252 dest_ptr += 3 * sizeof(float);
4254 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4255 dest_ptr += sizeof(float);
4260 ( (float *) dest_conv)[0] = x * w;
4261 ( (float *) dest_conv)[1] = y * w;
4262 ( (float *) dest_conv)[2] = z * w;
4263 ( (float *) dest_conv)[3] = w;
4265 dest_conv += 3 * sizeof(float);
4267 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4268 dest_conv += sizeof(float);
4272 if (DestFVF & WINED3DFVF_PSIZE) {
4273 dest_ptr += sizeof(DWORD);
4274 if(dest_conv) dest_conv += sizeof(DWORD);
4276 if (DestFVF & WINED3DFVF_NORMAL) {
4277 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4278 const float *normal = (const float *)(element->data + i * element->stride);
4279 /* AFAIK this should go into the lighting information */
4280 FIXME("Didn't expect the destination to have a normal\n");
4281 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4283 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4287 if (DestFVF & WINED3DFVF_DIFFUSE) {
4288 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4289 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4291 static BOOL warned = FALSE;
4294 ERR("No diffuse color in source, but destination has one\n");
4298 *( (DWORD *) dest_ptr) = 0xffffffff;
4299 dest_ptr += sizeof(DWORD);
4302 *( (DWORD *) dest_conv) = 0xffffffff;
4303 dest_conv += sizeof(DWORD);
4307 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4309 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4310 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4311 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4312 dest_conv += sizeof(DWORD);
4317 if (DestFVF & WINED3DFVF_SPECULAR) {
4318 /* What's the color value in the feedback buffer? */
4319 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4320 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4322 static BOOL warned = FALSE;
4325 ERR("No specular color in source, but destination has one\n");
4329 *( (DWORD *) dest_ptr) = 0xFF000000;
4330 dest_ptr += sizeof(DWORD);
4333 *( (DWORD *) dest_conv) = 0xFF000000;
4334 dest_conv += sizeof(DWORD);
4338 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4340 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4341 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4342 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4343 dest_conv += sizeof(DWORD);
4348 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4349 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4350 const float *tex_coord = (const float *)(element->data + i * element->stride);
4352 ERR("No source texture, but destination requests one\n");
4353 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4354 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4357 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4359 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4366 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4367 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4368 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4369 dwCount * get_flexible_vertex_size(DestFVF),
4371 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4372 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4379 #undef copy_and_next
4381 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4382 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4386 struct wined3d_stream_info stream_info;
4387 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4388 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4391 ERR("Output vertex declaration not implemented yet\n");
4394 /* Need any context to write to the vbo. */
4395 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4397 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4398 * control the streamIsUP flag, thus restore it afterwards.
4400 This->stateBlock->streamIsUP = FALSE;
4401 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4402 This->stateBlock->streamIsUP = streamWasUP;
4404 if(vbo || SrcStartIndex) {
4406 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4407 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4409 * Also get the start index in, but only loop over all elements if there's something to add at all.
4411 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4413 struct wined3d_stream_info_element *e = &stream_info.elements[i];
4414 if (e->buffer_object)
4416 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4417 e->buffer_object = 0;
4418 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4420 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4421 vb->buffer_object = 0;
4424 if (e->data) e->data += e->stride * SrcStartIndex;
4428 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4429 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4433 * Get / Set Texture Stage States
4434 * TODO: Verify against dx9 definitions
4436 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4438 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4440 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4442 if (Stage >= MAX_TEXTURES) {
4443 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4447 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4448 This->updateStateBlock->textureState[Stage][Type] = Value;
4450 if (This->isRecordingState) {
4451 TRACE("Recording... not performing anything\n");
4455 /* Checked after the assignments to allow proper stateblock recording */
4456 if(oldValue == Value) {
4457 TRACE("App is setting the old value over, nothing to do\n");
4461 if(Stage > This->stateBlock->lowest_disabled_stage &&
4462 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4463 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4464 * Changes in other states are important on disabled stages too
4469 if(Type == WINED3DTSS_COLOROP) {
4472 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4473 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4474 * they have to be disabled
4476 * The current stage is dirtified below.
4478 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4479 TRACE("Additionally dirtifying stage %u\n", i);
4480 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4482 This->stateBlock->lowest_disabled_stage = Stage;
4483 TRACE("New lowest disabled: %u\n", Stage);
4484 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4485 /* Previously disabled stage enabled. Stages above it may need enabling
4486 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4487 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4489 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4492 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4493 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4496 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4497 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4499 This->stateBlock->lowest_disabled_stage = i;
4500 TRACE("New lowest disabled: %u\n", i);
4504 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4509 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4511 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4512 *pValue = This->updateStateBlock->textureState[Stage][Type];
4519 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4521 IWineD3DBaseTexture *oldTexture;
4523 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4525 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4526 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4529 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4530 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4531 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4534 oldTexture = This->updateStateBlock->textures[Stage];
4536 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4537 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4539 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4540 return WINED3DERR_INVALIDCALL;
4543 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4544 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4546 This->updateStateBlock->changed.textures |= 1 << Stage;
4547 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4548 This->updateStateBlock->textures[Stage] = pTexture;
4550 /* Handle recording of state blocks */
4551 if (This->isRecordingState) {
4552 TRACE("Recording... not performing anything\n");
4556 if(oldTexture == pTexture) {
4557 TRACE("App is setting the same texture again, nothing to do\n");
4561 /** NOTE: MSDN says that setTexture increases the reference count,
4562 * and that the application must set the texture back to null (or have a leaky application),
4563 * This means we should pass the refcount up to the parent
4564 *******************************/
4565 if (NULL != This->updateStateBlock->textures[Stage]) {
4566 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4567 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4568 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4570 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4572 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4574 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4577 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4578 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4579 * so the COLOROP and ALPHAOP have to be dirtified.
4581 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4582 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4584 if(bindCount == 1) {
4585 new->baseTexture.sampler = Stage;
4587 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4591 if (NULL != oldTexture) {
4592 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4593 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4595 IWineD3DBaseTexture_Release(oldTexture);
4596 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4597 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4598 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4601 if(bindCount && old->baseTexture.sampler == Stage) {
4603 /* Have to do a search for the other sampler(s) where the texture is bound to
4604 * Shouldn't happen as long as apps bind a texture only to one stage
4606 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4607 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4608 if(This->updateStateBlock->textures[i] == oldTexture) {
4609 old->baseTexture.sampler = i;
4616 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4621 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4624 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4626 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4627 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4630 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4631 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4632 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4635 *ppTexture=This->stateBlock->textures[Stage];
4637 IWineD3DBaseTexture_AddRef(*ppTexture);
4639 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4647 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4648 IWineD3DSurface **ppBackBuffer) {
4649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4650 IWineD3DSwapChain *swapChain;
4653 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4655 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4656 if (hr == WINED3D_OK) {
4657 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4658 IWineD3DSwapChain_Release(swapChain);
4660 *ppBackBuffer = NULL;
4665 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4666 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4667 WARN("(%p) : stub, calling idirect3d for now\n", This);
4668 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4671 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4673 IWineD3DSwapChain *swapChain;
4676 if(iSwapChain > 0) {
4677 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4678 if (hr == WINED3D_OK) {
4679 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4680 IWineD3DSwapChain_Release(swapChain);
4682 FIXME("(%p) Error getting display mode\n", This);
4685 /* Don't read the real display mode,
4686 but return the stored mode instead. X11 can't change the color
4687 depth, and some apps are pretty angry if they SetDisplayMode from
4688 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4690 Also don't relay to the swapchain because with ddraw it's possible
4691 that there isn't a swapchain at all */
4692 pMode->Width = This->ddraw_width;
4693 pMode->Height = This->ddraw_height;
4694 pMode->Format = This->ddraw_format;
4695 pMode->RefreshRate = 0;
4703 * Stateblock related functions
4706 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4708 IWineD3DStateBlock *stateblock;
4711 TRACE("(%p)\n", This);
4713 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4715 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4716 if (FAILED(hr)) return hr;
4718 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4719 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4720 This->isRecordingState = TRUE;
4722 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4727 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4730 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4732 if (!This->isRecordingState) {
4733 WARN("(%p) not recording! returning error\n", This);
4734 *ppStateBlock = NULL;
4735 return WINED3DERR_INVALIDCALL;
4738 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
4740 DWORD map = object->changed.renderState[i];
4741 for (j = 0; map; map >>= 1, ++j)
4743 if (!(map & 1)) continue;
4745 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
4749 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
4751 DWORD map = object->changed.transform[i];
4752 for (j = 0; map; map >>= 1, ++j)
4754 if (!(map & 1)) continue;
4756 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
4759 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4760 if(object->changed.vertexShaderConstantsF[i]) {
4761 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4762 object->num_contained_vs_consts_f++;
4765 for(i = 0; i < MAX_CONST_I; i++) {
4766 if (object->changed.vertexShaderConstantsI & (1 << i))
4768 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4769 object->num_contained_vs_consts_i++;
4772 for(i = 0; i < MAX_CONST_B; i++) {
4773 if (object->changed.vertexShaderConstantsB & (1 << i))
4775 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4776 object->num_contained_vs_consts_b++;
4779 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4781 if (object->changed.pixelShaderConstantsF[i])
4783 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4784 ++object->num_contained_ps_consts_f;
4787 for(i = 0; i < MAX_CONST_I; i++) {
4788 if (object->changed.pixelShaderConstantsI & (1 << i))
4790 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4791 object->num_contained_ps_consts_i++;
4794 for(i = 0; i < MAX_CONST_B; i++) {
4795 if (object->changed.pixelShaderConstantsB & (1 << i))
4797 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4798 object->num_contained_ps_consts_b++;
4801 for(i = 0; i < MAX_TEXTURES; i++) {
4802 DWORD map = object->changed.textureState[i];
4804 for(j = 0; map; map >>= 1, ++j)
4806 if (!(map & 1)) continue;
4808 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4809 object->contained_tss_states[object->num_contained_tss_states].state = j;
4810 ++object->num_contained_tss_states;
4813 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4814 DWORD map = object->changed.samplerState[i];
4816 for (j = 0; map; map >>= 1, ++j)
4818 if (!(map & 1)) continue;
4820 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4821 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4822 ++object->num_contained_sampler_states;
4826 *ppStateBlock = (IWineD3DStateBlock*) object;
4827 This->isRecordingState = FALSE;
4828 This->updateStateBlock = This->stateBlock;
4829 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4830 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4831 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4836 * Scene related functions
4838 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4839 /* At the moment we have no need for any functionality at the beginning
4841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4842 TRACE("(%p)\n", This);
4845 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4846 return WINED3DERR_INVALIDCALL;
4848 This->inScene = TRUE;
4852 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4854 TRACE("(%p)\n", This);
4856 if(!This->inScene) {
4857 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4858 return WINED3DERR_INVALIDCALL;
4861 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4862 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4864 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4868 This->inScene = FALSE;
4872 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4873 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4874 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4876 IWineD3DSwapChain *swapChain = NULL;
4878 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4880 TRACE("(%p) Presenting the frame\n", This);
4882 for(i = 0 ; i < swapchains ; i ++) {
4884 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4885 TRACE("presentinng chain %d, %p\n", i, swapChain);
4886 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4887 IWineD3DSwapChain_Release(swapChain);
4893 /* Not called from the VTable (internal subroutine) */
4894 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4895 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4896 float Z, DWORD Stencil) {
4897 GLbitfield glMask = 0;
4899 WINED3DRECT curRect;
4901 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4902 UINT drawable_width, drawable_height;
4903 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4904 IWineD3DSwapChainImpl *swapchain = NULL;
4906 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4907 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4908 * for the cleared parts, and the untouched parts.
4910 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4911 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4912 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4913 * checking all this if the dest surface is in the drawable anyway.
4915 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4917 if(vp->X != 0 || vp->Y != 0 ||
4918 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4919 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4922 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4923 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4924 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4925 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4926 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4929 if(Count > 0 && pRects && (
4930 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4931 pRects[0].x2 < target->currentDesc.Width ||
4932 pRects[0].y2 < target->currentDesc.Height)) {
4933 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4940 target->get_drawable_size(target, &drawable_width, &drawable_height);
4942 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4945 /* Only set the values up once, as they are not changing */
4946 if (Flags & WINED3DCLEAR_STENCIL) {
4947 glClearStencil(Stencil);
4948 checkGLcall("glClearStencil");
4949 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4950 glStencilMask(0xFFFFFFFF);
4953 if (Flags & WINED3DCLEAR_ZBUFFER) {
4954 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4955 glDepthMask(GL_TRUE);
4957 checkGLcall("glClearDepth");
4958 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4959 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4961 if (vp->X != 0 || vp->Y != 0 ||
4962 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4963 surface_load_ds_location(This->stencilBufferTarget, location);
4965 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4966 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4967 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4968 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4969 surface_load_ds_location(This->stencilBufferTarget, location);
4971 else if (Count > 0 && pRects && (
4972 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4973 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4974 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4975 surface_load_ds_location(This->stencilBufferTarget, location);
4979 if (Flags & WINED3DCLEAR_TARGET) {
4980 TRACE("Clearing screen with glClear to color %x\n", Color);
4981 glClearColor(D3DCOLOR_R(Color),
4985 checkGLcall("glClearColor");
4987 /* Clear ALL colors! */
4988 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4989 glMask = glMask | GL_COLOR_BUFFER_BIT;
4992 vp_rect.left = vp->X;
4993 vp_rect.top = vp->Y;
4994 vp_rect.right = vp->X + vp->Width;
4995 vp_rect.bottom = vp->Y + vp->Height;
4996 if (!(Count > 0 && pRects)) {
4997 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4998 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5000 if(This->render_offscreen) {
5001 glScissor(vp_rect.left, vp_rect.top,
5002 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5004 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5005 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5007 checkGLcall("glScissor");
5009 checkGLcall("glClear");
5011 /* Now process each rect in turn */
5012 for (i = 0; i < Count; i++) {
5013 /* Note gl uses lower left, width/height */
5014 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5015 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5016 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5018 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5019 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5020 curRect.x1, (target->currentDesc.Height - curRect.y2),
5021 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5023 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5024 * The rectangle is not cleared, no error is returned, but further rectanlges are
5025 * still cleared if they are valid
5027 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5028 TRACE("Rectangle with negative dimensions, ignoring\n");
5032 if(This->render_offscreen) {
5033 glScissor(curRect.x1, curRect.y1,
5034 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5036 glScissor(curRect.x1, drawable_height - curRect.y2,
5037 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5039 checkGLcall("glScissor");
5042 checkGLcall("glClear");
5046 /* Restore the old values (why..?) */
5047 if (Flags & WINED3DCLEAR_STENCIL) {
5048 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5050 if (Flags & WINED3DCLEAR_TARGET) {
5051 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5052 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5053 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5054 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5055 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5057 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5058 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5060 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5062 if (Flags & WINED3DCLEAR_ZBUFFER) {
5063 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5064 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5065 surface_modify_ds_location(This->stencilBufferTarget, location);
5070 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5071 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5074 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5080 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5081 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5083 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5085 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5086 Count, pRects, Flags, Color, Z, Stencil);
5088 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5089 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5090 /* TODO: What about depth stencil buffers without stencil bits? */
5091 return WINED3DERR_INVALIDCALL;
5094 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5101 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5102 WINED3DPRIMITIVETYPE primitive_type)
5104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5106 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5108 This->updateStateBlock->changed.primitive_type = TRUE;
5109 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5112 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5113 WINED3DPRIMITIVETYPE *primitive_type)
5115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5117 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5119 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5121 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5124 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5128 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5130 if(!This->stateBlock->vertexDecl) {
5131 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5132 return WINED3DERR_INVALIDCALL;
5135 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5136 if(This->stateBlock->streamIsUP) {
5137 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5138 This->stateBlock->streamIsUP = FALSE;
5141 if(This->stateBlock->loadBaseVertexIndex != 0) {
5142 This->stateBlock->loadBaseVertexIndex = 0;
5143 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5145 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5146 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5147 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5151 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5152 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5156 IWineD3DBuffer *pIB;
5159 pIB = This->stateBlock->pIndexData;
5161 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5162 * without an index buffer set. (The first time at least...)
5163 * D3D8 simply dies, but I doubt it can do much harm to return
5164 * D3DERR_INVALIDCALL there as well. */
5165 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5166 return WINED3DERR_INVALIDCALL;
5169 if(!This->stateBlock->vertexDecl) {
5170 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5171 return WINED3DERR_INVALIDCALL;
5174 if(This->stateBlock->streamIsUP) {
5175 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5176 This->stateBlock->streamIsUP = FALSE;
5178 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
5180 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5181 This, minIndex, NumVertices, startIndex, index_count);
5183 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
5189 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5190 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5191 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5194 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5195 vbo ? NULL : ((struct wined3d_buffer *) pIB)->resource.allocatedMemory, minIndex);
5200 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5201 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5206 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5207 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5209 if(!This->stateBlock->vertexDecl) {
5210 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5211 return WINED3DERR_INVALIDCALL;
5214 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5215 vb = This->stateBlock->streamSource[0];
5216 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5217 if (vb) IWineD3DBuffer_Release(vb);
5218 This->stateBlock->streamOffset[0] = 0;
5219 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5220 This->stateBlock->streamIsUP = TRUE;
5221 This->stateBlock->loadBaseVertexIndex = 0;
5223 /* TODO: Only mark dirty if drawing from a different UP address */
5224 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5226 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5227 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5229 /* MSDN specifies stream zero settings must be set to NULL */
5230 This->stateBlock->streamStride[0] = 0;
5231 This->stateBlock->streamSource[0] = NULL;
5233 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5234 * the new stream sources or use UP drawing again
5239 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5240 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5241 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5248 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5249 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5250 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5252 if(!This->stateBlock->vertexDecl) {
5253 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5254 return WINED3DERR_INVALIDCALL;
5257 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5263 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5264 vb = This->stateBlock->streamSource[0];
5265 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5266 if (vb) IWineD3DBuffer_Release(vb);
5267 This->stateBlock->streamIsUP = TRUE;
5268 This->stateBlock->streamOffset[0] = 0;
5269 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5271 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5272 This->stateBlock->baseVertexIndex = 0;
5273 This->stateBlock->loadBaseVertexIndex = 0;
5274 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5275 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5276 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5278 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5279 idxStride, pIndexData, MinVertexIndex);
5281 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5282 This->stateBlock->streamSource[0] = NULL;
5283 This->stateBlock->streamStride[0] = 0;
5284 ib = This->stateBlock->pIndexData;
5286 IWineD3DBuffer_Release(ib);
5287 This->stateBlock->pIndexData = NULL;
5289 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5290 * SetStreamSource to specify a vertex buffer
5296 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5297 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5301 /* Mark the state dirty until we have nicer tracking
5302 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5305 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5306 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5307 This->stateBlock->baseVertexIndex = 0;
5308 This->up_strided = DrawPrimStrideData;
5309 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5310 This->up_strided = NULL;
5314 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5315 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5316 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5319 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5321 /* Mark the state dirty until we have nicer tracking
5322 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5325 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5326 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5327 This->stateBlock->streamIsUP = TRUE;
5328 This->stateBlock->baseVertexIndex = 0;
5329 This->up_strided = DrawPrimStrideData;
5330 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5331 This->up_strided = NULL;
5335 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5336 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5337 * not callable by the app directly no parameter validation checks are needed here.
5339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5340 WINED3DLOCKED_BOX src;
5341 WINED3DLOCKED_BOX dst;
5343 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5345 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5346 * dirtification to improve loading performance.
5348 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5349 if(FAILED(hr)) return hr;
5350 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5352 IWineD3DVolume_UnlockBox(pSourceVolume);
5356 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5358 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5360 IWineD3DVolume_UnlockBox(pSourceVolume);
5362 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5367 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5368 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5370 HRESULT hr = WINED3D_OK;
5371 WINED3DRESOURCETYPE sourceType;
5372 WINED3DRESOURCETYPE destinationType;
5375 /* TODO: think about moving the code into IWineD3DBaseTexture */
5377 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5379 /* verify that the source and destination textures aren't NULL */
5380 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5381 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5382 This, pSourceTexture, pDestinationTexture);
5383 hr = WINED3DERR_INVALIDCALL;
5386 if (pSourceTexture == pDestinationTexture) {
5387 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5388 This, pSourceTexture, pDestinationTexture);
5389 hr = WINED3DERR_INVALIDCALL;
5391 /* Verify that the source and destination textures are the same type */
5392 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5393 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5395 if (sourceType != destinationType) {
5396 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5398 hr = WINED3DERR_INVALIDCALL;
5401 /* check that both textures have the identical numbers of levels */
5402 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5403 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5404 hr = WINED3DERR_INVALIDCALL;
5407 if (WINED3D_OK == hr) {
5408 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5410 /* Make sure that the destination texture is loaded */
5411 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5413 /* Update every surface level of the texture */
5414 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5416 switch (sourceType) {
5417 case WINED3DRTYPE_TEXTURE:
5419 IWineD3DSurface *srcSurface;
5420 IWineD3DSurface *destSurface;
5422 for (i = 0 ; i < levels ; ++i) {
5423 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5424 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5425 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5426 IWineD3DSurface_Release(srcSurface);
5427 IWineD3DSurface_Release(destSurface);
5428 if (WINED3D_OK != hr) {
5429 WARN("(%p) : Call to update surface failed\n", This);
5435 case WINED3DRTYPE_CUBETEXTURE:
5437 IWineD3DSurface *srcSurface;
5438 IWineD3DSurface *destSurface;
5439 WINED3DCUBEMAP_FACES faceType;
5441 for (i = 0 ; i < levels ; ++i) {
5442 /* Update each cube face */
5443 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5444 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5445 if (WINED3D_OK != hr) {
5446 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5448 TRACE("Got srcSurface %p\n", srcSurface);
5450 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5451 if (WINED3D_OK != hr) {
5452 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5454 TRACE("Got desrSurface %p\n", destSurface);
5456 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5457 IWineD3DSurface_Release(srcSurface);
5458 IWineD3DSurface_Release(destSurface);
5459 if (WINED3D_OK != hr) {
5460 WARN("(%p) : Call to update surface failed\n", This);
5468 case WINED3DRTYPE_VOLUMETEXTURE:
5470 IWineD3DVolume *srcVolume = NULL;
5471 IWineD3DVolume *destVolume = NULL;
5473 for (i = 0 ; i < levels ; ++i) {
5474 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5475 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5476 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5477 IWineD3DVolume_Release(srcVolume);
5478 IWineD3DVolume_Release(destVolume);
5479 if (WINED3D_OK != hr) {
5480 WARN("(%p) : Call to update volume failed\n", This);
5488 FIXME("(%p) : Unsupported source and destination type\n", This);
5489 hr = WINED3DERR_INVALIDCALL;
5496 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5497 IWineD3DSwapChain *swapChain;
5499 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5500 if(hr == WINED3D_OK) {
5501 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5502 IWineD3DSwapChain_Release(swapChain);
5507 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5509 IWineD3DBaseTextureImpl *texture;
5512 TRACE("(%p) : %p\n", This, pNumPasses);
5514 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5515 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5516 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5517 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5519 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5520 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5521 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5524 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5525 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5527 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5528 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5531 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5532 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5535 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5536 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5537 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5542 /* return a sensible default */
5545 TRACE("returning D3D_OK\n");
5549 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5553 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5554 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5555 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
5556 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
5558 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5563 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5567 PALETTEENTRY **palettes;
5569 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5571 if (PaletteNumber >= MAX_PALETTES) {
5572 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5573 return WINED3DERR_INVALIDCALL;
5576 if (PaletteNumber >= This->NumberOfPalettes) {
5577 NewSize = This->NumberOfPalettes;
5580 } while(PaletteNumber >= NewSize);
5581 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5583 ERR("Out of memory!\n");
5584 return E_OUTOFMEMORY;
5586 This->palettes = palettes;
5587 This->NumberOfPalettes = NewSize;
5590 if (!This->palettes[PaletteNumber]) {
5591 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5592 if (!This->palettes[PaletteNumber]) {
5593 ERR("Out of memory!\n");
5594 return E_OUTOFMEMORY;
5598 for (j = 0; j < 256; ++j) {
5599 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5600 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5601 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5602 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5604 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5605 TRACE("(%p) : returning\n", This);
5609 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5612 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5613 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5614 /* What happens in such situation isn't documented; Native seems to silently abort
5615 on such conditions. Return Invalid Call. */
5616 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5617 return WINED3DERR_INVALIDCALL;
5619 for (j = 0; j < 256; ++j) {
5620 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5621 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5622 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5623 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5625 TRACE("(%p) : returning\n", This);
5629 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5631 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5632 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5633 (tested with reference rasterizer). Return Invalid Call. */
5634 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5635 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5636 return WINED3DERR_INVALIDCALL;
5638 /*TODO: stateblocks */
5639 if (This->currentPalette != PaletteNumber) {
5640 This->currentPalette = PaletteNumber;
5641 dirtify_p8_texture_samplers(This);
5643 TRACE("(%p) : returning\n", This);
5647 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5649 if (PaletteNumber == NULL) {
5650 WARN("(%p) : returning Invalid Call\n", This);
5651 return WINED3DERR_INVALIDCALL;
5653 /*TODO: stateblocks */
5654 *PaletteNumber = This->currentPalette;
5655 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5659 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5664 FIXME("(%p) : stub\n", This);
5668 This->softwareVertexProcessing = bSoftware;
5673 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5678 FIXME("(%p) : stub\n", This);
5681 return This->softwareVertexProcessing;
5685 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5687 IWineD3DSwapChain *swapChain;
5690 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5692 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5693 if(hr == WINED3D_OK){
5694 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5695 IWineD3DSwapChain_Release(swapChain);
5697 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5703 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5706 if(nSegments != 0.0f) {
5709 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5716 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5721 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5727 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5729 /** TODO: remove casts to IWineD3DSurfaceImpl
5730 * NOTE: move code to surface to accomplish this
5731 ****************************************/
5732 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5733 int srcWidth, srcHeight;
5734 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5735 WINED3DFORMAT destFormat, srcFormat;
5737 int srcLeft, destLeft, destTop;
5738 WINED3DPOOL srcPool, destPool;
5740 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5741 glDescriptor *glDescription = NULL;
5742 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5746 CONVERT_TYPES convert = NO_CONVERSION;
5748 WINED3DSURFACE_DESC winedesc;
5750 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5751 memset(&winedesc, 0, sizeof(winedesc));
5752 winedesc.Width = &srcSurfaceWidth;
5753 winedesc.Height = &srcSurfaceHeight;
5754 winedesc.Pool = &srcPool;
5755 winedesc.Format = &srcFormat;
5757 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5759 winedesc.Width = &destSurfaceWidth;
5760 winedesc.Height = &destSurfaceHeight;
5761 winedesc.Pool = &destPool;
5762 winedesc.Format = &destFormat;
5763 winedesc.Size = &destSize;
5765 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5767 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5768 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5769 return WINED3DERR_INVALIDCALL;
5772 /* This call loads the opengl surface directly, instead of copying the surface to the
5773 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5774 * copy in sysmem and use regular surface loading.
5776 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5777 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5778 if(convert != NO_CONVERSION) {
5779 return IWineD3DSurface_BltFast(pDestinationSurface,
5780 pDestPoint ? pDestPoint->x : 0,
5781 pDestPoint ? pDestPoint->y : 0,
5782 pSourceSurface, pSourceRect, 0);
5785 if (destFormat == WINED3DFMT_UNKNOWN) {
5786 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5787 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5789 /* Get the update surface description */
5790 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5793 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5796 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5797 checkGLcall("glActiveTextureARB");
5800 /* Make sure the surface is loaded and up to date */
5801 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5802 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5804 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5806 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5807 dst_format_desc = ((IWineD3DSurfaceImpl *)pDestinationSurface)->resource.format_desc;
5809 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5810 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5811 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5812 srcLeft = pSourceRect ? pSourceRect->left : 0;
5813 destLeft = pDestPoint ? pDestPoint->x : 0;
5814 destTop = pDestPoint ? pDestPoint->y : 0;
5817 /* This function doesn't support compressed textures
5818 the pitch is just bytesPerPixel * width */
5819 if(srcWidth != srcSurfaceWidth || srcLeft ){
5820 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5821 offset += srcLeft * src_format_desc->byte_count;
5822 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5824 /* TODO DXT formats */
5826 if(pSourceRect != NULL && pSourceRect->top != 0){
5827 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5829 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5830 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5831 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5834 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5836 /* need to lock the surface to get the data */
5837 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5842 /* TODO: Cube and volume support */
5844 /* not a whole row so we have to do it a line at a time */
5847 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5848 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5850 for (j = destTop; j < (srcHeight + destTop); ++j)
5852 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, j,
5853 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5857 } else { /* Full width, so just write out the whole texture */
5858 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5860 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5862 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5864 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5865 FIXME("Updating part of a compressed texture is not supported.\n");
5867 if (destFormat != srcFormat)
5869 FIXME("Updating mixed format compressed textures is not supported.\n");
5873 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
5874 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5879 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
5880 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5883 checkGLcall("glTexSubImage2D");
5887 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5888 sampler = This->rev_tex_unit_map[0];
5889 if (sampler != -1) {
5890 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5896 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5898 struct WineD3DRectPatch *patch;
5899 GLenum old_primitive_type;
5903 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5905 if(!(Handle || pRectPatchInfo)) {
5906 /* TODO: Write a test for the return value, thus the FIXME */
5907 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5908 return WINED3DERR_INVALIDCALL;
5912 i = PATCHMAP_HASHFUNC(Handle);
5914 LIST_FOR_EACH(e, &This->patches[i]) {
5915 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5916 if(patch->Handle == Handle) {
5923 TRACE("Patch does not exist. Creating a new one\n");
5924 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5925 patch->Handle = Handle;
5926 list_add_head(&This->patches[i], &patch->entry);
5928 TRACE("Found existing patch %p\n", patch);
5931 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5932 * attributes we have to tesselate, read back, and draw. This needs a patch
5933 * management structure instance. Create one.
5935 * A possible improvement is to check if a vertex shader is used, and if not directly
5938 FIXME("Drawing an uncached patch. This is slow\n");
5939 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5942 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5943 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5944 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5946 TRACE("Tesselation density or patch info changed, retesselating\n");
5948 if(pRectPatchInfo) {
5949 patch->RectPatchInfo = *pRectPatchInfo;
5951 patch->numSegs[0] = pNumSegs[0];
5952 patch->numSegs[1] = pNumSegs[1];
5953 patch->numSegs[2] = pNumSegs[2];
5954 patch->numSegs[3] = pNumSegs[3];
5956 hr = tesselate_rectpatch(This, patch);
5958 WARN("Patch tesselation failed\n");
5960 /* Do not release the handle to store the params of the patch */
5962 HeapFree(GetProcessHeap(), 0, patch);
5968 This->currentPatch = patch;
5969 old_primitive_type = This->stateBlock->gl_primitive_type;
5970 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5971 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5972 This->stateBlock->gl_primitive_type = old_primitive_type;
5973 This->currentPatch = NULL;
5975 /* Destroy uncached patches */
5977 HeapFree(GetProcessHeap(), 0, patch->mem);
5978 HeapFree(GetProcessHeap(), 0, patch);
5983 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5984 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5985 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5986 FIXME("(%p) : Stub\n", This);
5990 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5993 struct WineD3DRectPatch *patch;
5995 TRACE("(%p) Handle(%d)\n", This, Handle);
5997 i = PATCHMAP_HASHFUNC(Handle);
5998 LIST_FOR_EACH(e, &This->patches[i]) {
5999 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6000 if(patch->Handle == Handle) {
6001 TRACE("Deleting patch %p\n", patch);
6002 list_remove(&patch->entry);
6003 HeapFree(GetProcessHeap(), 0, patch->mem);
6004 HeapFree(GetProcessHeap(), 0, patch);
6009 /* TODO: Write a test for the return value */
6010 FIXME("Attempt to destroy nonexistent patch\n");
6011 return WINED3DERR_INVALIDCALL;
6014 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6016 IWineD3DSwapChain *swapchain;
6018 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6019 if (SUCCEEDED(hr)) {
6020 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6027 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6028 const WINED3DRECT *rect, const float color[4])
6030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6031 IWineD3DSwapChain *swapchain;
6033 swapchain = get_swapchain(surface);
6037 TRACE("Surface %p is onscreen\n", surface);
6039 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6041 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6042 buffer = surface_get_gl_buffer(surface, swapchain);
6043 glDrawBuffer(buffer);
6044 checkGLcall("glDrawBuffer()");
6046 TRACE("Surface %p is offscreen\n", surface);
6048 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6050 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6051 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6052 context_attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, NULL, FALSE);
6056 glEnable(GL_SCISSOR_TEST);
6058 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6060 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6061 rect->x2 - rect->x1, rect->y2 - rect->y1);
6063 checkGLcall("glScissor");
6064 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6066 glDisable(GL_SCISSOR_TEST);
6068 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6070 glDisable(GL_BLEND);
6071 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6073 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6074 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6076 glClearColor(color[0], color[1], color[2], color[3]);
6077 glClear(GL_COLOR_BUFFER_BIT);
6078 checkGLcall("glClear");
6080 if (This->activeContext->current_fbo) {
6081 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6083 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6084 checkGLcall("glBindFramebuffer()");
6087 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6088 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6089 glDrawBuffer(GL_BACK);
6090 checkGLcall("glDrawBuffer()");
6096 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6097 unsigned int r, g, b, a;
6100 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6101 destfmt == WINED3DFMT_R8G8B8)
6104 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6106 a = (color & 0xff000000) >> 24;
6107 r = (color & 0x00ff0000) >> 16;
6108 g = (color & 0x0000ff00) >> 8;
6109 b = (color & 0x000000ff) >> 0;
6113 case WINED3DFMT_R5G6B5:
6114 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6121 TRACE("Returning %08x\n", ret);
6124 case WINED3DFMT_X1R5G5B5:
6125 case WINED3DFMT_A1R5G5B5:
6134 TRACE("Returning %08x\n", ret);
6137 case WINED3DFMT_A8_UNORM:
6138 TRACE("Returning %08x\n", a);
6141 case WINED3DFMT_X4R4G4B4:
6142 case WINED3DFMT_A4R4G4B4:
6151 TRACE("Returning %08x\n", ret);
6154 case WINED3DFMT_R3G3B2:
6161 TRACE("Returning %08x\n", ret);
6164 case WINED3DFMT_X8B8G8R8:
6165 case WINED3DFMT_R8G8B8A8_UNORM:
6170 TRACE("Returning %08x\n", ret);
6173 case WINED3DFMT_A2R10G10B10:
6175 r = (r * 1024) / 256;
6176 g = (g * 1024) / 256;
6177 b = (b * 1024) / 256;
6182 TRACE("Returning %08x\n", ret);
6185 case WINED3DFMT_R10G10B10A2_UNORM:
6187 r = (r * 1024) / 256;
6188 g = (g * 1024) / 256;
6189 b = (b * 1024) / 256;
6194 TRACE("Returning %08x\n", ret);
6198 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6203 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6205 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6207 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6209 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6210 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6211 return WINED3DERR_INVALIDCALL;
6214 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6215 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6216 color_fill_fbo(iface, pSurface, pRect, c);
6219 /* Just forward this to the DirectDraw blitting engine */
6220 memset(&BltFx, 0, sizeof(BltFx));
6221 BltFx.dwSize = sizeof(BltFx);
6222 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6223 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6224 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6228 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6229 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6231 IWineD3DResource *resource;
6232 IWineD3DSurface *surface;
6235 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6238 ERR("Failed to get resource, hr %#x\n", hr);
6242 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6244 FIXME("Only supported on surface resources\n");
6245 IWineD3DResource_Release(resource);
6249 surface = (IWineD3DSurface *)resource;
6251 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6253 color_fill_fbo(iface, surface, NULL, color);
6260 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6262 c = ((DWORD)(color[2] * 255.0));
6263 c |= ((DWORD)(color[1] * 255.0)) << 8;
6264 c |= ((DWORD)(color[0] * 255.0)) << 16;
6265 c |= ((DWORD)(color[3] * 255.0)) << 24;
6267 /* Just forward this to the DirectDraw blitting engine */
6268 memset(&BltFx, 0, sizeof(BltFx));
6269 BltFx.dwSize = sizeof(BltFx);
6270 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6271 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6274 ERR("Blt failed, hr %#x\n", hr);
6278 IWineD3DResource_Release(resource);
6281 /* rendertarget and depth stencil functions */
6282 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6285 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6286 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6287 return WINED3DERR_INVALIDCALL;
6290 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6291 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6292 /* Note inc ref on returned surface */
6293 if(*ppRenderTarget != NULL)
6294 IWineD3DSurface_AddRef(*ppRenderTarget);
6298 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6300 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6301 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6302 IWineD3DSwapChainImpl *Swapchain;
6305 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6307 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6308 if(hr != WINED3D_OK) {
6309 ERR("Can't get the swapchain\n");
6313 /* Make sure to release the swapchain */
6314 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6316 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6317 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6318 return WINED3DERR_INVALIDCALL;
6320 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6321 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6322 return WINED3DERR_INVALIDCALL;
6325 if(Swapchain->frontBuffer != Front) {
6326 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6328 if(Swapchain->frontBuffer)
6330 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6331 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6333 Swapchain->frontBuffer = Front;
6335 if(Swapchain->frontBuffer) {
6336 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6337 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6341 if(Back && !Swapchain->backBuffer) {
6342 /* We need memory for the back buffer array - only one back buffer this way */
6343 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6344 if(!Swapchain->backBuffer) {
6345 ERR("Out of memory\n");
6346 return E_OUTOFMEMORY;
6350 if(Swapchain->backBuffer[0] != Back) {
6351 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6353 /* What to do about the context here in the case of multithreading? Not sure.
6354 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6357 if(!Swapchain->backBuffer[0]) {
6358 /* GL was told to draw to the front buffer at creation,
6361 glDrawBuffer(GL_BACK);
6362 checkGLcall("glDrawBuffer(GL_BACK)");
6363 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6364 Swapchain->presentParms.BackBufferCount = 1;
6366 /* That makes problems - disable for now */
6367 /* glDrawBuffer(GL_FRONT); */
6368 checkGLcall("glDrawBuffer(GL_FRONT)");
6369 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6370 Swapchain->presentParms.BackBufferCount = 0;
6374 if(Swapchain->backBuffer[0])
6376 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6377 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6379 Swapchain->backBuffer[0] = Back;
6381 if(Swapchain->backBuffer[0]) {
6382 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6383 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6385 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6386 Swapchain->backBuffer = NULL;
6394 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6396 *ppZStencilSurface = This->stencilBufferTarget;
6397 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6399 if(*ppZStencilSurface != NULL) {
6400 /* Note inc ref on returned surface */
6401 IWineD3DSurface_AddRef(*ppZStencilSurface);
6404 return WINED3DERR_NOTFOUND;
6408 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6409 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6411 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6412 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6413 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6415 POINT offset = {0, 0};
6417 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6418 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6419 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6420 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6423 case WINED3DTEXF_LINEAR:
6424 gl_filter = GL_LINEAR;
6428 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6429 case WINED3DTEXF_NONE:
6430 case WINED3DTEXF_POINT:
6431 gl_filter = GL_NEAREST;
6435 /* Attach src surface to src fbo */
6436 src_swapchain = get_swapchain(src_surface);
6437 if (src_swapchain) {
6438 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6440 TRACE("Source surface %p is onscreen\n", src_surface);
6441 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6442 /* Make sure the drawable is up to date. In the offscreen case
6443 * attach_surface_fbo() implicitly takes care of this. */
6444 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6446 if(buffer == GL_FRONT) {
6449 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6450 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6451 h = windowsize.bottom - windowsize.top;
6452 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6453 src_rect->y1 = offset.y + h - src_rect->y1;
6454 src_rect->y2 = offset.y + h - src_rect->y2;
6456 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6457 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6461 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6462 glReadBuffer(buffer);
6463 checkGLcall("glReadBuffer()");
6465 TRACE("Source surface %p is offscreen\n", src_surface);
6467 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6468 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6469 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6470 checkGLcall("glReadBuffer()");
6471 context_attach_depth_stencil_fbo(This, GL_READ_FRAMEBUFFER_EXT, NULL, FALSE);
6475 /* Attach dst surface to dst fbo */
6476 dst_swapchain = get_swapchain(dst_surface);
6477 if (dst_swapchain) {
6478 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6480 TRACE("Destination surface %p is onscreen\n", dst_surface);
6481 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6482 /* Make sure the drawable is up to date. In the offscreen case
6483 * attach_surface_fbo() implicitly takes care of this. */
6484 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6486 if(buffer == GL_FRONT) {
6489 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6490 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6491 h = windowsize.bottom - windowsize.top;
6492 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6493 dst_rect->y1 = offset.y + h - dst_rect->y1;
6494 dst_rect->y2 = offset.y + h - dst_rect->y2;
6496 /* Screen coords = window coords, surface height = window height */
6497 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6498 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6502 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6503 glDrawBuffer(buffer);
6504 checkGLcall("glDrawBuffer()");
6506 TRACE("Destination surface %p is offscreen\n", dst_surface);
6508 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6509 if(!src_swapchain) {
6510 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6514 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6515 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6516 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6517 checkGLcall("glDrawBuffer()");
6518 context_attach_depth_stencil_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, NULL, FALSE);
6520 glDisable(GL_SCISSOR_TEST);
6521 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6524 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6525 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6526 checkGLcall("glBlitFramebuffer()");
6528 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6529 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6530 checkGLcall("glBlitFramebuffer()");
6533 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6535 if (This->activeContext->current_fbo) {
6536 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6538 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6539 checkGLcall("glBindFramebuffer()");
6542 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6543 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6544 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6545 glDrawBuffer(GL_BACK);
6546 checkGLcall("glDrawBuffer()");
6551 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6553 WINED3DVIEWPORT viewport;
6555 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6557 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6558 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6559 This, RenderTargetIndex, GL_LIMITS(buffers));
6560 return WINED3DERR_INVALIDCALL;
6563 /* MSDN says that null disables the render target
6564 but a device must always be associated with a render target
6565 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6567 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6568 FIXME("Trying to set render target 0 to NULL\n");
6569 return WINED3DERR_INVALIDCALL;
6571 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6572 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);
6573 return WINED3DERR_INVALIDCALL;
6576 /* If we are trying to set what we already have, don't bother */
6577 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6578 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6581 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6582 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6583 This->render_targets[RenderTargetIndex] = pRenderTarget;
6585 /* Render target 0 is special */
6586 if(RenderTargetIndex == 0) {
6587 /* Finally, reset the viewport as the MSDN states. */
6588 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6589 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6592 viewport.MaxZ = 1.0f;
6593 viewport.MinZ = 0.0f;
6594 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6595 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6596 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6598 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6603 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6605 HRESULT hr = WINED3D_OK;
6606 IWineD3DSurface *tmp;
6608 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6610 if (pNewZStencil == This->stencilBufferTarget) {
6611 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6613 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6614 * depending on the renter target implementation being used.
6615 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6616 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6617 * stencil buffer and incur an extra memory overhead
6618 ******************************************************/
6620 if (This->stencilBufferTarget) {
6621 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6622 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6623 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6625 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6626 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6627 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6631 tmp = This->stencilBufferTarget;
6632 This->stencilBufferTarget = pNewZStencil;
6633 /* should we be calling the parent or the wined3d surface? */
6634 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6635 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6638 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6639 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6640 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6641 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6642 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6649 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6650 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6652 /* TODO: the use of Impl is deprecated. */
6653 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6654 WINED3DLOCKED_RECT lockedRect;
6656 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6658 /* some basic validation checks */
6659 if(This->cursorTexture) {
6660 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6662 glDeleteTextures(1, &This->cursorTexture);
6664 This->cursorTexture = 0;
6667 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6668 This->haveHardwareCursor = TRUE;
6670 This->haveHardwareCursor = FALSE;
6673 WINED3DLOCKED_RECT rect;
6675 /* MSDN: Cursor must be A8R8G8B8 */
6676 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
6678 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6679 return WINED3DERR_INVALIDCALL;
6682 /* MSDN: Cursor must be smaller than the display mode */
6683 if(pSur->currentDesc.Width > This->ddraw_width ||
6684 pSur->currentDesc.Height > This->ddraw_height) {
6685 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);
6686 return WINED3DERR_INVALIDCALL;
6689 if (!This->haveHardwareCursor) {
6690 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6692 /* Do not store the surface's pointer because the application may
6693 * release it after setting the cursor image. Windows doesn't
6694 * addref the set surface, so we can't do this either without
6695 * creating circular refcount dependencies. Copy out the gl texture
6698 This->cursorWidth = pSur->currentDesc.Width;
6699 This->cursorHeight = pSur->currentDesc.Height;
6700 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6702 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
6703 char *mem, *bits = rect.pBits;
6704 GLint intfmt = glDesc->glInternal;
6705 GLint format = glDesc->glFormat;
6706 GLint type = glDesc->glType;
6707 INT height = This->cursorHeight;
6708 INT width = This->cursorWidth;
6709 INT bpp = glDesc->byte_count;
6712 /* Reformat the texture memory (pitch and width can be
6714 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6715 for(i = 0; i < height; i++)
6716 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6717 IWineD3DSurface_UnlockRect(pCursorBitmap);
6720 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6721 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6722 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6725 /* Make sure that a proper texture unit is selected */
6726 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6727 checkGLcall("glActiveTextureARB");
6728 sampler = This->rev_tex_unit_map[0];
6729 if (sampler != -1) {
6730 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6732 /* Create a new cursor texture */
6733 glGenTextures(1, &This->cursorTexture);
6734 checkGLcall("glGenTextures");
6735 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6736 checkGLcall("glBindTexture");
6737 /* Copy the bitmap memory into the cursor texture */
6738 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6739 HeapFree(GetProcessHeap(), 0, mem);
6740 checkGLcall("glTexImage2D");
6742 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6743 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6744 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6751 FIXME("A cursor texture was not returned.\n");
6752 This->cursorTexture = 0;
6757 /* Draw a hardware cursor */
6758 ICONINFO cursorInfo;
6760 /* Create and clear maskBits because it is not needed for
6761 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6763 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6764 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6765 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6766 WINED3DLOCK_NO_DIRTY_UPDATE |
6767 WINED3DLOCK_READONLY
6769 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6770 pSur->currentDesc.Height);
6772 cursorInfo.fIcon = FALSE;
6773 cursorInfo.xHotspot = XHotSpot;
6774 cursorInfo.yHotspot = YHotSpot;
6775 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6776 pSur->currentDesc.Height, 1,
6778 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6779 pSur->currentDesc.Height, 1,
6780 32, lockedRect.pBits);
6781 IWineD3DSurface_UnlockRect(pCursorBitmap);
6782 /* Create our cursor and clean up. */
6783 cursor = CreateIconIndirect(&cursorInfo);
6785 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6786 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6787 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6788 This->hardwareCursor = cursor;
6789 HeapFree(GetProcessHeap(), 0, maskBits);
6793 This->xHotSpot = XHotSpot;
6794 This->yHotSpot = YHotSpot;
6798 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6800 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6802 This->xScreenSpace = XScreenSpace;
6803 This->yScreenSpace = YScreenSpace;
6809 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6811 BOOL oldVisible = This->bCursorVisible;
6814 TRACE("(%p) : visible(%d)\n", This, bShow);
6817 * When ShowCursor is first called it should make the cursor appear at the OS's last
6818 * known cursor position. Because of this, some applications just repetitively call
6819 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6822 This->xScreenSpace = pt.x;
6823 This->yScreenSpace = pt.y;
6825 if (This->haveHardwareCursor) {
6826 This->bCursorVisible = bShow;
6828 SetCursor(This->hardwareCursor);
6834 if (This->cursorTexture)
6835 This->bCursorVisible = bShow;
6841 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6843 IWineD3DResourceImpl *resource;
6844 TRACE("(%p) : state (%u)\n", This, This->state);
6846 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6847 switch (This->state) {
6850 case WINED3DERR_DEVICELOST:
6852 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6853 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6854 return WINED3DERR_DEVICENOTRESET;
6856 return WINED3DERR_DEVICELOST;
6858 case WINED3DERR_DRIVERINTERNALERROR:
6859 return WINED3DERR_DRIVERINTERNALERROR;
6863 return WINED3DERR_DRIVERINTERNALERROR;
6867 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6869 /** FIXME: Resource tracking needs to be done,
6870 * The closes we can do to this is set the priorities of all managed textures low
6871 * and then reset them.
6872 ***********************************************************/
6873 FIXME("(%p) : stub\n", This);
6877 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6879 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6881 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6882 if(surface->Flags & SFLAG_DIBSECTION) {
6883 /* Release the DC */
6884 SelectObject(surface->hDC, surface->dib.holdbitmap);
6885 DeleteDC(surface->hDC);
6886 /* Release the DIB section */
6887 DeleteObject(surface->dib.DIBsection);
6888 surface->dib.bitmap_data = NULL;
6889 surface->resource.allocatedMemory = NULL;
6890 surface->Flags &= ~SFLAG_DIBSECTION;
6892 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6893 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6894 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6895 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6896 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6897 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6899 surface->pow2Width = surface->pow2Height = 1;
6900 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6901 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6903 surface->glRect.left = 0;
6904 surface->glRect.top = 0;
6905 surface->glRect.right = surface->pow2Width;
6906 surface->glRect.bottom = surface->pow2Height;
6908 if(surface->glDescription.textureName) {
6909 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6911 glDeleteTextures(1, &surface->glDescription.textureName);
6913 surface->glDescription.textureName = 0;
6914 surface->Flags &= ~SFLAG_CLIENT;
6916 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6917 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6918 surface->Flags |= SFLAG_NONPOW2;
6920 surface->Flags &= ~SFLAG_NONPOW2;
6922 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6923 surface->resource.allocatedMemory = NULL;
6924 surface->resource.heapMemory = NULL;
6925 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6926 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6927 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6928 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6930 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6934 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6935 TRACE("Unloading resource %p\n", resource);
6936 IWineD3DResource_UnLoad(resource);
6937 IWineD3DResource_Release(resource);
6941 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6944 WINED3DDISPLAYMODE m;
6947 /* All Windowed modes are supported, as is leaving the current mode */
6948 if(pp->Windowed) return TRUE;
6949 if(!pp->BackBufferWidth) return TRUE;
6950 if(!pp->BackBufferHeight) return TRUE;
6952 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6953 for(i = 0; i < count; i++) {
6954 memset(&m, 0, sizeof(m));
6955 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6957 ERR("EnumAdapterModes failed\n");
6959 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6960 /* Mode found, it is supported */
6964 /* Mode not found -> not supported */
6968 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6970 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6972 IWineD3DBaseShaderImpl *shader;
6974 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6975 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6976 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6980 if(This->depth_blt_texture) {
6981 glDeleteTextures(1, &This->depth_blt_texture);
6982 This->depth_blt_texture = 0;
6984 if (This->depth_blt_rb) {
6985 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
6986 This->depth_blt_rb = 0;
6987 This->depth_blt_rb_w = 0;
6988 This->depth_blt_rb_h = 0;
6992 This->blitter->free_private(iface);
6993 This->frag_pipe->free_private(iface);
6994 This->shader_backend->shader_free_private(iface);
6997 for (i = 0; i < GL_LIMITS(textures); i++) {
6998 /* Textures are recreated below */
6999 glDeleteTextures(1, &This->dummyTextureName[i]);
7000 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7001 This->dummyTextureName[i] = 0;
7005 while(This->numContexts) {
7006 DestroyContext(This, This->contexts[0]);
7008 This->activeContext = NULL;
7009 HeapFree(GetProcessHeap(), 0, swapchain->context);
7010 swapchain->context = NULL;
7011 swapchain->num_contexts = 0;
7014 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7016 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7018 IWineD3DSurfaceImpl *target;
7020 /* Recreate the primary swapchain's context */
7021 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7022 if(swapchain->backBuffer) {
7023 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7025 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7027 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7028 &swapchain->presentParms);
7029 swapchain->num_contexts = 1;
7030 This->activeContext = swapchain->context[0];
7032 create_dummy_textures(This);
7034 hr = This->shader_backend->shader_alloc_private(iface);
7036 ERR("Failed to recreate shader private data\n");
7039 hr = This->frag_pipe->alloc_private(iface);
7041 TRACE("Fragment pipeline private data couldn't be allocated\n");
7044 hr = This->blitter->alloc_private(iface);
7046 TRACE("Blitter private data couldn't be allocated\n");
7053 This->blitter->free_private(iface);
7054 This->frag_pipe->free_private(iface);
7055 This->shader_backend->shader_free_private(iface);
7059 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7061 IWineD3DSwapChainImpl *swapchain;
7063 BOOL DisplayModeChanged = FALSE;
7064 WINED3DDISPLAYMODE mode;
7065 TRACE("(%p)\n", This);
7067 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7069 ERR("Failed to get the first implicit swapchain\n");
7073 if(!is_display_mode_supported(This, pPresentationParameters)) {
7074 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7075 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7076 pPresentationParameters->BackBufferHeight);
7077 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7078 return WINED3DERR_INVALIDCALL;
7081 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7082 * on an existing gl context, so there's no real need for recreation.
7084 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7086 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7088 TRACE("New params:\n");
7089 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7090 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7091 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7092 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7093 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7094 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7095 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7096 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7097 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7098 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7099 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7100 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7101 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7103 /* No special treatment of these parameters. Just store them */
7104 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7105 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7106 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7107 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7109 /* What to do about these? */
7110 if(pPresentationParameters->BackBufferCount != 0 &&
7111 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7112 ERR("Cannot change the back buffer count yet\n");
7114 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7115 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7116 ERR("Cannot change the back buffer format yet\n");
7118 if(pPresentationParameters->hDeviceWindow != NULL &&
7119 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7120 ERR("Cannot change the device window yet\n");
7122 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7125 TRACE("Creating the depth stencil buffer\n");
7127 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
7129 pPresentationParameters->BackBufferWidth,
7130 pPresentationParameters->BackBufferHeight,
7131 pPresentationParameters->AutoDepthStencilFormat,
7132 pPresentationParameters->MultiSampleType,
7133 pPresentationParameters->MultiSampleQuality,
7135 &This->auto_depth_stencil_buffer);
7138 ERR("Failed to create the depth stencil buffer\n");
7139 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7140 return WINED3DERR_INVALIDCALL;
7144 /* Reset the depth stencil */
7145 if (pPresentationParameters->EnableAutoDepthStencil)
7146 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7148 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7150 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7152 if(pPresentationParameters->Windowed) {
7153 mode.Width = swapchain->orig_width;
7154 mode.Height = swapchain->orig_height;
7155 mode.RefreshRate = 0;
7156 mode.Format = swapchain->presentParms.BackBufferFormat;
7158 mode.Width = pPresentationParameters->BackBufferWidth;
7159 mode.Height = pPresentationParameters->BackBufferHeight;
7160 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7161 mode.Format = swapchain->presentParms.BackBufferFormat;
7164 /* Should Width == 800 && Height == 0 set 800x600? */
7165 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7166 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7167 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7171 if(!pPresentationParameters->Windowed) {
7172 DisplayModeChanged = TRUE;
7174 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7175 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7177 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7178 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7179 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7181 if(This->auto_depth_stencil_buffer) {
7182 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7186 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7187 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7188 DisplayModeChanged) {
7190 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7192 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7193 if(swapchain->presentParms.Windowed) {
7194 /* switch from windowed to fs */
7195 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7196 pPresentationParameters->BackBufferWidth,
7197 pPresentationParameters->BackBufferHeight);
7199 /* Fullscreen -> fullscreen mode change */
7200 MoveWindow(swapchain->win_handle, 0, 0,
7201 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7204 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7205 /* Fullscreen -> windowed switch */
7206 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7208 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7209 } else if(!pPresentationParameters->Windowed) {
7210 DWORD style = This->style, exStyle = This->exStyle;
7211 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7212 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7213 * Reset to clear up their mess. Guild Wars also loses the device during that.
7217 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7218 pPresentationParameters->BackBufferWidth,
7219 pPresentationParameters->BackBufferHeight);
7220 This->style = style;
7221 This->exStyle = exStyle;
7224 TRACE("Resetting stateblock\n");
7225 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7226 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7228 /* Note: No parent needed for initial internal stateblock */
7229 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7230 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7231 else TRACE("Created stateblock %p\n", This->stateBlock);
7232 This->updateStateBlock = This->stateBlock;
7233 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7235 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7237 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7240 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7241 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7243 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7249 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7251 /** FIXME: always true at the moment **/
7252 if(!bEnableDialogs) {
7253 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7259 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7261 TRACE("(%p) : pParameters %p\n", This, pParameters);
7263 *pParameters = This->createParms;
7267 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7268 IWineD3DSwapChain *swapchain;
7270 TRACE("Relaying to swapchain\n");
7272 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7273 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7274 IWineD3DSwapChain_Release(swapchain);
7279 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7280 IWineD3DSwapChain *swapchain;
7282 TRACE("Relaying to swapchain\n");
7284 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7285 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7286 IWineD3DSwapChain_Release(swapchain);
7292 /** ********************************************************
7293 * Notification functions
7294 ** ********************************************************/
7295 /** This function must be called in the release of a resource when ref == 0,
7296 * the contents of resource must still be correct,
7297 * any handles to other resource held by the caller must be closed
7298 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7299 *****************************************************/
7300 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7302 TRACE("(%p) : Adding resource %p\n", This, resource);
7304 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7307 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7309 TRACE("(%p) : Removing resource %p\n", This, resource);
7311 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7314 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7316 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7319 TRACE("(%p) : resource %p\n", This, resource);
7321 context_resource_released((IWineD3DDevice *)This, resource, type);
7324 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7325 case WINED3DRTYPE_SURFACE: {
7328 /* Cleanup any FBO attachments if d3d is enabled */
7329 if(This->d3d_initialized) {
7330 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7331 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7333 TRACE("Last active render target destroyed\n");
7334 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7335 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7336 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7337 * and the lastActiveRenderTarget member shouldn't matter
7340 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7341 TRACE("Activating primary back buffer\n");
7342 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7343 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7344 /* Single buffering environment */
7345 TRACE("Activating primary front buffer\n");
7346 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7348 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7349 /* Implicit render target destroyed, that means the device is being destroyed
7350 * whatever we set here, it shouldn't matter
7352 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7355 /* May happen during ddraw uninitialization */
7356 TRACE("Render target set, but swapchain does not exist!\n");
7357 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7361 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7362 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7363 This->render_targets[i] = NULL;
7366 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7367 This->stencilBufferTarget = NULL;
7373 case WINED3DRTYPE_TEXTURE:
7374 case WINED3DRTYPE_CUBETEXTURE:
7375 case WINED3DRTYPE_VOLUMETEXTURE:
7376 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7377 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7378 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7379 This->stateBlock->textures[counter] = NULL;
7381 if (This->updateStateBlock != This->stateBlock ){
7382 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7383 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7384 This->updateStateBlock->textures[counter] = NULL;
7389 case WINED3DRTYPE_VOLUME:
7390 /* TODO: nothing really? */
7392 case WINED3DRTYPE_BUFFER:
7395 TRACE("Cleaning up stream pointers\n");
7397 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7398 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7399 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7401 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7402 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7403 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7404 This->updateStateBlock->streamSource[streamNumber] = 0;
7405 /* Set changed flag? */
7408 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) */
7409 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7410 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7411 This->stateBlock->streamSource[streamNumber] = 0;
7416 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7417 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7418 This->updateStateBlock->pIndexData = NULL;
7421 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7422 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7423 This->stateBlock->pIndexData = NULL;
7430 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7435 /* Remove the resource from the resourceStore */
7436 device_resource_remove(This, resource);
7438 TRACE("Resource released\n");
7442 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7444 IWineD3DResourceImpl *resource, *cursor;
7446 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7448 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7449 TRACE("enumerating resource %p\n", resource);
7450 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7451 ret = pCallback((IWineD3DResource *) resource, pData);
7452 if(ret == S_FALSE) {
7453 TRACE("Canceling enumeration\n");
7460 /**********************************************************
7461 * IWineD3DDevice VTbl follows
7462 **********************************************************/
7464 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7466 /*** IUnknown methods ***/
7467 IWineD3DDeviceImpl_QueryInterface,
7468 IWineD3DDeviceImpl_AddRef,
7469 IWineD3DDeviceImpl_Release,
7470 /*** IWineD3DDevice methods ***/
7471 IWineD3DDeviceImpl_GetParent,
7472 /*** Creation methods**/
7473 IWineD3DDeviceImpl_CreateBuffer,
7474 IWineD3DDeviceImpl_CreateVertexBuffer,
7475 IWineD3DDeviceImpl_CreateIndexBuffer,
7476 IWineD3DDeviceImpl_CreateStateBlock,
7477 IWineD3DDeviceImpl_CreateSurface,
7478 IWineD3DDeviceImpl_CreateRendertargetView,
7479 IWineD3DDeviceImpl_CreateTexture,
7480 IWineD3DDeviceImpl_CreateVolumeTexture,
7481 IWineD3DDeviceImpl_CreateVolume,
7482 IWineD3DDeviceImpl_CreateCubeTexture,
7483 IWineD3DDeviceImpl_CreateQuery,
7484 IWineD3DDeviceImpl_CreateSwapChain,
7485 IWineD3DDeviceImpl_CreateVertexDeclaration,
7486 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7487 IWineD3DDeviceImpl_CreateVertexShader,
7488 IWineD3DDeviceImpl_CreatePixelShader,
7489 IWineD3DDeviceImpl_CreatePalette,
7490 /*** Odd functions **/
7491 IWineD3DDeviceImpl_Init3D,
7492 IWineD3DDeviceImpl_InitGDI,
7493 IWineD3DDeviceImpl_Uninit3D,
7494 IWineD3DDeviceImpl_UninitGDI,
7495 IWineD3DDeviceImpl_SetMultithreaded,
7496 IWineD3DDeviceImpl_EvictManagedResources,
7497 IWineD3DDeviceImpl_GetAvailableTextureMem,
7498 IWineD3DDeviceImpl_GetBackBuffer,
7499 IWineD3DDeviceImpl_GetCreationParameters,
7500 IWineD3DDeviceImpl_GetDeviceCaps,
7501 IWineD3DDeviceImpl_GetDirect3D,
7502 IWineD3DDeviceImpl_GetDisplayMode,
7503 IWineD3DDeviceImpl_SetDisplayMode,
7504 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7505 IWineD3DDeviceImpl_GetRasterStatus,
7506 IWineD3DDeviceImpl_GetSwapChain,
7507 IWineD3DDeviceImpl_Reset,
7508 IWineD3DDeviceImpl_SetDialogBoxMode,
7509 IWineD3DDeviceImpl_SetCursorProperties,
7510 IWineD3DDeviceImpl_SetCursorPosition,
7511 IWineD3DDeviceImpl_ShowCursor,
7512 IWineD3DDeviceImpl_TestCooperativeLevel,
7513 /*** Getters and setters **/
7514 IWineD3DDeviceImpl_SetClipPlane,
7515 IWineD3DDeviceImpl_GetClipPlane,
7516 IWineD3DDeviceImpl_SetClipStatus,
7517 IWineD3DDeviceImpl_GetClipStatus,
7518 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7519 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7520 IWineD3DDeviceImpl_SetDepthStencilSurface,
7521 IWineD3DDeviceImpl_GetDepthStencilSurface,
7522 IWineD3DDeviceImpl_SetGammaRamp,
7523 IWineD3DDeviceImpl_GetGammaRamp,
7524 IWineD3DDeviceImpl_SetIndices,
7525 IWineD3DDeviceImpl_GetIndices,
7526 IWineD3DDeviceImpl_SetBaseVertexIndex,
7527 IWineD3DDeviceImpl_GetBaseVertexIndex,
7528 IWineD3DDeviceImpl_SetLight,
7529 IWineD3DDeviceImpl_GetLight,
7530 IWineD3DDeviceImpl_SetLightEnable,
7531 IWineD3DDeviceImpl_GetLightEnable,
7532 IWineD3DDeviceImpl_SetMaterial,
7533 IWineD3DDeviceImpl_GetMaterial,
7534 IWineD3DDeviceImpl_SetNPatchMode,
7535 IWineD3DDeviceImpl_GetNPatchMode,
7536 IWineD3DDeviceImpl_SetPaletteEntries,
7537 IWineD3DDeviceImpl_GetPaletteEntries,
7538 IWineD3DDeviceImpl_SetPixelShader,
7539 IWineD3DDeviceImpl_GetPixelShader,
7540 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7541 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7542 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7543 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7544 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7545 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7546 IWineD3DDeviceImpl_SetRenderState,
7547 IWineD3DDeviceImpl_GetRenderState,
7548 IWineD3DDeviceImpl_SetRenderTarget,
7549 IWineD3DDeviceImpl_GetRenderTarget,
7550 IWineD3DDeviceImpl_SetFrontBackBuffers,
7551 IWineD3DDeviceImpl_SetSamplerState,
7552 IWineD3DDeviceImpl_GetSamplerState,
7553 IWineD3DDeviceImpl_SetScissorRect,
7554 IWineD3DDeviceImpl_GetScissorRect,
7555 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7556 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7557 IWineD3DDeviceImpl_SetStreamSource,
7558 IWineD3DDeviceImpl_GetStreamSource,
7559 IWineD3DDeviceImpl_SetStreamSourceFreq,
7560 IWineD3DDeviceImpl_GetStreamSourceFreq,
7561 IWineD3DDeviceImpl_SetTexture,
7562 IWineD3DDeviceImpl_GetTexture,
7563 IWineD3DDeviceImpl_SetTextureStageState,
7564 IWineD3DDeviceImpl_GetTextureStageState,
7565 IWineD3DDeviceImpl_SetTransform,
7566 IWineD3DDeviceImpl_GetTransform,
7567 IWineD3DDeviceImpl_SetVertexDeclaration,
7568 IWineD3DDeviceImpl_GetVertexDeclaration,
7569 IWineD3DDeviceImpl_SetVertexShader,
7570 IWineD3DDeviceImpl_GetVertexShader,
7571 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7572 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7573 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7574 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7575 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7576 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7577 IWineD3DDeviceImpl_SetViewport,
7578 IWineD3DDeviceImpl_GetViewport,
7579 IWineD3DDeviceImpl_MultiplyTransform,
7580 IWineD3DDeviceImpl_ValidateDevice,
7581 IWineD3DDeviceImpl_ProcessVertices,
7582 /*** State block ***/
7583 IWineD3DDeviceImpl_BeginStateBlock,
7584 IWineD3DDeviceImpl_EndStateBlock,
7585 /*** Scene management ***/
7586 IWineD3DDeviceImpl_BeginScene,
7587 IWineD3DDeviceImpl_EndScene,
7588 IWineD3DDeviceImpl_Present,
7589 IWineD3DDeviceImpl_Clear,
7590 IWineD3DDeviceImpl_ClearRendertargetView,
7592 IWineD3DDeviceImpl_SetPrimitiveType,
7593 IWineD3DDeviceImpl_GetPrimitiveType,
7594 IWineD3DDeviceImpl_DrawPrimitive,
7595 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7596 IWineD3DDeviceImpl_DrawPrimitiveUP,
7597 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7598 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7599 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7600 IWineD3DDeviceImpl_DrawRectPatch,
7601 IWineD3DDeviceImpl_DrawTriPatch,
7602 IWineD3DDeviceImpl_DeletePatch,
7603 IWineD3DDeviceImpl_ColorFill,
7604 IWineD3DDeviceImpl_UpdateTexture,
7605 IWineD3DDeviceImpl_UpdateSurface,
7606 IWineD3DDeviceImpl_GetFrontBufferData,
7607 /*** object tracking ***/
7608 IWineD3DDeviceImpl_EnumResources
7611 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7612 WINED3DRS_ALPHABLENDENABLE ,
7613 WINED3DRS_ALPHAFUNC ,
7614 WINED3DRS_ALPHAREF ,
7615 WINED3DRS_ALPHATESTENABLE ,
7617 WINED3DRS_COLORWRITEENABLE ,
7618 WINED3DRS_DESTBLEND ,
7619 WINED3DRS_DITHERENABLE ,
7620 WINED3DRS_FILLMODE ,
7621 WINED3DRS_FOGDENSITY ,
7623 WINED3DRS_FOGSTART ,
7624 WINED3DRS_LASTPIXEL ,
7625 WINED3DRS_SHADEMODE ,
7626 WINED3DRS_SRCBLEND ,
7627 WINED3DRS_STENCILENABLE ,
7628 WINED3DRS_STENCILFAIL ,
7629 WINED3DRS_STENCILFUNC ,
7630 WINED3DRS_STENCILMASK ,
7631 WINED3DRS_STENCILPASS ,
7632 WINED3DRS_STENCILREF ,
7633 WINED3DRS_STENCILWRITEMASK ,
7634 WINED3DRS_STENCILZFAIL ,
7635 WINED3DRS_TEXTUREFACTOR ,
7646 WINED3DRS_ZWRITEENABLE
7649 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7650 WINED3DTSS_ALPHAARG0 ,
7651 WINED3DTSS_ALPHAARG1 ,
7652 WINED3DTSS_ALPHAARG2 ,
7653 WINED3DTSS_ALPHAOP ,
7654 WINED3DTSS_BUMPENVLOFFSET ,
7655 WINED3DTSS_BUMPENVLSCALE ,
7656 WINED3DTSS_BUMPENVMAT00 ,
7657 WINED3DTSS_BUMPENVMAT01 ,
7658 WINED3DTSS_BUMPENVMAT10 ,
7659 WINED3DTSS_BUMPENVMAT11 ,
7660 WINED3DTSS_COLORARG0 ,
7661 WINED3DTSS_COLORARG1 ,
7662 WINED3DTSS_COLORARG2 ,
7663 WINED3DTSS_COLOROP ,
7664 WINED3DTSS_RESULTARG ,
7665 WINED3DTSS_TEXCOORDINDEX ,
7666 WINED3DTSS_TEXTURETRANSFORMFLAGS
7669 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7670 WINED3DSAMP_ADDRESSU ,
7671 WINED3DSAMP_ADDRESSV ,
7672 WINED3DSAMP_ADDRESSW ,
7673 WINED3DSAMP_BORDERCOLOR ,
7674 WINED3DSAMP_MAGFILTER ,
7675 WINED3DSAMP_MINFILTER ,
7676 WINED3DSAMP_MIPFILTER ,
7677 WINED3DSAMP_MIPMAPLODBIAS ,
7678 WINED3DSAMP_MAXMIPLEVEL ,
7679 WINED3DSAMP_MAXANISOTROPY ,
7680 WINED3DSAMP_SRGBTEXTURE ,
7681 WINED3DSAMP_ELEMENTINDEX
7684 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7686 WINED3DRS_AMBIENTMATERIALSOURCE ,
7687 WINED3DRS_CLIPPING ,
7688 WINED3DRS_CLIPPLANEENABLE ,
7689 WINED3DRS_COLORVERTEX ,
7690 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7691 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7692 WINED3DRS_FOGDENSITY ,
7694 WINED3DRS_FOGSTART ,
7695 WINED3DRS_FOGTABLEMODE ,
7696 WINED3DRS_FOGVERTEXMODE ,
7697 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7698 WINED3DRS_LIGHTING ,
7699 WINED3DRS_LOCALVIEWER ,
7700 WINED3DRS_MULTISAMPLEANTIALIAS ,
7701 WINED3DRS_MULTISAMPLEMASK ,
7702 WINED3DRS_NORMALIZENORMALS ,
7703 WINED3DRS_PATCHEDGESTYLE ,
7704 WINED3DRS_POINTSCALE_A ,
7705 WINED3DRS_POINTSCALE_B ,
7706 WINED3DRS_POINTSCALE_C ,
7707 WINED3DRS_POINTSCALEENABLE ,
7708 WINED3DRS_POINTSIZE ,
7709 WINED3DRS_POINTSIZE_MAX ,
7710 WINED3DRS_POINTSIZE_MIN ,
7711 WINED3DRS_POINTSPRITEENABLE ,
7712 WINED3DRS_RANGEFOGENABLE ,
7713 WINED3DRS_SPECULARMATERIALSOURCE ,
7714 WINED3DRS_TWEENFACTOR ,
7715 WINED3DRS_VERTEXBLEND ,
7716 WINED3DRS_CULLMODE ,
7720 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7721 WINED3DTSS_TEXCOORDINDEX ,
7722 WINED3DTSS_TEXTURETRANSFORMFLAGS
7725 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7726 WINED3DSAMP_DMAPOFFSET
7729 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7730 DWORD rep = This->StateTable[state].representative;
7734 WineD3DContext *context;
7737 for(i = 0; i < This->numContexts; i++) {
7738 context = This->contexts[i];
7739 if(isStateDirty(context, rep)) continue;
7741 context->dirtyArray[context->numDirtyEntries++] = rep;
7744 context->isStateDirty[idx] |= (1 << shift);
7748 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7749 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7750 /* The drawable size of a pbuffer render target is the current pbuffer size
7752 *width = dev->pbufferWidth;
7753 *height = dev->pbufferHeight;
7756 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7757 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7759 *width = This->pow2Width;
7760 *height = This->pow2Height;
7763 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7764 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7765 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7766 * current context's drawable, which is the size of the back buffer of the swapchain
7767 * the active context belongs to. The back buffer of the swapchain is stored as the
7768 * surface the context belongs to.
7770 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7771 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;