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 /* Context activation is done by the caller. */
170 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
171 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
173 /* We need to deal with frequency data! */
174 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
175 UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
176 const DWORD *streams = declaration->streams;
179 memset(stream_info, 0, sizeof(*stream_info));
181 /* Check for transformed vertices, disable vertex shader if present. */
182 stream_info->position_transformed = declaration->position_transformed;
183 if (declaration->position_transformed) use_vshader = FALSE;
185 /* Translate the declaration into strided data. */
186 for (i = 0; i < declaration->element_count; ++i)
188 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
189 GLuint buffer_object = 0;
190 const BYTE *data = NULL;
195 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
196 element, i + 1, declaration->element_count);
198 if (!This->stateBlock->streamSource[element->input_slot]) continue;
200 stride = This->stateBlock->streamStride[element->input_slot];
201 if (This->stateBlock->streamIsUP)
203 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
205 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
209 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
210 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
212 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
213 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
214 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
215 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
216 * not, drawStridedSlow is needed, including a vertex buffer path. */
217 if (This->stateBlock->loadBaseVertexIndex < 0)
219 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
221 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
222 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
224 FIXME("System memory vertex data load offset is negative!\n");
230 if (buffer_object) *fixup = TRUE;
231 else if (*fixup && !use_vshader
232 && (element->usage == WINED3DDECLUSAGE_COLOR
233 || element->usage == WINED3DDECLUSAGE_POSITIONT))
235 static BOOL warned = FALSE;
238 /* This may be bad with the fixed function pipeline. */
239 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
245 data += element->offset;
247 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
251 if (element->output_slot == ~0U)
253 /* TODO: Assuming vertexdeclarations are usually used with the
254 * same or a similar shader, it might be worth it to store the
255 * last used output slot and try that one first. */
256 stride_used = vshader_get_input(This->stateBlock->vertexShader,
257 element->usage, element->usage_idx, &idx);
261 idx = element->output_slot;
267 if (!element->ffp_valid)
269 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
270 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
275 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
281 TRACE("Load %s array %u [usage %s, usage_idx %u, "
282 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
283 use_vshader ? "shader": "fixed function", idx,
284 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
285 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
287 stream_info->elements[idx].format_desc = element->format_desc;
288 stream_info->elements[idx].stride = stride;
289 stream_info->elements[idx].data = data;
290 stream_info->elements[idx].stream_idx = element->input_slot;
291 stream_info->elements[idx].buffer_object = buffer_object;
293 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && element->format_desc->format == WINED3DFMT_A8R8G8B8)
295 stream_info->swizzle_map |= 1 << idx;
297 stream_info->use_map |= 1 << idx;
301 /* Now call PreLoad on all the vertex buffers. In the very rare case
302 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
303 * The vertex buffer can now use the strided structure in the device instead of finding its
306 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
308 for (i = 0; i < stream_count; ++i)
310 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
311 if (vb) IWineD3DBuffer_PreLoad(vb);
315 static void stream_info_element_from_strided(IWineD3DDeviceImpl *This,
316 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
318 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, &This->adapter->gl_info);
319 e->format_desc = format_desc;
320 e->stride = strided->dwStride;
321 e->data = strided->lpData;
323 e->buffer_object = 0;
326 void device_stream_info_from_strided(IWineD3DDeviceImpl *This,
327 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
331 memset(stream_info, 0, sizeof(*stream_info));
333 if (strided->position.lpData)
334 stream_info_element_from_strided(This, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
335 if (strided->normal.lpData)
336 stream_info_element_from_strided(This, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
337 if (strided->diffuse.lpData)
338 stream_info_element_from_strided(This, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
339 if (strided->specular.lpData)
340 stream_info_element_from_strided(This, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
342 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
344 if (strided->texCoords[i].lpData)
345 stream_info_element_from_strided(This, &strided->texCoords[i],
346 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
349 stream_info->position_transformed = strided->position_transformed;
351 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
353 if (!stream_info->elements[i].format_desc) continue;
355 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && stream_info->elements[i].format_desc->format == WINED3DFMT_A8R8G8B8)
357 stream_info->swizzle_map |= 1 << i;
359 stream_info->use_map |= 1 << i;
363 /**********************************************************
364 * IUnknown parts follows
365 **********************************************************/
367 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
371 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
372 if (IsEqualGUID(riid, &IID_IUnknown)
373 || IsEqualGUID(riid, &IID_IWineD3DBase)
374 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
375 IUnknown_AddRef(iface);
380 return E_NOINTERFACE;
383 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
385 ULONG refCount = InterlockedIncrement(&This->ref);
387 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
391 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
393 ULONG refCount = InterlockedDecrement(&This->ref);
395 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
400 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
401 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
402 This->multistate_funcs[i] = NULL;
405 /* TODO: Clean up all the surfaces and textures! */
406 /* NOTE: You must release the parent if the object was created via a callback
407 ** ***************************/
409 if (!list_empty(&This->resources)) {
410 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
411 dumpResources(&This->resources);
414 if(This->contexts) ERR("Context array not freed!\n");
415 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
416 This->haveHardwareCursor = FALSE;
418 IWineD3D_Release(This->wineD3D);
419 This->wineD3D = NULL;
420 HeapFree(GetProcessHeap(), 0, This);
421 TRACE("Freed device %p\n", This);
427 /**********************************************************
428 * IWineD3DDevice implementation follows
429 **********************************************************/
430 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
432 *pParent = This->parent;
433 IUnknown_AddRef(This->parent);
437 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface,
438 struct wined3d_buffer_desc *desc, const void *data, IUnknown *parent, IWineD3DBuffer **buffer)
440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
441 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_UNKNOWN, &This->adapter->gl_info);
442 struct wined3d_buffer *object;
445 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
447 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
450 ERR("Failed to allocate memory\n");
451 return E_OUTOFMEMORY;
454 object->vtbl = &wined3d_buffer_vtbl;
455 object->desc = *desc;
457 FIXME("Ignoring access flags (pool)\n");
459 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, desc->byte_width,
460 desc->usage, format_desc, WINED3DPOOL_MANAGED, parent);
463 WARN("Failed to initialize resource, returning %#x\n", hr);
464 HeapFree(GetProcessHeap(), 0, object);
467 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
469 TRACE("Created resource %p\n", object);
471 TRACE("size %#x, usage=%#x, format %s, memory @ %p, iface @ %p\n", object->resource.size, object->resource.usage,
472 debug_d3dformat(object->resource.format_desc->format), object->resource.allocatedMemory, object);
478 hr = IWineD3DBuffer_Map((IWineD3DBuffer *)object, 0, desc->byte_width, &ptr, 0);
481 ERR("Failed to map buffer, hr %#x\n", hr);
482 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
486 memcpy(ptr, data, desc->byte_width);
488 hr = IWineD3DBuffer_Unmap((IWineD3DBuffer *)object);
491 ERR("Failed to unmap buffer, hr %#x\n", hr);
492 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
497 *buffer = (IWineD3DBuffer *)object;
502 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
503 DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer, IUnknown *parent)
505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
506 /* Dummy format for now */
507 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_VERTEXDATA, &This->adapter->gl_info);
508 struct wined3d_buffer *object;
509 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
514 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
515 *ppVertexBuffer = NULL;
516 return WINED3DERR_INVALIDCALL;
517 } else if(Pool == WINED3DPOOL_SCRATCH) {
518 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
519 * anyway, SCRATCH vertex buffers aren't usable anywhere
521 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
522 *ppVertexBuffer = NULL;
523 return WINED3DERR_INVALIDCALL;
526 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
529 ERR("Out of memory\n");
530 *ppVertexBuffer = NULL;
531 return WINED3DERR_OUTOFVIDEOMEMORY;
534 object->vtbl = &wined3d_buffer_vtbl;
535 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, Size, Usage, format_desc, Pool, parent);
538 WARN("Failed to initialize resource, returning %#x\n", hr);
539 HeapFree(GetProcessHeap(), 0, object);
540 *ppVertexBuffer = NULL;
543 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
545 TRACE("(%p) : Created resource %p\n", This, object);
547 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);
548 *ppVertexBuffer = (IWineD3DBuffer *)object;
550 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
551 * drawStridedFast (half-life 2).
553 * Basically converting the vertices in the buffer is quite expensive, and observations
554 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
555 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
557 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
558 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
559 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
560 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
562 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
563 * more. In this call we can convert dx7 buffers too.
565 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
566 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
567 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
568 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
569 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
570 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
571 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
572 } else if(dxVersion <= 7 && conv) {
573 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
575 object->flags |= WINED3D_BUFFER_CREATEBO;
580 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
581 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer, IUnknown *parent)
583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
584 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_UNKNOWN, &This->adapter->gl_info);
585 struct wined3d_buffer *object;
588 TRACE("(%p) Creating index buffer\n", This);
590 /* Allocate the storage for the device */
591 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
594 ERR("Out of memory\n");
595 *ppIndexBuffer = NULL;
596 return WINED3DERR_OUTOFVIDEOMEMORY;
599 object->vtbl = &wined3d_buffer_vtbl;
600 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, Length, Usage, format_desc, Pool, parent);
603 WARN("Failed to initialize resource, returning %#x\n", hr);
604 HeapFree(GetProcessHeap(), 0, object);
605 *ppIndexBuffer = NULL;
608 object->buffer_type_hint = GL_ELEMENT_ARRAY_BUFFER_ARB;
610 TRACE("(%p) : Created resource %p\n", This, object);
612 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
613 object->flags |= WINED3D_BUFFER_CREATEBO;
616 TRACE("(%p) : Len=%d, Use=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage,
617 Pool, object, object->resource.allocatedMemory);
618 *ppIndexBuffer = (IWineD3DBuffer *) object;
623 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
626 IWineD3DStateBlockImpl *object;
630 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
633 ERR("Out of memory\n");
634 *ppStateBlock = NULL;
635 return WINED3DERR_OUTOFVIDEOMEMORY;
638 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
639 object->wineD3DDevice = This;
640 object->parent = parent;
642 object->blockType = Type;
644 *ppStateBlock = (IWineD3DStateBlock *)object;
646 for(i = 0; i < LIGHTMAP_SIZE; i++) {
647 list_init(&object->lightMap[i]);
650 temp_result = allocate_shader_constants(object);
651 if (FAILED(temp_result))
653 HeapFree(GetProcessHeap(), 0, object);
657 /* Special case - Used during initialization to produce a placeholder stateblock
658 so other functions called can update a state block */
659 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
661 /* Don't bother increasing the reference count otherwise a device will never
662 be freed due to circular dependencies */
666 /* Otherwise, might as well set the whole state block to the appropriate values */
667 if (This->stateBlock != NULL)
668 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
670 memset(object->streamFreq, 1, sizeof(object->streamFreq));
672 /* Reset the ref and type after kludging it */
673 object->wineD3DDevice = This;
675 object->blockType = Type;
677 TRACE("Updating changed flags appropriate for type %d\n", Type);
679 if (Type == WINED3DSBT_ALL) {
681 TRACE("ALL => Pretend everything has changed\n");
682 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
684 /* Lights are not part of the changed / set structure */
685 for(j = 0; j < LIGHTMAP_SIZE; j++) {
687 LIST_FOR_EACH(e, &object->lightMap[j]) {
688 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
689 light->changed = TRUE;
690 light->enabledChanged = TRUE;
693 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
694 object->contained_render_states[j - 1] = j;
696 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
697 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
698 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
699 object->contained_transform_states[j - 1] = j;
701 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
702 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
703 object->contained_vs_consts_f[j] = j;
705 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
706 for(j = 0; j < MAX_CONST_I; j++) {
707 object->contained_vs_consts_i[j] = j;
709 object->num_contained_vs_consts_i = MAX_CONST_I;
710 for(j = 0; j < MAX_CONST_B; j++) {
711 object->contained_vs_consts_b[j] = j;
713 object->num_contained_vs_consts_b = MAX_CONST_B;
714 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
715 object->contained_ps_consts_f[j] = j;
717 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
718 for(j = 0; j < MAX_CONST_I; j++) {
719 object->contained_ps_consts_i[j] = j;
721 object->num_contained_ps_consts_i = MAX_CONST_I;
722 for(j = 0; j < MAX_CONST_B; j++) {
723 object->contained_ps_consts_b[j] = j;
725 object->num_contained_ps_consts_b = MAX_CONST_B;
726 for(i = 0; i < MAX_TEXTURES; i++) {
727 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
729 object->contained_tss_states[object->num_contained_tss_states].stage = i;
730 object->contained_tss_states[object->num_contained_tss_states].state = j;
731 object->num_contained_tss_states++;
734 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
735 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
736 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
737 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
738 object->num_contained_sampler_states++;
742 for(i = 0; i < MAX_STREAMS; i++) {
743 if(object->streamSource[i]) {
744 IWineD3DBuffer_AddRef(object->streamSource[i]);
747 if(object->pIndexData) {
748 IWineD3DBuffer_AddRef(object->pIndexData);
750 if(object->vertexShader) {
751 IWineD3DVertexShader_AddRef(object->vertexShader);
753 if(object->pixelShader) {
754 IWineD3DPixelShader_AddRef(object->pixelShader);
757 } else if (Type == WINED3DSBT_PIXELSTATE) {
759 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
760 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
762 object->changed.pixelShader = TRUE;
764 /* Pixel Shader Constants */
765 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
766 object->contained_ps_consts_f[i] = i;
767 object->changed.pixelShaderConstantsF[i] = TRUE;
769 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
770 for (i = 0; i < MAX_CONST_B; ++i) {
771 object->contained_ps_consts_b[i] = i;
772 object->changed.pixelShaderConstantsB |= (1 << i);
774 object->num_contained_ps_consts_b = MAX_CONST_B;
775 for (i = 0; i < MAX_CONST_I; ++i) {
776 object->contained_ps_consts_i[i] = i;
777 object->changed.pixelShaderConstantsI |= (1 << i);
779 object->num_contained_ps_consts_i = MAX_CONST_I;
781 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
782 DWORD rs = SavedPixelStates_R[i];
783 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
784 object->contained_render_states[i] = rs;
786 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
787 for (j = 0; j < MAX_TEXTURES; j++) {
788 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
789 DWORD state = SavedPixelStates_T[i];
790 object->changed.textureState[j] |= 1 << state;
791 object->contained_tss_states[object->num_contained_tss_states].stage = j;
792 object->contained_tss_states[object->num_contained_tss_states].state = state;
793 object->num_contained_tss_states++;
796 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
797 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
798 DWORD state = SavedPixelStates_S[i];
799 object->changed.samplerState[j] |= 1 << state;
800 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
801 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
802 object->num_contained_sampler_states++;
805 if(object->pixelShader) {
806 IWineD3DPixelShader_AddRef(object->pixelShader);
809 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
810 * on them. This makes releasing the buffer easier
812 for(i = 0; i < MAX_STREAMS; i++) {
813 object->streamSource[i] = NULL;
815 object->pIndexData = NULL;
816 object->vertexShader = NULL;
818 } else if (Type == WINED3DSBT_VERTEXSTATE) {
820 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
821 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
823 object->changed.vertexShader = TRUE;
825 /* Vertex Shader Constants */
826 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
827 object->changed.vertexShaderConstantsF[i] = TRUE;
828 object->contained_vs_consts_f[i] = i;
830 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
831 for (i = 0; i < MAX_CONST_B; ++i) {
832 object->contained_vs_consts_b[i] = i;
833 object->changed.vertexShaderConstantsB |= (1 << i);
835 object->num_contained_vs_consts_b = MAX_CONST_B;
836 for (i = 0; i < MAX_CONST_I; ++i) {
837 object->contained_vs_consts_i[i] = i;
838 object->changed.vertexShaderConstantsI |= (1 << i);
840 object->num_contained_vs_consts_i = MAX_CONST_I;
841 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
842 DWORD rs = SavedVertexStates_R[i];
843 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
844 object->contained_render_states[i] = rs;
846 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
847 for (j = 0; j < MAX_TEXTURES; j++) {
848 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
849 DWORD state = SavedVertexStates_T[i];
850 object->changed.textureState[j] |= 1 << state;
851 object->contained_tss_states[object->num_contained_tss_states].stage = j;
852 object->contained_tss_states[object->num_contained_tss_states].state = state;
853 object->num_contained_tss_states++;
856 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
857 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
858 DWORD state = SavedVertexStates_S[i];
859 object->changed.samplerState[j] |= 1 << state;
860 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
861 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
862 object->num_contained_sampler_states++;
866 for(j = 0; j < LIGHTMAP_SIZE; j++) {
868 LIST_FOR_EACH(e, &object->lightMap[j]) {
869 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
870 light->changed = TRUE;
871 light->enabledChanged = TRUE;
875 for(i = 0; i < MAX_STREAMS; i++) {
876 if(object->streamSource[i]) {
877 IWineD3DBuffer_AddRef(object->streamSource[i]);
880 if(object->vertexShader) {
881 IWineD3DVertexShader_AddRef(object->vertexShader);
883 object->pIndexData = NULL;
884 object->pixelShader = NULL;
886 FIXME("Unrecognized state block type %d\n", Type);
889 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
893 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
894 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
895 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
896 WINED3DSURFTYPE Impl, IUnknown *parent)
898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
899 IWineD3DSurfaceImpl *object;
902 TRACE("(%p) Create surface\n",This);
904 if (Impl == SURFACE_OPENGL && !This->adapter)
906 ERR("OpenGL surfaces are not available without OpenGL.\n");
907 return WINED3DERR_NOTAVAILABLE;
910 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
913 ERR("Failed to allocate surface memory.\n");
915 return WINED3DERR_OUTOFVIDEOMEMORY;
918 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
919 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent);
922 WARN("Failed to initialize surface, returning %#x.\n", hr);
923 HeapFree(GetProcessHeap(), 0, object);
928 TRACE("(%p) : Created surface %p\n", This, object);
930 *ppSurface = (IWineD3DSurface *)object;
935 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
936 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
938 struct wined3d_rendertarget_view *object;
940 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
943 ERR("Failed to allocate memory\n");
944 return E_OUTOFMEMORY;
947 object->vtbl = &wined3d_rendertarget_view_vtbl;
948 object->refcount = 1;
949 IWineD3DResource_AddRef(resource);
950 object->resource = resource;
951 object->parent = parent;
953 *rendertarget_view = (IWineD3DRendertargetView *)object;
958 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
959 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
960 WINED3DPOOL Pool, IWineD3DTexture **ppTexture, IUnknown *parent)
962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
963 IWineD3DTextureImpl *object;
966 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
967 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
968 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
970 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
973 ERR("Out of memory\n");
975 return WINED3DERR_OUTOFVIDEOMEMORY;
978 object->lpVtbl = &IWineD3DTexture_Vtbl;
980 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent);
983 WARN("Failed to initialize texture, returning %#x\n", hr);
984 HeapFree(GetProcessHeap(), 0, object);
989 *ppTexture = (IWineD3DTexture *)object;
991 TRACE("(%p) : Created texture %p\n", This, object);
996 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
997 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
998 WINED3DPOOL Pool, IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent)
1000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1001 IWineD3DVolumeTextureImpl *object;
1004 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1005 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1007 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1010 ERR("Out of memory\n");
1011 *ppVolumeTexture = NULL;
1012 return WINED3DERR_OUTOFVIDEOMEMORY;
1015 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1016 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent);
1019 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1020 HeapFree(GetProcessHeap(), 0, object);
1021 *ppVolumeTexture = NULL;
1025 TRACE("(%p) : Created volume texture %p.\n", This, object);
1026 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1031 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1032 UINT Width, UINT Height, UINT Depth, DWORD Usage, WINED3DFORMAT Format,
1033 WINED3DPOOL Pool, IWineD3DVolume **ppVolume, IUnknown *parent)
1035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1036 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1037 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &GLINFO_LOCATION);
1040 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1041 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1042 return WINED3DERR_INVALIDCALL;
1045 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1048 ERR("Out of memory\n");
1050 return WINED3DERR_OUTOFVIDEOMEMORY;
1053 object->lpVtbl = &IWineD3DVolume_Vtbl;
1054 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_VOLUME, This,
1055 Width * Height * Depth * format_desc->byte_count, Usage, format_desc, Pool, parent);
1058 WARN("Failed to initialize resource, returning %#x\n", hr);
1059 HeapFree(GetProcessHeap(), 0, object);
1064 TRACE("(%p) : Created resource %p\n", This, object);
1066 *ppVolume = (IWineD3DVolume *)object;
1068 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1069 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1071 object->currentDesc.Width = Width;
1072 object->currentDesc.Height = Height;
1073 object->currentDesc.Depth = Depth;
1075 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1076 object->lockable = TRUE;
1077 object->locked = FALSE;
1078 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1079 object->dirty = TRUE;
1081 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1086 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1087 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1088 WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture, IUnknown *parent)
1090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1091 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1094 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1097 ERR("Out of memory\n");
1098 *ppCubeTexture = NULL;
1099 return WINED3DERR_OUTOFVIDEOMEMORY;
1102 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1103 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent);
1106 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1107 HeapFree(GetProcessHeap(), 0, object);
1108 *ppCubeTexture = NULL;
1112 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1113 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1118 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1120 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1121 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1122 const IWineD3DQueryVtbl *vtable;
1124 /* Just a check to see if we support this type of query */
1126 case WINED3DQUERYTYPE_OCCLUSION:
1127 TRACE("(%p) occlusion query\n", This);
1128 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1131 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1133 vtable = &IWineD3DOcclusionQuery_Vtbl;
1136 case WINED3DQUERYTYPE_EVENT:
1137 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1138 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1139 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1141 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1143 vtable = &IWineD3DEventQuery_Vtbl;
1147 case WINED3DQUERYTYPE_VCACHE:
1148 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1149 case WINED3DQUERYTYPE_VERTEXSTATS:
1150 case WINED3DQUERYTYPE_TIMESTAMP:
1151 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1152 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1153 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1154 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1155 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1156 case WINED3DQUERYTYPE_PIXELTIMINGS:
1157 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1158 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1160 /* Use the base Query vtable until we have a special one for each query */
1161 vtable = &IWineD3DQuery_Vtbl;
1162 FIXME("(%p) Unhandled query type %d\n", This, Type);
1164 if(NULL == ppQuery || hr != WINED3D_OK) {
1168 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1171 ERR("Out of memory\n");
1173 return WINED3DERR_OUTOFVIDEOMEMORY;
1176 object->lpVtbl = vtable;
1177 object->type = Type;
1178 object->state = QUERY_CREATED;
1179 object->wineD3DDevice = This;
1180 object->parent = parent;
1183 *ppQuery = (IWineD3DQuery *)object;
1185 /* allocated the 'extended' data based on the type of query requested */
1187 case WINED3DQUERYTYPE_OCCLUSION:
1188 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1189 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1191 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1192 TRACE("(%p) Allocating data for an occlusion query\n", This);
1194 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1196 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1200 case WINED3DQUERYTYPE_EVENT:
1201 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1202 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1204 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1206 if(GL_SUPPORT(APPLE_FENCE)) {
1207 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1208 checkGLcall("glGenFencesAPPLE");
1209 } else if(GL_SUPPORT(NV_FENCE)) {
1210 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1211 checkGLcall("glGenFencesNV");
1216 case WINED3DQUERYTYPE_VCACHE:
1217 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1218 case WINED3DQUERYTYPE_VERTEXSTATS:
1219 case WINED3DQUERYTYPE_TIMESTAMP:
1220 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1221 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1222 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1223 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1224 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1225 case WINED3DQUERYTYPE_PIXELTIMINGS:
1226 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1227 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1229 object->extendedData = 0;
1230 FIXME("(%p) Unhandled query type %d\n",This , Type);
1232 TRACE("(%p) : Created Query %p\n", This, object);
1236 /*****************************************************************************
1237 * IWineD3DDeviceImpl_SetupFullscreenWindow
1239 * Helper function that modifies a HWND's Style and ExStyle for proper
1243 * iface: Pointer to the IWineD3DDevice interface
1244 * window: Window to setup
1246 *****************************************************************************/
1247 static LONG fullscreen_style(LONG orig_style) {
1248 LONG style = orig_style;
1249 style &= ~WS_CAPTION;
1250 style &= ~WS_THICKFRAME;
1252 /* Make sure the window is managed, otherwise we won't get keyboard input */
1253 style |= WS_POPUP | WS_SYSMENU;
1258 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1259 LONG exStyle = orig_exStyle;
1261 /* Filter out window decorations */
1262 exStyle &= ~WS_EX_WINDOWEDGE;
1263 exStyle &= ~WS_EX_CLIENTEDGE;
1268 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1271 LONG style, exStyle;
1272 /* Don't do anything if an original style is stored.
1273 * That shouldn't happen
1275 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1276 if (This->style || This->exStyle) {
1277 ERR("(%p): Want to change the window parameters of HWND %p, but "
1278 "another style is stored for restoration afterwards\n", This, window);
1281 /* Get the parameters and save them */
1282 style = GetWindowLongW(window, GWL_STYLE);
1283 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1284 This->style = style;
1285 This->exStyle = exStyle;
1287 style = fullscreen_style(style);
1288 exStyle = fullscreen_exStyle(exStyle);
1290 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1291 This->style, This->exStyle, style, exStyle);
1293 SetWindowLongW(window, GWL_STYLE, style);
1294 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1296 /* Inform the window about the update. */
1297 SetWindowPos(window, HWND_TOP, 0, 0,
1298 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1301 /*****************************************************************************
1302 * IWineD3DDeviceImpl_RestoreWindow
1304 * Helper function that restores a windows' properties when taking it out
1305 * of fullscreen mode
1308 * iface: Pointer to the IWineD3DDevice interface
1309 * window: Window to setup
1311 *****************************************************************************/
1312 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1314 LONG style, exStyle;
1316 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1317 * switch, do nothing
1319 if (!This->style && !This->exStyle) return;
1321 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1322 This, window, This->style, This->exStyle);
1324 style = GetWindowLongW(window, GWL_STYLE);
1325 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1327 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1328 * Some applications change it before calling Reset() when switching between windowed and
1329 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1331 if(style == fullscreen_style(This->style) &&
1332 exStyle == fullscreen_style(This->exStyle)) {
1333 SetWindowLongW(window, GWL_STYLE, This->style);
1334 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1337 /* Delete the old values */
1341 /* Inform the window about the update */
1342 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1343 0, 0, 0, 0, /* Pos, Size, ignored */
1344 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1347 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1348 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1349 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1350 IUnknown *parent, WINED3DSURFTYPE surface_type)
1352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1355 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1357 IUnknown *bufferParent;
1358 BOOL displaymode_set = FALSE;
1359 WINED3DDISPLAYMODE Mode;
1360 const struct GlPixelFormatDesc *format_desc;
1362 TRACE("(%p) : Created Additional Swap Chain\n", This);
1364 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1365 * does a device hold a reference to a swap chain giving them a lifetime of the device
1366 * or does the swap chain notify the device of its destruction.
1367 *******************************/
1369 /* Check the params */
1370 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1371 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1372 return WINED3DERR_INVALIDCALL;
1373 } else if (pPresentationParameters->BackBufferCount > 1) {
1374 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");
1377 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1380 ERR("Out of memory\n");
1381 *ppSwapChain = NULL;
1382 return WINED3DERR_OUTOFVIDEOMEMORY;
1385 switch(surface_type) {
1387 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1389 case SURFACE_OPENGL:
1390 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1392 case SURFACE_UNKNOWN:
1393 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1394 HeapFree(GetProcessHeap(), 0, object);
1395 return WINED3DERR_INVALIDCALL;
1397 object->wineD3DDevice = This;
1398 object->parent = parent;
1401 *ppSwapChain = (IWineD3DSwapChain *)object;
1403 /*********************
1404 * Lookup the window Handle and the relating X window handle
1405 ********************/
1407 /* Setup hwnd we are using, plus which display this equates to */
1408 object->win_handle = pPresentationParameters->hDeviceWindow;
1409 if (!object->win_handle) {
1410 object->win_handle = This->createParms.hFocusWindow;
1412 if(!pPresentationParameters->Windowed && object->win_handle) {
1413 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1414 pPresentationParameters->BackBufferWidth,
1415 pPresentationParameters->BackBufferHeight);
1418 hDc = GetDC(object->win_handle);
1419 TRACE("Using hDc %p\n", hDc);
1422 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1423 return WINED3DERR_NOTAVAILABLE;
1426 /* Get info on the current display setup */
1427 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1428 object->orig_width = Mode.Width;
1429 object->orig_height = Mode.Height;
1430 object->orig_fmt = Mode.Format;
1431 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1433 if (pPresentationParameters->Windowed &&
1434 ((pPresentationParameters->BackBufferWidth == 0) ||
1435 (pPresentationParameters->BackBufferHeight == 0) ||
1436 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1439 GetClientRect(object->win_handle, &Rect);
1441 if (pPresentationParameters->BackBufferWidth == 0) {
1442 pPresentationParameters->BackBufferWidth = Rect.right;
1443 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1445 if (pPresentationParameters->BackBufferHeight == 0) {
1446 pPresentationParameters->BackBufferHeight = Rect.bottom;
1447 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1449 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1450 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1451 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1455 /* Put the correct figures in the presentation parameters */
1456 TRACE("Copying across presentation parameters\n");
1457 object->presentParms = *pPresentationParameters;
1459 TRACE("calling rendertarget CB\n");
1460 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1461 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1462 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1463 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1464 if (SUCCEEDED(hr)) {
1465 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1466 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1467 if(surface_type == SURFACE_OPENGL) {
1468 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1471 ERR("Failed to create the front buffer\n");
1475 /*********************
1476 * Windowed / Fullscreen
1477 *******************/
1480 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1481 * so we should really check to see if there is a fullscreen swapchain already
1482 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1483 **************************************/
1485 if (!pPresentationParameters->Windowed) {
1486 WINED3DDISPLAYMODE mode;
1489 /* Change the display settings */
1490 mode.Width = pPresentationParameters->BackBufferWidth;
1491 mode.Height = pPresentationParameters->BackBufferHeight;
1492 mode.Format = pPresentationParameters->BackBufferFormat;
1493 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1495 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1496 displaymode_set = TRUE;
1500 * Create an opengl context for the display visual
1501 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1502 * use different properties after that point in time. FIXME: How to handle when requested format
1503 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1504 * it chooses is identical to the one already being used!
1505 **********************************/
1506 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1508 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1509 if(!object->context) {
1510 ERR("Failed to create the context array\n");
1514 object->num_contexts = 1;
1516 if(surface_type == SURFACE_OPENGL) {
1517 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1518 if (!object->context[0]) {
1519 ERR("Failed to create a new context\n");
1520 hr = WINED3DERR_NOTAVAILABLE;
1523 TRACE("Context created (HWND=%p, glContext=%p)\n",
1524 object->win_handle, object->context[0]->glCtx);
1528 /*********************
1529 * Create the back, front and stencil buffers
1530 *******************/
1531 if(object->presentParms.BackBufferCount > 0) {
1534 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1535 if(!object->backBuffer) {
1536 ERR("Out of memory\n");
1541 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1542 TRACE("calling rendertarget CB\n");
1543 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1544 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1545 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1546 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1548 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1549 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1551 ERR("Cannot create new back buffer\n");
1554 if(surface_type == SURFACE_OPENGL) {
1556 glDrawBuffer(GL_BACK);
1557 checkGLcall("glDrawBuffer(GL_BACK)");
1562 object->backBuffer = NULL;
1564 /* Single buffering - draw to front buffer */
1565 if(surface_type == SURFACE_OPENGL) {
1567 glDrawBuffer(GL_FRONT);
1568 checkGLcall("glDrawBuffer(GL_FRONT)");
1573 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1574 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1575 TRACE("Creating depth stencil buffer\n");
1576 if (This->auto_depth_stencil_buffer == NULL ) {
1577 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1578 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1579 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1580 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1581 &This->auto_depth_stencil_buffer);
1582 if (SUCCEEDED(hr)) {
1583 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1585 ERR("Failed to create the auto depth stencil\n");
1591 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1593 TRACE("Created swapchain %p\n", object);
1594 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1598 if (displaymode_set) {
1602 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1605 /* Change the display settings */
1606 memset(&devmode, 0, sizeof(devmode));
1607 devmode.dmSize = sizeof(devmode);
1608 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1609 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1610 devmode.dmPelsWidth = object->orig_width;
1611 devmode.dmPelsHeight = object->orig_height;
1612 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1615 if (object->backBuffer) {
1617 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1618 if(object->backBuffer[i]) {
1619 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1620 IUnknown_Release(bufferParent); /* once for the get parent */
1621 if (IUnknown_Release(bufferParent) > 0) {
1622 FIXME("(%p) Something's still holding the back buffer\n",This);
1626 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1627 object->backBuffer = NULL;
1629 if(object->context && object->context[0])
1630 DestroyContext(This, object->context[0]);
1631 if(object->frontBuffer) {
1632 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1633 IUnknown_Release(bufferParent); /* once for the get parent */
1634 if (IUnknown_Release(bufferParent) > 0) {
1635 FIXME("(%p) Something's still holding the front buffer\n",This);
1638 HeapFree(GetProcessHeap(), 0, object);
1642 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1643 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1645 TRACE("(%p)\n", This);
1647 return This->NumberOfSwapChains;
1650 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1652 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1654 if(iSwapChain < This->NumberOfSwapChains) {
1655 *pSwapChain = This->swapchains[iSwapChain];
1656 IWineD3DSwapChain_AddRef(*pSwapChain);
1657 TRACE("(%p) returning %p\n", This, *pSwapChain);
1660 TRACE("Swapchain out of range\n");
1662 return WINED3DERR_INVALIDCALL;
1667 * Vertex Declaration
1669 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1670 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1672 IWineD3DVertexDeclarationImpl *object = NULL;
1673 HRESULT hr = WINED3D_OK;
1675 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1676 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1678 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1681 ERR("Out of memory\n");
1682 *ppVertexDeclaration = NULL;
1683 return WINED3DERR_OUTOFVIDEOMEMORY;
1686 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
1687 object->wineD3DDevice = This;
1688 object->parent = parent;
1691 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1693 hr = vertexdeclaration_init(object, elements, element_count);
1696 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1697 *ppVertexDeclaration = NULL;
1703 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1704 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1706 unsigned int idx, idx2;
1707 unsigned int offset;
1708 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1709 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1710 BOOL has_blend_idx = has_blend &&
1711 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1712 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1713 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1714 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1715 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1716 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1717 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1719 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1720 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1721 WINED3DVERTEXELEMENT *elements = NULL;
1724 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1725 if (has_blend_idx) num_blends--;
1727 /* Compute declaration size */
1728 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1729 has_psize + has_diffuse + has_specular + num_textures;
1731 /* convert the declaration */
1732 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1733 if (!elements) return ~0U;
1737 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1738 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1739 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1741 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1742 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1743 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1746 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1747 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1749 elements[idx].usage_idx = 0;
1752 if (has_blend && (num_blends > 0)) {
1753 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1754 elements[idx].format = WINED3DFMT_A8R8G8B8;
1756 switch(num_blends) {
1757 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1758 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1759 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1760 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1762 ERR("Unexpected amount of blend values: %u\n", num_blends);
1765 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1766 elements[idx].usage_idx = 0;
1769 if (has_blend_idx) {
1770 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1771 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1772 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1773 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1774 elements[idx].format = WINED3DFMT_A8R8G8B8;
1776 elements[idx].format = WINED3DFMT_R32_FLOAT;
1777 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1778 elements[idx].usage_idx = 0;
1782 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1783 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1784 elements[idx].usage_idx = 0;
1788 elements[idx].format = WINED3DFMT_R32_FLOAT;
1789 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1790 elements[idx].usage_idx = 0;
1794 elements[idx].format = WINED3DFMT_A8R8G8B8;
1795 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1796 elements[idx].usage_idx = 0;
1800 elements[idx].format = WINED3DFMT_A8R8G8B8;
1801 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1802 elements[idx].usage_idx = 1;
1805 for (idx2 = 0; idx2 < num_textures; idx2++) {
1806 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1807 switch (numcoords) {
1808 case WINED3DFVF_TEXTUREFORMAT1:
1809 elements[idx].format = WINED3DFMT_R32_FLOAT;
1811 case WINED3DFVF_TEXTUREFORMAT2:
1812 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1814 case WINED3DFVF_TEXTUREFORMAT3:
1815 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1817 case WINED3DFVF_TEXTUREFORMAT4:
1818 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1821 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1822 elements[idx].usage_idx = idx2;
1826 /* Now compute offsets, and initialize the rest of the fields */
1827 for (idx = 0, offset = 0; idx < size; ++idx)
1829 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1830 elements[idx].input_slot = 0;
1831 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1832 elements[idx].offset = offset;
1833 offset += format_desc->component_count * format_desc->component_size;
1836 *ppVertexElements = elements;
1840 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1841 WINED3DVERTEXELEMENT* elements = NULL;
1842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1846 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1847 if (size == ~0U) return WINED3DERR_OUTOFVIDEOMEMORY;
1849 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1850 HeapFree(GetProcessHeap(), 0, elements);
1851 if (hr != S_OK) return hr;
1856 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1857 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1858 IWineD3DVertexShader **ppVertexShader, IUnknown *parent)
1860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1861 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1862 HRESULT hr = WINED3D_OK;
1864 if (!pFunction) return WINED3DERR_INVALIDCALL;
1866 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1869 ERR("Out of memory\n");
1870 *ppVertexShader = NULL;
1871 return WINED3DERR_OUTOFVIDEOMEMORY;
1874 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
1875 object->parent = parent;
1876 shader_init(&object->baseShader, iface);
1877 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1878 *ppVertexShader = (IWineD3DVertexShader *)object;
1880 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
1882 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction, output_signature);
1885 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
1886 IWineD3DVertexShader_Release(*ppVertexShader);
1887 *ppVertexShader = NULL;
1894 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1895 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1896 IWineD3DPixelShader **ppPixelShader, IUnknown *parent)
1898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1899 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1900 HRESULT hr = WINED3D_OK;
1902 if (!pFunction) return WINED3DERR_INVALIDCALL;
1904 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1907 ERR("Out of memory\n");
1908 *ppPixelShader = NULL;
1909 return WINED3DERR_OUTOFVIDEOMEMORY;
1912 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
1913 object->parent = parent;
1914 shader_init(&object->baseShader, iface);
1915 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1916 *ppPixelShader = (IWineD3DPixelShader *)object;
1918 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
1920 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction, output_signature);
1923 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
1924 IWineD3DPixelShader_Release(*ppPixelShader);
1925 *ppPixelShader = NULL;
1932 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1933 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1936 IWineD3DPaletteImpl *object;
1938 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1940 /* Create the new object */
1941 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1943 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1944 return E_OUTOFMEMORY;
1947 object->lpVtbl = &IWineD3DPalette_Vtbl;
1949 object->Flags = Flags;
1950 object->parent = Parent;
1951 object->wineD3DDevice = This;
1952 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1953 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1956 HeapFree( GetProcessHeap(), 0, object);
1957 return E_OUTOFMEMORY;
1960 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1962 IWineD3DPalette_Release((IWineD3DPalette *) object);
1966 *Palette = (IWineD3DPalette *) object;
1971 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1975 HDC dcb = NULL, dcs = NULL;
1976 WINEDDCOLORKEY colorkey;
1978 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1981 GetObjectA(hbm, sizeof(BITMAP), &bm);
1982 dcb = CreateCompatibleDC(NULL);
1984 SelectObject(dcb, hbm);
1988 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1989 * couldn't be loaded
1991 memset(&bm, 0, sizeof(bm));
1996 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5, TRUE,
1997 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL);
1999 ERR("Wine logo requested, but failed to create surface\n");
2004 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2005 if(FAILED(hr)) goto out;
2006 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2007 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2009 colorkey.dwColorSpaceLowValue = 0;
2010 colorkey.dwColorSpaceHighValue = 0;
2011 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2013 /* Fill the surface with a white color to show that wined3d is there */
2014 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2027 /* Context activation is done by the caller. */
2028 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2030 /* Under DirectX you can have texture stage operations even if no texture is
2031 bound, whereas opengl will only do texture operations when a valid texture is
2032 bound. We emulate this by creating dummy textures and binding them to each
2033 texture stage, but disable all stages by default. Hence if a stage is enabled
2034 then the default texture will kick in until replaced by a SetTexture call */
2037 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2038 /* The dummy texture does not have client storage backing */
2039 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2040 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2042 for (i = 0; i < GL_LIMITS(textures); i++) {
2043 GLubyte white = 255;
2045 /* Make appropriate texture active */
2046 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2047 checkGLcall("glActiveTextureARB");
2049 /* Generate an opengl texture name */
2050 glGenTextures(1, &This->dummyTextureName[i]);
2051 checkGLcall("glGenTextures");
2052 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2054 /* Generate a dummy 2d texture (not using 1d because they cause many
2055 * DRI drivers fall back to sw) */
2056 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2057 checkGLcall("glBindTexture");
2059 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2060 checkGLcall("glTexImage2D");
2062 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2063 /* Reenable because if supported it is enabled by default */
2064 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2065 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2071 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2072 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2075 IWineD3DSwapChainImpl *swapchain = NULL;
2080 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2082 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2083 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2085 /* TODO: Test if OpenGL is compiled in and loaded */
2087 TRACE("(%p) : Creating stateblock\n", This);
2088 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2089 hr = IWineD3DDevice_CreateStateBlock(iface,
2091 (IWineD3DStateBlock **)&This->stateBlock,
2093 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2094 WARN("Failed to create stateblock\n");
2097 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2098 This->updateStateBlock = This->stateBlock;
2099 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2101 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2102 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2104 This->NumberOfPalettes = 1;
2105 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2106 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2107 ERR("Out of memory!\n");
2110 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2111 if(!This->palettes[0]) {
2112 ERR("Out of memory!\n");
2115 for (i = 0; i < 256; ++i) {
2116 This->palettes[0][i].peRed = 0xFF;
2117 This->palettes[0][i].peGreen = 0xFF;
2118 This->palettes[0][i].peBlue = 0xFF;
2119 This->palettes[0][i].peFlags = 0xFF;
2121 This->currentPalette = 0;
2123 /* Initialize the texture unit mapping to a 1:1 mapping */
2124 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2125 if (state < GL_LIMITS(fragment_samplers)) {
2126 This->texUnitMap[state] = state;
2127 This->rev_tex_unit_map[state] = state;
2129 This->texUnitMap[state] = -1;
2130 This->rev_tex_unit_map[state] = -1;
2134 /* Setup the implicit swapchain. This also initializes a context. */
2135 TRACE("Creating implicit swapchain\n");
2136 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2137 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2140 WARN("Failed to create implicit swapchain\n");
2144 This->NumberOfSwapChains = 1;
2145 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2146 if(!This->swapchains) {
2147 ERR("Out of memory!\n");
2150 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2152 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2153 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2154 This->render_targets[0] = swapchain->backBuffer[0];
2155 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2158 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2159 This->render_targets[0] = swapchain->frontBuffer;
2160 This->lastActiveRenderTarget = swapchain->frontBuffer;
2162 IWineD3DSurface_AddRef(This->render_targets[0]);
2163 This->activeContext = swapchain->context[0];
2164 This->lastThread = GetCurrentThreadId();
2166 /* Depth Stencil support */
2167 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2168 if (NULL != This->stencilBufferTarget) {
2169 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2172 hr = This->shader_backend->shader_alloc_private(iface);
2174 TRACE("Shader private data couldn't be allocated\n");
2177 hr = This->frag_pipe->alloc_private(iface);
2179 TRACE("Fragment pipeline private data couldn't be allocated\n");
2182 hr = This->blitter->alloc_private(iface);
2184 TRACE("Blitter private data couldn't be allocated\n");
2188 /* Set up some starting GL setup */
2190 /* Setup all the devices defaults */
2191 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2192 create_dummy_textures(This);
2196 /* Initialize the current view state */
2197 This->view_ident = 1;
2198 This->contexts[0]->last_was_rhw = 0;
2199 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2200 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2202 switch(wined3d_settings.offscreen_rendering_mode) {
2205 This->offscreenBuffer = GL_BACK;
2208 case ORM_BACKBUFFER:
2210 if(This->activeContext->aux_buffers > 0) {
2211 TRACE("Using auxilliary buffer for offscreen rendering\n");
2212 This->offscreenBuffer = GL_AUX0;
2214 TRACE("Using back buffer for offscreen rendering\n");
2215 This->offscreenBuffer = GL_BACK;
2220 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2223 /* Clear the screen */
2224 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2225 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2228 This->d3d_initialized = TRUE;
2230 if(wined3d_settings.logo) {
2231 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2233 This->highest_dirty_ps_const = 0;
2234 This->highest_dirty_vs_const = 0;
2238 HeapFree(GetProcessHeap(), 0, This->render_targets);
2239 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2240 HeapFree(GetProcessHeap(), 0, This->swapchains);
2241 This->NumberOfSwapChains = 0;
2242 if(This->palettes) {
2243 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2244 HeapFree(GetProcessHeap(), 0, This->palettes);
2246 This->NumberOfPalettes = 0;
2248 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2250 if(This->stateBlock) {
2251 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2252 This->stateBlock = NULL;
2254 if (This->blit_priv) {
2255 This->blitter->free_private(iface);
2257 if (This->fragment_priv) {
2258 This->frag_pipe->free_private(iface);
2260 if (This->shader_priv) {
2261 This->shader_backend->shader_free_private(iface);
2266 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2267 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2270 IWineD3DSwapChainImpl *swapchain = NULL;
2273 /* Setup the implicit swapchain */
2274 TRACE("Creating implicit swapchain\n");
2275 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2276 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2279 WARN("Failed to create implicit swapchain\n");
2283 This->NumberOfSwapChains = 1;
2284 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2285 if(!This->swapchains) {
2286 ERR("Out of memory!\n");
2289 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2293 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2297 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2299 IWineD3DResource_UnLoad(resource);
2300 IWineD3DResource_Release(resource);
2304 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2308 TRACE("(%p)\n", This);
2310 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2312 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2313 * it was created. Thus make sure a context is active for the glDelete* calls
2315 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2317 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2319 /* Unload resources */
2320 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2322 TRACE("Deleting high order patches\n");
2323 for(i = 0; i < PATCHMAP_SIZE; i++) {
2324 struct list *e1, *e2;
2325 struct WineD3DRectPatch *patch;
2326 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2327 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2328 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2332 /* Delete the palette conversion shader if it is around */
2333 if(This->paletteConversionShader) {
2335 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2337 This->paletteConversionShader = 0;
2340 /* Delete the pbuffer context if there is any */
2341 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2343 /* Delete the mouse cursor texture */
2344 if(This->cursorTexture) {
2346 glDeleteTextures(1, &This->cursorTexture);
2348 This->cursorTexture = 0;
2351 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2352 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2354 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2355 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2358 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2359 * private data, it might contain opengl pointers
2361 if(This->depth_blt_texture) {
2363 glDeleteTextures(1, &This->depth_blt_texture);
2365 This->depth_blt_texture = 0;
2367 if (This->depth_blt_rb) {
2369 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2371 This->depth_blt_rb = 0;
2372 This->depth_blt_rb_w = 0;
2373 This->depth_blt_rb_h = 0;
2376 /* Release the update stateblock */
2377 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2378 if(This->updateStateBlock != This->stateBlock)
2379 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2381 This->updateStateBlock = NULL;
2383 { /* because were not doing proper internal refcounts releasing the primary state block
2384 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2385 to set this->stateBlock = NULL; first */
2386 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2387 This->stateBlock = NULL;
2389 /* Release the stateblock */
2390 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2391 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2395 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2396 This->blitter->free_private(iface);
2397 This->frag_pipe->free_private(iface);
2398 This->shader_backend->shader_free_private(iface);
2400 /* Release the buffers (with sanity checks)*/
2401 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2402 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2403 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2404 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2406 This->stencilBufferTarget = NULL;
2408 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2409 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2410 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2412 TRACE("Setting rendertarget to NULL\n");
2413 This->render_targets[0] = NULL;
2415 if (This->auto_depth_stencil_buffer) {
2416 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2417 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2419 This->auto_depth_stencil_buffer = NULL;
2422 for(i=0; i < This->NumberOfSwapChains; i++) {
2423 TRACE("Releasing the implicit swapchain %d\n", i);
2424 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2425 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2429 HeapFree(GetProcessHeap(), 0, This->swapchains);
2430 This->swapchains = NULL;
2431 This->NumberOfSwapChains = 0;
2433 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2434 HeapFree(GetProcessHeap(), 0, This->palettes);
2435 This->palettes = NULL;
2436 This->NumberOfPalettes = 0;
2438 HeapFree(GetProcessHeap(), 0, This->render_targets);
2439 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2440 This->render_targets = NULL;
2441 This->draw_buffers = NULL;
2443 This->d3d_initialized = FALSE;
2447 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2451 for(i=0; i < This->NumberOfSwapChains; i++) {
2452 TRACE("Releasing the implicit swapchain %d\n", i);
2453 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2454 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2458 HeapFree(GetProcessHeap(), 0, This->swapchains);
2459 This->swapchains = NULL;
2460 This->NumberOfSwapChains = 0;
2464 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2465 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2466 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2468 * There is no way to deactivate thread safety once it is enabled.
2470 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2473 /*For now just store the flag(needed in case of ddraw) */
2474 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2479 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2480 const WINED3DDISPLAYMODE* pMode) {
2482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2484 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2487 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2489 /* Resize the screen even without a window:
2490 * The app could have unset it with SetCooperativeLevel, but not called
2491 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2492 * but we don't have any hwnd
2495 memset(&devmode, 0, sizeof(devmode));
2496 devmode.dmSize = sizeof(devmode);
2497 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2498 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2499 devmode.dmPelsWidth = pMode->Width;
2500 devmode.dmPelsHeight = pMode->Height;
2502 devmode.dmDisplayFrequency = pMode->RefreshRate;
2503 if (pMode->RefreshRate != 0) {
2504 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2507 /* Only change the mode if necessary */
2508 if( (This->ddraw_width == pMode->Width) &&
2509 (This->ddraw_height == pMode->Height) &&
2510 (This->ddraw_format == pMode->Format) &&
2511 (pMode->RefreshRate == 0) ) {
2515 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2516 if (ret != DISP_CHANGE_SUCCESSFUL) {
2517 if(devmode.dmDisplayFrequency != 0) {
2518 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2519 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2520 devmode.dmDisplayFrequency = 0;
2521 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2523 if(ret != DISP_CHANGE_SUCCESSFUL) {
2524 return WINED3DERR_NOTAVAILABLE;
2528 /* Store the new values */
2529 This->ddraw_width = pMode->Width;
2530 This->ddraw_height = pMode->Height;
2531 This->ddraw_format = pMode->Format;
2533 /* And finally clip mouse to our screen */
2534 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2535 ClipCursor(&clip_rc);
2540 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2542 *ppD3D= This->wineD3D;
2543 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2544 IWineD3D_AddRef(*ppD3D);
2548 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2551 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2552 (This->adapter->TextureRam/(1024*1024)),
2553 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2554 /* return simulated texture memory left */
2555 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2559 * Get / Set Stream Source
2561 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2562 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2565 IWineD3DBuffer *oldSrc;
2567 if (StreamNumber >= MAX_STREAMS) {
2568 WARN("Stream out of range %d\n", StreamNumber);
2569 return WINED3DERR_INVALIDCALL;
2570 } else if(OffsetInBytes & 0x3) {
2571 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2572 return WINED3DERR_INVALIDCALL;
2575 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2576 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2578 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2580 if(oldSrc == pStreamData &&
2581 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2582 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2583 TRACE("Application is setting the old values over, nothing to do\n");
2587 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2589 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2590 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2593 /* Handle recording of state blocks */
2594 if (This->isRecordingState) {
2595 TRACE("Recording... not performing anything\n");
2596 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2597 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2601 if (pStreamData != NULL) {
2602 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2603 IWineD3DBuffer_AddRef(pStreamData);
2605 if (oldSrc != NULL) {
2606 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2607 IWineD3DBuffer_Release(oldSrc);
2610 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2615 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2616 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2620 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2621 This->stateBlock->streamSource[StreamNumber],
2622 This->stateBlock->streamOffset[StreamNumber],
2623 This->stateBlock->streamStride[StreamNumber]);
2625 if (StreamNumber >= MAX_STREAMS) {
2626 WARN("Stream out of range %d\n", StreamNumber);
2627 return WINED3DERR_INVALIDCALL;
2629 *pStream = This->stateBlock->streamSource[StreamNumber];
2630 *pStride = This->stateBlock->streamStride[StreamNumber];
2632 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2635 if (*pStream != NULL) {
2636 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2641 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2643 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2644 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2646 /* Verify input at least in d3d9 this is invalid*/
2647 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2648 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2649 return WINED3DERR_INVALIDCALL;
2651 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2652 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2653 return WINED3DERR_INVALIDCALL;
2656 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2657 return WINED3DERR_INVALIDCALL;
2660 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2661 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2663 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2664 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2666 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2667 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2668 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2674 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2677 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2678 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2680 TRACE("(%p) : returning %d\n", This, *Divider);
2686 * Get / Set & Multiply Transform
2688 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2691 /* Most of this routine, comments included copied from ddraw tree initially: */
2692 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2694 /* Handle recording of state blocks */
2695 if (This->isRecordingState) {
2696 TRACE("Recording... not performing anything\n");
2697 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2698 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2703 * If the new matrix is the same as the current one,
2704 * we cut off any further processing. this seems to be a reasonable
2705 * optimization because as was noticed, some apps (warcraft3 for example)
2706 * tend towards setting the same matrix repeatedly for some reason.
2708 * From here on we assume that the new matrix is different, wherever it matters.
2710 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2711 TRACE("The app is setting the same matrix over again\n");
2714 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2718 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2719 where ViewMat = Camera space, WorldMat = world space.
2721 In OpenGL, camera and world space is combined into GL_MODELVIEW
2722 matrix. The Projection matrix stay projection matrix.
2725 /* Capture the times we can just ignore the change for now */
2726 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2727 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2728 /* Handled by the state manager */
2731 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2735 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2737 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2738 *pMatrix = This->stateBlock->transforms[State];
2742 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2743 const WINED3DMATRIX *mat = NULL;
2746 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2747 * below means it will be recorded in a state block change, but it
2748 * works regardless where it is recorded.
2749 * If this is found to be wrong, change to StateBlock.
2751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2752 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2754 if (State <= HIGHEST_TRANSFORMSTATE)
2756 mat = &This->updateStateBlock->transforms[State];
2758 FIXME("Unhandled transform state!!\n");
2761 multiply_matrix(&temp, mat, pMatrix);
2763 /* Apply change via set transform - will reapply to eg. lights this way */
2764 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2770 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2771 you can reference any indexes you want as long as that number max are enabled at any
2772 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2773 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2774 but when recording, just build a chain pretty much of commands to be replayed. */
2776 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2778 PLIGHTINFOEL *object = NULL;
2779 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2783 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2785 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2789 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2790 return WINED3DERR_INVALIDCALL;
2793 switch(pLight->Type) {
2794 case WINED3DLIGHT_POINT:
2795 case WINED3DLIGHT_SPOT:
2796 case WINED3DLIGHT_PARALLELPOINT:
2797 case WINED3DLIGHT_GLSPOT:
2798 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2801 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2802 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2803 return WINED3DERR_INVALIDCALL;
2807 case WINED3DLIGHT_DIRECTIONAL:
2808 /* Ignores attenuation */
2812 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2813 return WINED3DERR_INVALIDCALL;
2816 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2817 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2818 if(object->OriginalIndex == Index) break;
2823 TRACE("Adding new light\n");
2824 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2826 ERR("Out of memory error when allocating a light\n");
2827 return E_OUTOFMEMORY;
2829 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2830 object->glIndex = -1;
2831 object->OriginalIndex = Index;
2832 object->changed = TRUE;
2835 /* Initialize the object */
2836 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,
2837 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2838 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2839 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2840 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2841 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2842 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2844 /* Save away the information */
2845 object->OriginalParms = *pLight;
2847 switch (pLight->Type) {
2848 case WINED3DLIGHT_POINT:
2850 object->lightPosn[0] = pLight->Position.x;
2851 object->lightPosn[1] = pLight->Position.y;
2852 object->lightPosn[2] = pLight->Position.z;
2853 object->lightPosn[3] = 1.0f;
2854 object->cutoff = 180.0f;
2858 case WINED3DLIGHT_DIRECTIONAL:
2860 object->lightPosn[0] = -pLight->Direction.x;
2861 object->lightPosn[1] = -pLight->Direction.y;
2862 object->lightPosn[2] = -pLight->Direction.z;
2863 object->lightPosn[3] = 0.0;
2864 object->exponent = 0.0f;
2865 object->cutoff = 180.0f;
2868 case WINED3DLIGHT_SPOT:
2870 object->lightPosn[0] = pLight->Position.x;
2871 object->lightPosn[1] = pLight->Position.y;
2872 object->lightPosn[2] = pLight->Position.z;
2873 object->lightPosn[3] = 1.0;
2876 object->lightDirn[0] = pLight->Direction.x;
2877 object->lightDirn[1] = pLight->Direction.y;
2878 object->lightDirn[2] = pLight->Direction.z;
2879 object->lightDirn[3] = 1.0;
2882 * opengl-ish and d3d-ish spot lights use too different models for the
2883 * light "intensity" as a function of the angle towards the main light direction,
2884 * so we only can approximate very roughly.
2885 * however spot lights are rather rarely used in games (if ever used at all).
2886 * furthermore if still used, probably nobody pays attention to such details.
2888 if (pLight->Falloff == 0) {
2889 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2890 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2891 * will always be 1.0 for both of them, and we don't have to care for the
2892 * rest of the rather complex calculation
2894 object->exponent = 0;
2896 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2897 if (rho < 0.0001) rho = 0.0001f;
2898 object->exponent = -0.3/log(cos(rho/2));
2900 if (object->exponent > 128.0) {
2901 object->exponent = 128.0;
2903 object->cutoff = pLight->Phi*90/M_PI;
2909 FIXME("Unrecognized light type %d\n", pLight->Type);
2912 /* Update the live definitions if the light is currently assigned a glIndex */
2913 if (object->glIndex != -1 && !This->isRecordingState) {
2914 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2919 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2920 PLIGHTINFOEL *lightInfo = NULL;
2921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2922 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2924 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2926 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2927 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2928 if(lightInfo->OriginalIndex == Index) break;
2932 if (lightInfo == NULL) {
2933 TRACE("Light information requested but light not defined\n");
2934 return WINED3DERR_INVALIDCALL;
2937 *pLight = lightInfo->OriginalParms;
2942 * Get / Set Light Enable
2943 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2945 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2946 PLIGHTINFOEL *lightInfo = NULL;
2947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2948 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2950 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2952 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2953 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2954 if(lightInfo->OriginalIndex == Index) break;
2957 TRACE("Found light: %p\n", lightInfo);
2959 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2960 if (lightInfo == NULL) {
2962 TRACE("Light enabled requested but light not defined, so defining one!\n");
2963 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2965 /* Search for it again! Should be fairly quick as near head of list */
2966 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2967 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2968 if(lightInfo->OriginalIndex == Index) break;
2971 if (lightInfo == NULL) {
2972 FIXME("Adding default lights has failed dismally\n");
2973 return WINED3DERR_INVALIDCALL;
2977 lightInfo->enabledChanged = TRUE;
2979 if(lightInfo->glIndex != -1) {
2980 if(!This->isRecordingState) {
2981 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2984 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2985 lightInfo->glIndex = -1;
2987 TRACE("Light already disabled, nothing to do\n");
2989 lightInfo->enabled = FALSE;
2991 lightInfo->enabled = TRUE;
2992 if (lightInfo->glIndex != -1) {
2994 TRACE("Nothing to do as light was enabled\n");
2997 /* Find a free gl light */
2998 for(i = 0; i < This->maxConcurrentLights; i++) {
2999 if(This->updateStateBlock->activeLights[i] == NULL) {
3000 This->updateStateBlock->activeLights[i] = lightInfo;
3001 lightInfo->glIndex = i;
3005 if(lightInfo->glIndex == -1) {
3006 /* Our tests show that Windows returns D3D_OK in this situation, even with
3007 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3008 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3009 * as well for those lights.
3011 * TODO: Test how this affects rendering
3013 WARN("Too many concurrently active lights\n");
3017 /* i == lightInfo->glIndex */
3018 if(!This->isRecordingState) {
3019 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3027 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3029 PLIGHTINFOEL *lightInfo = NULL;
3030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3032 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3033 TRACE("(%p) : for idx(%d)\n", This, Index);
3035 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3036 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3037 if(lightInfo->OriginalIndex == Index) break;
3041 if (lightInfo == NULL) {
3042 TRACE("Light enabled state requested but light not defined\n");
3043 return WINED3DERR_INVALIDCALL;
3045 /* true is 128 according to SetLightEnable */
3046 *pEnable = lightInfo->enabled ? 128 : 0;
3051 * Get / Set Clip Planes
3053 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3055 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3057 /* Validate Index */
3058 if (Index >= GL_LIMITS(clipplanes)) {
3059 TRACE("Application has requested clipplane this device doesn't support\n");
3060 return WINED3DERR_INVALIDCALL;
3063 This->updateStateBlock->changed.clipplane |= 1 << Index;
3065 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3066 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3067 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3068 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3069 TRACE("Application is setting old values over, nothing to do\n");
3073 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3074 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3075 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3076 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3078 /* Handle recording of state blocks */
3079 if (This->isRecordingState) {
3080 TRACE("Recording... not performing anything\n");
3084 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3089 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3091 TRACE("(%p) : for idx %d\n", This, Index);
3093 /* Validate Index */
3094 if (Index >= GL_LIMITS(clipplanes)) {
3095 TRACE("Application has requested clipplane this device doesn't support\n");
3096 return WINED3DERR_INVALIDCALL;
3099 pPlane[0] = This->stateBlock->clipplane[Index][0];
3100 pPlane[1] = This->stateBlock->clipplane[Index][1];
3101 pPlane[2] = This->stateBlock->clipplane[Index][2];
3102 pPlane[3] = This->stateBlock->clipplane[Index][3];
3107 * Get / Set Clip Plane Status
3108 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3110 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3112 FIXME("(%p) : stub\n", This);
3113 if (NULL == pClipStatus) {
3114 return WINED3DERR_INVALIDCALL;
3116 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3117 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3121 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3123 FIXME("(%p) : stub\n", This);
3124 if (NULL == pClipStatus) {
3125 return WINED3DERR_INVALIDCALL;
3127 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3128 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3133 * Get / Set Material
3135 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3138 This->updateStateBlock->changed.material = TRUE;
3139 This->updateStateBlock->material = *pMaterial;
3141 /* Handle recording of state blocks */
3142 if (This->isRecordingState) {
3143 TRACE("Recording... not performing anything\n");
3147 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3151 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3153 *pMaterial = This->updateStateBlock->material;
3154 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3155 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3156 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3157 pMaterial->Ambient.b, pMaterial->Ambient.a);
3158 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3159 pMaterial->Specular.b, pMaterial->Specular.a);
3160 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3161 pMaterial->Emissive.b, pMaterial->Emissive.a);
3162 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3170 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DBuffer* pIndexData, WINED3DFORMAT fmt) {
3171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3172 IWineD3DBuffer *oldIdxs;
3174 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3175 oldIdxs = This->updateStateBlock->pIndexData;
3177 This->updateStateBlock->changed.indices = TRUE;
3178 This->updateStateBlock->pIndexData = pIndexData;
3179 This->updateStateBlock->IndexFmt = fmt;
3181 /* Handle recording of state blocks */
3182 if (This->isRecordingState) {
3183 TRACE("Recording... not performing anything\n");
3184 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3185 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3189 if(oldIdxs != pIndexData) {
3190 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3192 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3193 IWineD3DBuffer_AddRef(pIndexData);
3196 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3197 IWineD3DBuffer_Release(oldIdxs);
3204 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DBuffer** ppIndexData) {
3205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3207 *ppIndexData = This->stateBlock->pIndexData;
3209 /* up ref count on ppindexdata */
3211 IWineD3DBuffer_AddRef(*ppIndexData);
3212 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3214 TRACE("(%p) No index data set\n", This);
3216 TRACE("Returning %p\n", *ppIndexData);
3221 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3222 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3224 TRACE("(%p)->(%d)\n", This, BaseIndex);
3226 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3227 TRACE("Application is setting the old value over, nothing to do\n");
3231 This->updateStateBlock->baseVertexIndex = BaseIndex;
3233 if (This->isRecordingState) {
3234 TRACE("Recording... not performing anything\n");
3237 /* The base vertex index affects the stream sources */
3238 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3242 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3244 TRACE("(%p) : base_index %p\n", This, base_index);
3246 *base_index = This->stateBlock->baseVertexIndex;
3248 TRACE("Returning %u\n", *base_index);
3254 * Get / Set Viewports
3256 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3259 TRACE("(%p)\n", This);
3260 This->updateStateBlock->changed.viewport = TRUE;
3261 This->updateStateBlock->viewport = *pViewport;
3263 /* Handle recording of state blocks */
3264 if (This->isRecordingState) {
3265 TRACE("Recording... not performing anything\n");
3269 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3270 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3272 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3277 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3279 TRACE("(%p)\n", This);
3280 *pViewport = This->stateBlock->viewport;
3285 * Get / Set Render States
3286 * TODO: Verify against dx9 definitions
3288 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3291 DWORD oldValue = This->stateBlock->renderState[State];
3293 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3295 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3296 This->updateStateBlock->renderState[State] = Value;
3298 /* Handle recording of state blocks */
3299 if (This->isRecordingState) {
3300 TRACE("Recording... not performing anything\n");
3304 /* Compared here and not before the assignment to allow proper stateblock recording */
3305 if(Value == oldValue) {
3306 TRACE("Application is setting the old value over, nothing to do\n");
3308 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3314 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3316 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3317 *pValue = This->stateBlock->renderState[State];
3322 * Get / Set Sampler States
3323 * TODO: Verify against dx9 definitions
3326 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3327 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3330 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3331 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3333 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3334 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3337 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3338 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3339 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3342 * SetSampler is designed to allow for more than the standard up to 8 textures
3343 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3344 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3346 * http://developer.nvidia.com/object/General_FAQ.html#t6
3348 * There are two new settings for GForce
3350 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3351 * and the texture one:
3352 * GL_MAX_TEXTURE_COORDS_ARB.
3353 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3356 oldValue = This->stateBlock->samplerState[Sampler][Type];
3357 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3358 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3360 /* Handle recording of state blocks */
3361 if (This->isRecordingState) {
3362 TRACE("Recording... not performing anything\n");
3366 if(oldValue == Value) {
3367 TRACE("Application is setting the old value over, nothing to do\n");
3371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3376 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3379 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3380 This, Sampler, debug_d3dsamplerstate(Type), Type);
3382 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3383 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3386 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3387 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3388 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3390 *Value = This->stateBlock->samplerState[Sampler][Type];
3391 TRACE("(%p) : Returning %#x\n", This, *Value);
3396 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3399 This->updateStateBlock->changed.scissorRect = TRUE;
3400 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3401 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3404 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3406 if(This->isRecordingState) {
3407 TRACE("Recording... not performing anything\n");
3411 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3416 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3419 *pRect = This->updateStateBlock->scissorRect;
3420 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3424 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3425 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3426 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3428 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3430 This->updateStateBlock->vertexDecl = pDecl;
3431 This->updateStateBlock->changed.vertexDecl = TRUE;
3433 if (This->isRecordingState) {
3434 TRACE("Recording... not performing anything\n");
3436 } else if(pDecl == oldDecl) {
3437 /* Checked after the assignment to allow proper stateblock recording */
3438 TRACE("Application is setting the old declaration over, nothing to do\n");
3442 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3446 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3449 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3451 *ppDecl = This->stateBlock->vertexDecl;
3452 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3456 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3458 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3460 This->updateStateBlock->vertexShader = pShader;
3461 This->updateStateBlock->changed.vertexShader = TRUE;
3463 if (This->isRecordingState) {
3464 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3465 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3466 TRACE("Recording... not performing anything\n");
3468 } else if(oldShader == pShader) {
3469 /* Checked here to allow proper stateblock recording */
3470 TRACE("App is setting the old shader over, nothing to do\n");
3474 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3475 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3476 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3478 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3483 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3486 if (NULL == ppShader) {
3487 return WINED3DERR_INVALIDCALL;
3489 *ppShader = This->stateBlock->vertexShader;
3490 if( NULL != *ppShader)
3491 IWineD3DVertexShader_AddRef(*ppShader);
3493 TRACE("(%p) : returning %p\n", This, *ppShader);
3497 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3498 IWineD3DDevice *iface,
3500 CONST BOOL *srcData,
3503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3504 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3506 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3507 iface, srcData, start, count);
3509 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3511 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3512 for (i = 0; i < cnt; i++)
3513 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3515 for (i = start; i < cnt + start; ++i) {
3516 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3519 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3524 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3525 IWineD3DDevice *iface,
3530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3531 int cnt = min(count, MAX_CONST_B - start);
3533 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3534 iface, dstData, start, count);
3536 if (dstData == NULL || cnt < 0)
3537 return WINED3DERR_INVALIDCALL;
3539 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3543 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3544 IWineD3DDevice *iface,
3549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3550 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3552 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3553 iface, srcData, start, count);
3555 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3557 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3558 for (i = 0; i < cnt; i++)
3559 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3560 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3562 for (i = start; i < cnt + start; ++i) {
3563 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3566 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3571 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3572 IWineD3DDevice *iface,
3577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3578 int cnt = min(count, MAX_CONST_I - start);
3580 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3581 iface, dstData, start, count);
3583 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3584 return WINED3DERR_INVALIDCALL;
3586 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3590 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3591 IWineD3DDevice *iface,
3593 CONST float *srcData,
3596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3599 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3600 iface, srcData, start, count);
3602 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3603 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3604 return WINED3DERR_INVALIDCALL;
3606 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3608 for (i = 0; i < count; i++)
3609 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3610 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3613 if (!This->isRecordingState)
3615 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3616 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3619 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3620 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3625 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3626 IWineD3DDevice *iface,
3631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3632 int cnt = min(count, This->d3d_vshader_constantF - start);
3634 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3635 iface, dstData, start, count);
3637 if (dstData == NULL || cnt < 0)
3638 return WINED3DERR_INVALIDCALL;
3640 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3644 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3646 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3648 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3652 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3653 int i = This->rev_tex_unit_map[unit];
3654 int j = This->texUnitMap[stage];
3656 This->texUnitMap[stage] = unit;
3657 if (i != -1 && i != stage) {
3658 This->texUnitMap[i] = -1;
3661 This->rev_tex_unit_map[unit] = stage;
3662 if (j != -1 && j != unit) {
3663 This->rev_tex_unit_map[j] = -1;
3667 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3670 This->fixed_function_usage_map = 0;
3671 for (i = 0; i < MAX_TEXTURES; ++i) {
3672 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3673 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3674 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3675 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3676 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3677 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3678 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3679 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3681 if (color_op == WINED3DTOP_DISABLE) {
3682 /* Not used, and disable higher stages */
3686 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3687 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3688 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3689 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3690 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3691 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3692 This->fixed_function_usage_map |= (1 << i);
3695 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3696 This->fixed_function_usage_map |= (1 << (i + 1));
3701 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3702 unsigned int i, tex;
3705 device_update_fixed_function_usage_map(This);
3706 ffu_map = This->fixed_function_usage_map;
3708 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3709 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3710 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3712 if (!(ffu_map & 1)) continue;
3714 if (This->texUnitMap[i] != i) {
3715 device_map_stage(This, i, i);
3716 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3717 markTextureStagesDirty(This, i);
3723 /* Now work out the mapping */
3725 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3727 if (!(ffu_map & 1)) continue;
3729 if (This->texUnitMap[i] != tex) {
3730 device_map_stage(This, i, tex);
3731 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3732 markTextureStagesDirty(This, i);
3739 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3740 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3741 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3744 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3745 if (sampler_type[i] && This->texUnitMap[i] != i)
3747 device_map_stage(This, i, i);
3748 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3749 if (i < MAX_TEXTURES) {
3750 markTextureStagesDirty(This, i);
3756 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3757 const DWORD *vshader_sampler_tokens, int unit)
3759 int current_mapping = This->rev_tex_unit_map[unit];
3761 if (current_mapping == -1) {
3762 /* Not currently used */
3766 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3767 /* Used by a fragment sampler */
3769 if (!pshader_sampler_tokens) {
3770 /* No pixel shader, check fixed function */
3771 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3774 /* Pixel shader, check the shader's sampler map */
3775 return !pshader_sampler_tokens[current_mapping];
3778 /* Used by a vertex sampler */
3779 return !vshader_sampler_tokens[current_mapping];
3782 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3783 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3784 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3785 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3786 int start = GL_LIMITS(combined_samplers) - 1;
3790 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3792 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3793 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3794 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3797 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3798 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3799 if (vshader_sampler_type[i])
3801 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3803 /* Already mapped somewhere */
3807 while (start >= 0) {
3808 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3810 device_map_stage(This, vsampler_idx, start);
3811 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3823 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3824 BOOL vs = use_vs(This->stateBlock);
3825 BOOL ps = use_ps(This->stateBlock);
3828 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3829 * that would be really messy and require shader recompilation
3830 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3831 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3834 device_map_psamplers(This);
3836 device_map_fixed_function_samplers(This);
3840 device_map_vsamplers(This, ps);
3844 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3846 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3847 This->updateStateBlock->pixelShader = pShader;
3848 This->updateStateBlock->changed.pixelShader = TRUE;
3850 /* Handle recording of state blocks */
3851 if (This->isRecordingState) {
3852 TRACE("Recording... not performing anything\n");
3855 if (This->isRecordingState) {
3856 TRACE("Recording... not performing anything\n");
3857 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3858 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3862 if(pShader == oldShader) {
3863 TRACE("App is setting the old pixel shader over, nothing to do\n");
3867 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3868 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3870 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3871 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3876 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3879 if (NULL == ppShader) {
3880 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3881 return WINED3DERR_INVALIDCALL;
3884 *ppShader = This->stateBlock->pixelShader;
3885 if (NULL != *ppShader) {
3886 IWineD3DPixelShader_AddRef(*ppShader);
3888 TRACE("(%p) : returning %p\n", This, *ppShader);
3892 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3893 IWineD3DDevice *iface,
3895 CONST BOOL *srcData,
3898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3899 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3901 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3902 iface, srcData, start, count);
3904 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3906 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3907 for (i = 0; i < cnt; i++)
3908 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3910 for (i = start; i < cnt + start; ++i) {
3911 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3914 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3919 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3920 IWineD3DDevice *iface,
3925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3926 int cnt = min(count, MAX_CONST_B - start);
3928 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3929 iface, dstData, start, count);
3931 if (dstData == NULL || cnt < 0)
3932 return WINED3DERR_INVALIDCALL;
3934 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3938 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3939 IWineD3DDevice *iface,
3944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3945 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3947 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3948 iface, srcData, start, count);
3950 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3952 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3953 for (i = 0; i < cnt; i++)
3954 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3955 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3957 for (i = start; i < cnt + start; ++i) {
3958 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3961 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3966 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3967 IWineD3DDevice *iface,
3972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3973 int cnt = min(count, MAX_CONST_I - start);
3975 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3976 iface, dstData, start, count);
3978 if (dstData == NULL || cnt < 0)
3979 return WINED3DERR_INVALIDCALL;
3981 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3985 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3986 IWineD3DDevice *iface,
3988 CONST float *srcData,
3991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3994 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3995 iface, srcData, start, count);
3997 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3998 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3999 return WINED3DERR_INVALIDCALL;
4001 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4003 for (i = 0; i < count; i++)
4004 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4005 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4008 if (!This->isRecordingState)
4010 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4011 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4014 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4015 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4020 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4021 IWineD3DDevice *iface,
4026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4027 int cnt = min(count, This->d3d_pshader_constantF - start);
4029 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4030 iface, dstData, start, count);
4032 if (dstData == NULL || cnt < 0)
4033 return WINED3DERR_INVALIDCALL;
4035 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4039 /* Context activation is done by the caller. */
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);
5752 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5753 srcSurfaceWidth = winedesc.width;
5754 srcSurfaceHeight = winedesc.height;
5755 srcPool = winedesc.pool;
5756 srcFormat = winedesc.format;
5758 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5759 destSurfaceWidth = winedesc.width;
5760 destSurfaceHeight = winedesc.height;
5761 destPool = winedesc.pool;
5762 destFormat = winedesc.format;
5763 destSize = winedesc.size;
5765 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5766 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5767 return WINED3DERR_INVALIDCALL;
5770 /* This call loads the opengl surface directly, instead of copying the surface to the
5771 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5772 * copy in sysmem and use regular surface loading.
5774 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5775 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5776 if(convert != NO_CONVERSION) {
5777 return IWineD3DSurface_BltFast(pDestinationSurface,
5778 pDestPoint ? pDestPoint->x : 0,
5779 pDestPoint ? pDestPoint->y : 0,
5780 pSourceSurface, pSourceRect, 0);
5783 if (destFormat == WINED3DFMT_UNKNOWN) {
5784 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5785 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5787 /* Get the update surface description */
5788 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5791 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5794 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5795 checkGLcall("glActiveTextureARB");
5798 /* Make sure the surface is loaded and up to date */
5799 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5800 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5802 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5804 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5805 dst_format_desc = ((IWineD3DSurfaceImpl *)pDestinationSurface)->resource.format_desc;
5807 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5808 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5809 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5810 srcLeft = pSourceRect ? pSourceRect->left : 0;
5811 destLeft = pDestPoint ? pDestPoint->x : 0;
5812 destTop = pDestPoint ? pDestPoint->y : 0;
5815 /* This function doesn't support compressed textures
5816 the pitch is just bytesPerPixel * width */
5817 if(srcWidth != srcSurfaceWidth || srcLeft ){
5818 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5819 offset += srcLeft * src_format_desc->byte_count;
5820 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5822 /* TODO DXT formats */
5824 if(pSourceRect != NULL && pSourceRect->top != 0){
5825 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5827 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5828 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5829 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5832 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5834 /* need to lock the surface to get the data */
5835 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5840 /* TODO: Cube and volume support */
5842 /* not a whole row so we have to do it a line at a time */
5845 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5846 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5848 for (j = destTop; j < (srcHeight + destTop); ++j)
5850 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, j,
5851 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5855 } else { /* Full width, so just write out the whole texture */
5856 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5858 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5860 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5862 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5863 FIXME("Updating part of a compressed texture is not supported.\n");
5865 if (destFormat != srcFormat)
5867 FIXME("Updating mixed format compressed textures is not supported.\n");
5871 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
5872 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5877 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
5878 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5881 checkGLcall("glTexSubImage2D");
5885 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5886 sampler = This->rev_tex_unit_map[0];
5887 if (sampler != -1) {
5888 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5894 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5896 struct WineD3DRectPatch *patch;
5897 GLenum old_primitive_type;
5901 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5903 if(!(Handle || pRectPatchInfo)) {
5904 /* TODO: Write a test for the return value, thus the FIXME */
5905 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5906 return WINED3DERR_INVALIDCALL;
5910 i = PATCHMAP_HASHFUNC(Handle);
5912 LIST_FOR_EACH(e, &This->patches[i]) {
5913 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5914 if(patch->Handle == Handle) {
5921 TRACE("Patch does not exist. Creating a new one\n");
5922 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5923 patch->Handle = Handle;
5924 list_add_head(&This->patches[i], &patch->entry);
5926 TRACE("Found existing patch %p\n", patch);
5929 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5930 * attributes we have to tesselate, read back, and draw. This needs a patch
5931 * management structure instance. Create one.
5933 * A possible improvement is to check if a vertex shader is used, and if not directly
5936 FIXME("Drawing an uncached patch. This is slow\n");
5937 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5940 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5941 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5942 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5944 TRACE("Tesselation density or patch info changed, retesselating\n");
5946 if(pRectPatchInfo) {
5947 patch->RectPatchInfo = *pRectPatchInfo;
5949 patch->numSegs[0] = pNumSegs[0];
5950 patch->numSegs[1] = pNumSegs[1];
5951 patch->numSegs[2] = pNumSegs[2];
5952 patch->numSegs[3] = pNumSegs[3];
5954 hr = tesselate_rectpatch(This, patch);
5956 WARN("Patch tesselation failed\n");
5958 /* Do not release the handle to store the params of the patch */
5960 HeapFree(GetProcessHeap(), 0, patch);
5966 This->currentPatch = patch;
5967 old_primitive_type = This->stateBlock->gl_primitive_type;
5968 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5969 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5970 This->stateBlock->gl_primitive_type = old_primitive_type;
5971 This->currentPatch = NULL;
5973 /* Destroy uncached patches */
5975 HeapFree(GetProcessHeap(), 0, patch->mem);
5976 HeapFree(GetProcessHeap(), 0, patch);
5981 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5983 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5984 FIXME("(%p) : Stub\n", This);
5988 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5989 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5991 struct WineD3DRectPatch *patch;
5993 TRACE("(%p) Handle(%d)\n", This, Handle);
5995 i = PATCHMAP_HASHFUNC(Handle);
5996 LIST_FOR_EACH(e, &This->patches[i]) {
5997 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5998 if(patch->Handle == Handle) {
5999 TRACE("Deleting patch %p\n", patch);
6000 list_remove(&patch->entry);
6001 HeapFree(GetProcessHeap(), 0, patch->mem);
6002 HeapFree(GetProcessHeap(), 0, patch);
6007 /* TODO: Write a test for the return value */
6008 FIXME("Attempt to destroy nonexistent patch\n");
6009 return WINED3DERR_INVALIDCALL;
6012 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6014 IWineD3DSwapChain *swapchain;
6016 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6017 if (SUCCEEDED(hr)) {
6018 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6025 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6026 const WINED3DRECT *rect, const float color[4])
6028 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6029 IWineD3DSwapChain *swapchain;
6031 swapchain = get_swapchain(surface);
6035 TRACE("Surface %p is onscreen\n", surface);
6037 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6039 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6040 buffer = surface_get_gl_buffer(surface, swapchain);
6041 glDrawBuffer(buffer);
6042 checkGLcall("glDrawBuffer()");
6044 TRACE("Surface %p is offscreen\n", surface);
6046 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6048 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6049 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6050 context_attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, NULL, FALSE);
6054 glEnable(GL_SCISSOR_TEST);
6056 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6058 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6059 rect->x2 - rect->x1, rect->y2 - rect->y1);
6061 checkGLcall("glScissor");
6062 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6064 glDisable(GL_SCISSOR_TEST);
6066 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6068 glDisable(GL_BLEND);
6069 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6071 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6072 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6074 glClearColor(color[0], color[1], color[2], color[3]);
6075 glClear(GL_COLOR_BUFFER_BIT);
6076 checkGLcall("glClear");
6078 if (This->activeContext->current_fbo) {
6079 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6081 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6082 checkGLcall("glBindFramebuffer()");
6085 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6086 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6087 glDrawBuffer(GL_BACK);
6088 checkGLcall("glDrawBuffer()");
6094 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6095 unsigned int r, g, b, a;
6098 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6099 destfmt == WINED3DFMT_R8G8B8)
6102 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6104 a = (color & 0xff000000) >> 24;
6105 r = (color & 0x00ff0000) >> 16;
6106 g = (color & 0x0000ff00) >> 8;
6107 b = (color & 0x000000ff) >> 0;
6111 case WINED3DFMT_R5G6B5:
6112 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6119 TRACE("Returning %08x\n", ret);
6122 case WINED3DFMT_X1R5G5B5:
6123 case WINED3DFMT_A1R5G5B5:
6132 TRACE("Returning %08x\n", ret);
6135 case WINED3DFMT_A8_UNORM:
6136 TRACE("Returning %08x\n", a);
6139 case WINED3DFMT_X4R4G4B4:
6140 case WINED3DFMT_A4R4G4B4:
6149 TRACE("Returning %08x\n", ret);
6152 case WINED3DFMT_R3G3B2:
6159 TRACE("Returning %08x\n", ret);
6162 case WINED3DFMT_X8B8G8R8:
6163 case WINED3DFMT_R8G8B8A8_UNORM:
6168 TRACE("Returning %08x\n", ret);
6171 case WINED3DFMT_A2R10G10B10:
6173 r = (r * 1024) / 256;
6174 g = (g * 1024) / 256;
6175 b = (b * 1024) / 256;
6180 TRACE("Returning %08x\n", ret);
6183 case WINED3DFMT_R10G10B10A2_UNORM:
6185 r = (r * 1024) / 256;
6186 g = (g * 1024) / 256;
6187 b = (b * 1024) / 256;
6192 TRACE("Returning %08x\n", ret);
6196 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6201 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6203 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6205 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6207 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6208 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6209 return WINED3DERR_INVALIDCALL;
6212 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6213 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6214 color_fill_fbo(iface, pSurface, pRect, c);
6217 /* Just forward this to the DirectDraw blitting engine */
6218 memset(&BltFx, 0, sizeof(BltFx));
6219 BltFx.dwSize = sizeof(BltFx);
6220 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6221 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6222 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6226 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6227 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6229 IWineD3DResource *resource;
6230 IWineD3DSurface *surface;
6233 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6236 ERR("Failed to get resource, hr %#x\n", hr);
6240 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6242 FIXME("Only supported on surface resources\n");
6243 IWineD3DResource_Release(resource);
6247 surface = (IWineD3DSurface *)resource;
6249 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6251 color_fill_fbo(iface, surface, NULL, color);
6258 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6260 c = ((DWORD)(color[2] * 255.0));
6261 c |= ((DWORD)(color[1] * 255.0)) << 8;
6262 c |= ((DWORD)(color[0] * 255.0)) << 16;
6263 c |= ((DWORD)(color[3] * 255.0)) << 24;
6265 /* Just forward this to the DirectDraw blitting engine */
6266 memset(&BltFx, 0, sizeof(BltFx));
6267 BltFx.dwSize = sizeof(BltFx);
6268 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6269 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6272 ERR("Blt failed, hr %#x\n", hr);
6276 IWineD3DResource_Release(resource);
6279 /* rendertarget and depth stencil functions */
6280 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6283 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6284 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6285 return WINED3DERR_INVALIDCALL;
6288 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6289 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6290 /* Note inc ref on returned surface */
6291 if(*ppRenderTarget != NULL)
6292 IWineD3DSurface_AddRef(*ppRenderTarget);
6296 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6298 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6299 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6300 IWineD3DSwapChainImpl *Swapchain;
6303 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6305 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6306 if(hr != WINED3D_OK) {
6307 ERR("Can't get the swapchain\n");
6311 /* Make sure to release the swapchain */
6312 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6314 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6315 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6316 return WINED3DERR_INVALIDCALL;
6318 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6319 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6320 return WINED3DERR_INVALIDCALL;
6323 if(Swapchain->frontBuffer != Front) {
6324 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6326 if(Swapchain->frontBuffer)
6328 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6329 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6331 Swapchain->frontBuffer = Front;
6333 if(Swapchain->frontBuffer) {
6334 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6335 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6339 if(Back && !Swapchain->backBuffer) {
6340 /* We need memory for the back buffer array - only one back buffer this way */
6341 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6342 if(!Swapchain->backBuffer) {
6343 ERR("Out of memory\n");
6344 return E_OUTOFMEMORY;
6348 if(Swapchain->backBuffer[0] != Back) {
6349 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6351 /* What to do about the context here in the case of multithreading? Not sure.
6352 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6354 WARN("No active context?\n");
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 dst_swapchain = get_swapchain(dst_surface);
6439 if (src_swapchain) ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6440 else if (dst_swapchain) ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6441 else ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6443 if (src_swapchain) {
6444 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6446 TRACE("Source surface %p is onscreen\n", src_surface);
6447 /* Make sure the drawable is up to date. In the offscreen case
6448 * attach_surface_fbo() implicitly takes care of this. */
6449 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6451 if(buffer == GL_FRONT) {
6454 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6455 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6456 h = windowsize.bottom - windowsize.top;
6457 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6458 src_rect->y1 = offset.y + h - src_rect->y1;
6459 src_rect->y2 = offset.y + h - src_rect->y2;
6461 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6462 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6466 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6467 glReadBuffer(buffer);
6468 checkGLcall("glReadBuffer()");
6470 TRACE("Source surface %p is offscreen\n", src_surface);
6472 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6473 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6474 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6475 checkGLcall("glReadBuffer()");
6476 context_attach_depth_stencil_fbo(This, GL_READ_FRAMEBUFFER_EXT, NULL, FALSE);
6480 /* Attach dst surface to dst fbo */
6481 if (dst_swapchain) {
6482 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6484 TRACE("Destination surface %p is onscreen\n", dst_surface);
6485 /* Make sure the drawable is up to date. In the offscreen case
6486 * attach_surface_fbo() implicitly takes care of this. */
6487 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6489 if(buffer == GL_FRONT) {
6492 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6493 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6494 h = windowsize.bottom - windowsize.top;
6495 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6496 dst_rect->y1 = offset.y + h - dst_rect->y1;
6497 dst_rect->y2 = offset.y + h - dst_rect->y2;
6499 /* Screen coords = window coords, surface height = window height */
6500 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6501 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6505 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6506 glDrawBuffer(buffer);
6507 checkGLcall("glDrawBuffer()");
6509 TRACE("Destination surface %p is offscreen\n", dst_surface);
6512 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6513 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6514 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6515 checkGLcall("glDrawBuffer()");
6516 context_attach_depth_stencil_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, NULL, FALSE);
6518 glDisable(GL_SCISSOR_TEST);
6519 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6522 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6523 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6524 checkGLcall("glBlitFramebuffer()");
6526 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6527 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6528 checkGLcall("glBlitFramebuffer()");
6531 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6533 if (This->activeContext->current_fbo) {
6534 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6536 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6537 checkGLcall("glBindFramebuffer()");
6540 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6541 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6542 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6543 glDrawBuffer(GL_BACK);
6544 checkGLcall("glDrawBuffer()");
6549 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6551 WINED3DVIEWPORT viewport;
6553 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6555 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6556 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6557 This, RenderTargetIndex, GL_LIMITS(buffers));
6558 return WINED3DERR_INVALIDCALL;
6561 /* MSDN says that null disables the render target
6562 but a device must always be associated with a render target
6563 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6565 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6566 FIXME("Trying to set render target 0 to NULL\n");
6567 return WINED3DERR_INVALIDCALL;
6569 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6570 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);
6571 return WINED3DERR_INVALIDCALL;
6574 /* If we are trying to set what we already have, don't bother */
6575 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6576 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6579 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6580 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6581 This->render_targets[RenderTargetIndex] = pRenderTarget;
6583 /* Render target 0 is special */
6584 if(RenderTargetIndex == 0) {
6585 /* Finally, reset the viewport as the MSDN states. */
6586 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6587 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6590 viewport.MaxZ = 1.0f;
6591 viewport.MinZ = 0.0f;
6592 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6593 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6594 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6596 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6601 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6603 HRESULT hr = WINED3D_OK;
6604 IWineD3DSurface *tmp;
6606 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6608 if (pNewZStencil == This->stencilBufferTarget) {
6609 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6611 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6612 * depending on the renter target implementation being used.
6613 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6614 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6615 * stencil buffer and incur an extra memory overhead
6616 ******************************************************/
6618 if (This->stencilBufferTarget) {
6619 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6620 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6621 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6623 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6624 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6625 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6629 tmp = This->stencilBufferTarget;
6630 This->stencilBufferTarget = pNewZStencil;
6631 /* should we be calling the parent or the wined3d surface? */
6632 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6633 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6636 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6637 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6638 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6639 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6640 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6647 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6648 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6650 /* TODO: the use of Impl is deprecated. */
6651 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6652 WINED3DLOCKED_RECT lockedRect;
6654 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6656 /* some basic validation checks */
6657 if(This->cursorTexture) {
6658 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6660 glDeleteTextures(1, &This->cursorTexture);
6662 This->cursorTexture = 0;
6665 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6666 This->haveHardwareCursor = TRUE;
6668 This->haveHardwareCursor = FALSE;
6671 WINED3DLOCKED_RECT rect;
6673 /* MSDN: Cursor must be A8R8G8B8 */
6674 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
6676 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6677 return WINED3DERR_INVALIDCALL;
6680 /* MSDN: Cursor must be smaller than the display mode */
6681 if(pSur->currentDesc.Width > This->ddraw_width ||
6682 pSur->currentDesc.Height > This->ddraw_height) {
6683 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);
6684 return WINED3DERR_INVALIDCALL;
6687 if (!This->haveHardwareCursor) {
6688 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6690 /* Do not store the surface's pointer because the application may
6691 * release it after setting the cursor image. Windows doesn't
6692 * addref the set surface, so we can't do this either without
6693 * creating circular refcount dependencies. Copy out the gl texture
6696 This->cursorWidth = pSur->currentDesc.Width;
6697 This->cursorHeight = pSur->currentDesc.Height;
6698 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6700 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
6701 char *mem, *bits = rect.pBits;
6702 GLint intfmt = glDesc->glInternal;
6703 GLint format = glDesc->glFormat;
6704 GLint type = glDesc->glType;
6705 INT height = This->cursorHeight;
6706 INT width = This->cursorWidth;
6707 INT bpp = glDesc->byte_count;
6710 /* Reformat the texture memory (pitch and width can be
6712 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6713 for(i = 0; i < height; i++)
6714 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6715 IWineD3DSurface_UnlockRect(pCursorBitmap);
6717 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6721 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6722 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6723 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6726 /* Make sure that a proper texture unit is selected */
6727 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6728 checkGLcall("glActiveTextureARB");
6729 sampler = This->rev_tex_unit_map[0];
6730 if (sampler != -1) {
6731 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6733 /* Create a new cursor texture */
6734 glGenTextures(1, &This->cursorTexture);
6735 checkGLcall("glGenTextures");
6736 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6737 checkGLcall("glBindTexture");
6738 /* Copy the bitmap memory into the cursor texture */
6739 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6740 HeapFree(GetProcessHeap(), 0, mem);
6741 checkGLcall("glTexImage2D");
6743 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6744 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6745 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6752 FIXME("A cursor texture was not returned.\n");
6753 This->cursorTexture = 0;
6758 /* Draw a hardware cursor */
6759 ICONINFO cursorInfo;
6761 /* Create and clear maskBits because it is not needed for
6762 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6764 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6765 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6766 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6767 WINED3DLOCK_NO_DIRTY_UPDATE |
6768 WINED3DLOCK_READONLY
6770 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6771 pSur->currentDesc.Height);
6773 cursorInfo.fIcon = FALSE;
6774 cursorInfo.xHotspot = XHotSpot;
6775 cursorInfo.yHotspot = YHotSpot;
6776 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6777 pSur->currentDesc.Height, 1,
6779 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6780 pSur->currentDesc.Height, 1,
6781 32, lockedRect.pBits);
6782 IWineD3DSurface_UnlockRect(pCursorBitmap);
6783 /* Create our cursor and clean up. */
6784 cursor = CreateIconIndirect(&cursorInfo);
6786 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6787 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6788 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6789 This->hardwareCursor = cursor;
6790 HeapFree(GetProcessHeap(), 0, maskBits);
6794 This->xHotSpot = XHotSpot;
6795 This->yHotSpot = YHotSpot;
6799 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6801 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6803 This->xScreenSpace = XScreenSpace;
6804 This->yScreenSpace = YScreenSpace;
6810 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6812 BOOL oldVisible = This->bCursorVisible;
6815 TRACE("(%p) : visible(%d)\n", This, bShow);
6818 * When ShowCursor is first called it should make the cursor appear at the OS's last
6819 * known cursor position. Because of this, some applications just repetitively call
6820 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6823 This->xScreenSpace = pt.x;
6824 This->yScreenSpace = pt.y;
6826 if (This->haveHardwareCursor) {
6827 This->bCursorVisible = bShow;
6829 SetCursor(This->hardwareCursor);
6835 if (This->cursorTexture)
6836 This->bCursorVisible = bShow;
6842 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6844 IWineD3DResourceImpl *resource;
6845 TRACE("(%p) : state (%u)\n", This, This->state);
6847 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6848 switch (This->state) {
6851 case WINED3DERR_DEVICELOST:
6853 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6854 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6855 return WINED3DERR_DEVICENOTRESET;
6857 return WINED3DERR_DEVICELOST;
6859 case WINED3DERR_DRIVERINTERNALERROR:
6860 return WINED3DERR_DRIVERINTERNALERROR;
6864 return WINED3DERR_DRIVERINTERNALERROR;
6867 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6868 TRACE("checking resource %p for eviction\n", resource);
6869 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6870 TRACE("Evicting %p\n", resource);
6871 IWineD3DResource_UnLoad(resource);
6873 IWineD3DResource_Release(resource);
6877 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6879 TRACE("(%p)\n", This);
6881 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6885 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6887 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6889 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6890 if(surface->Flags & SFLAG_DIBSECTION) {
6891 /* Release the DC */
6892 SelectObject(surface->hDC, surface->dib.holdbitmap);
6893 DeleteDC(surface->hDC);
6894 /* Release the DIB section */
6895 DeleteObject(surface->dib.DIBsection);
6896 surface->dib.bitmap_data = NULL;
6897 surface->resource.allocatedMemory = NULL;
6898 surface->Flags &= ~SFLAG_DIBSECTION;
6900 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6901 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6902 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6903 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6904 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6905 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6907 surface->pow2Width = surface->pow2Height = 1;
6908 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6909 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6911 surface->glRect.left = 0;
6912 surface->glRect.top = 0;
6913 surface->glRect.right = surface->pow2Width;
6914 surface->glRect.bottom = surface->pow2Height;
6916 if(surface->glDescription.textureName) {
6917 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6919 glDeleteTextures(1, &surface->glDescription.textureName);
6921 surface->glDescription.textureName = 0;
6922 surface->Flags &= ~SFLAG_CLIENT;
6924 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6925 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6926 surface->Flags |= SFLAG_NONPOW2;
6928 surface->Flags &= ~SFLAG_NONPOW2;
6930 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6931 surface->resource.allocatedMemory = NULL;
6932 surface->resource.heapMemory = NULL;
6933 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6934 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6935 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6936 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6938 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6942 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6943 TRACE("Unloading resource %p\n", resource);
6944 IWineD3DResource_UnLoad(resource);
6945 IWineD3DResource_Release(resource);
6949 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6952 WINED3DDISPLAYMODE m;
6955 /* All Windowed modes are supported, as is leaving the current mode */
6956 if(pp->Windowed) return TRUE;
6957 if(!pp->BackBufferWidth) return TRUE;
6958 if(!pp->BackBufferHeight) return TRUE;
6960 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6961 for(i = 0; i < count; i++) {
6962 memset(&m, 0, sizeof(m));
6963 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6965 ERR("EnumAdapterModes failed\n");
6967 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6968 /* Mode found, it is supported */
6972 /* Mode not found -> not supported */
6976 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6978 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6980 IWineD3DBaseShaderImpl *shader;
6982 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6984 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6985 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6986 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6990 if(This->depth_blt_texture) {
6991 glDeleteTextures(1, &This->depth_blt_texture);
6992 This->depth_blt_texture = 0;
6994 if (This->depth_blt_rb) {
6995 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
6996 This->depth_blt_rb = 0;
6997 This->depth_blt_rb_w = 0;
6998 This->depth_blt_rb_h = 0;
7002 This->blitter->free_private(iface);
7003 This->frag_pipe->free_private(iface);
7004 This->shader_backend->shader_free_private(iface);
7007 for (i = 0; i < GL_LIMITS(textures); i++) {
7008 /* Textures are recreated below */
7009 glDeleteTextures(1, &This->dummyTextureName[i]);
7010 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7011 This->dummyTextureName[i] = 0;
7015 while(This->numContexts) {
7016 DestroyContext(This, This->contexts[0]);
7018 This->activeContext = NULL;
7019 HeapFree(GetProcessHeap(), 0, swapchain->context);
7020 swapchain->context = NULL;
7021 swapchain->num_contexts = 0;
7024 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7026 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7028 IWineD3DSurfaceImpl *target;
7030 /* Recreate the primary swapchain's context */
7031 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7032 if(swapchain->backBuffer) {
7033 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7035 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7037 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7038 &swapchain->presentParms);
7039 swapchain->num_contexts = 1;
7040 This->activeContext = swapchain->context[0];
7042 create_dummy_textures(This);
7044 hr = This->shader_backend->shader_alloc_private(iface);
7046 ERR("Failed to recreate shader private data\n");
7049 hr = This->frag_pipe->alloc_private(iface);
7051 TRACE("Fragment pipeline private data couldn't be allocated\n");
7054 hr = This->blitter->alloc_private(iface);
7056 TRACE("Blitter private data couldn't be allocated\n");
7063 This->blitter->free_private(iface);
7064 This->frag_pipe->free_private(iface);
7065 This->shader_backend->shader_free_private(iface);
7069 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7071 IWineD3DSwapChainImpl *swapchain;
7073 BOOL DisplayModeChanged = FALSE;
7074 WINED3DDISPLAYMODE mode;
7075 TRACE("(%p)\n", This);
7077 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7079 ERR("Failed to get the first implicit swapchain\n");
7083 if(!is_display_mode_supported(This, pPresentationParameters)) {
7084 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7085 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7086 pPresentationParameters->BackBufferHeight);
7087 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7088 return WINED3DERR_INVALIDCALL;
7091 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7092 * on an existing gl context, so there's no real need for recreation.
7094 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7096 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7098 TRACE("New params:\n");
7099 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7100 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7101 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7102 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7103 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7104 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7105 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7106 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7107 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7108 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7109 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7110 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7111 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7113 /* No special treatment of these parameters. Just store them */
7114 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7115 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7116 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7117 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7119 /* What to do about these? */
7120 if(pPresentationParameters->BackBufferCount != 0 &&
7121 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7122 ERR("Cannot change the back buffer count yet\n");
7124 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7125 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7126 ERR("Cannot change the back buffer format yet\n");
7128 if(pPresentationParameters->hDeviceWindow != NULL &&
7129 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7130 ERR("Cannot change the device window yet\n");
7132 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7135 TRACE("Creating the depth stencil buffer\n");
7137 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
7139 pPresentationParameters->BackBufferWidth,
7140 pPresentationParameters->BackBufferHeight,
7141 pPresentationParameters->AutoDepthStencilFormat,
7142 pPresentationParameters->MultiSampleType,
7143 pPresentationParameters->MultiSampleQuality,
7145 &This->auto_depth_stencil_buffer);
7148 ERR("Failed to create the depth stencil buffer\n");
7149 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7150 return WINED3DERR_INVALIDCALL;
7154 /* Reset the depth stencil */
7155 if (pPresentationParameters->EnableAutoDepthStencil)
7156 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7158 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7160 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7162 if(pPresentationParameters->Windowed) {
7163 mode.Width = swapchain->orig_width;
7164 mode.Height = swapchain->orig_height;
7165 mode.RefreshRate = 0;
7166 mode.Format = swapchain->presentParms.BackBufferFormat;
7168 mode.Width = pPresentationParameters->BackBufferWidth;
7169 mode.Height = pPresentationParameters->BackBufferHeight;
7170 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7171 mode.Format = swapchain->presentParms.BackBufferFormat;
7174 /* Should Width == 800 && Height == 0 set 800x600? */
7175 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7176 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7177 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7181 if(!pPresentationParameters->Windowed) {
7182 DisplayModeChanged = TRUE;
7184 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7185 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7187 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7188 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7189 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7191 if(This->auto_depth_stencil_buffer) {
7192 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7196 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7197 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7198 DisplayModeChanged) {
7200 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7202 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7203 if(swapchain->presentParms.Windowed) {
7204 /* switch from windowed to fs */
7205 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7206 pPresentationParameters->BackBufferWidth,
7207 pPresentationParameters->BackBufferHeight);
7209 /* Fullscreen -> fullscreen mode change */
7210 MoveWindow(swapchain->win_handle, 0, 0,
7211 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7214 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7215 /* Fullscreen -> windowed switch */
7216 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7218 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7219 } else if(!pPresentationParameters->Windowed) {
7220 DWORD style = This->style, exStyle = This->exStyle;
7221 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7222 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7223 * Reset to clear up their mess. Guild Wars also loses the device during that.
7227 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7228 pPresentationParameters->BackBufferWidth,
7229 pPresentationParameters->BackBufferHeight);
7230 This->style = style;
7231 This->exStyle = exStyle;
7234 TRACE("Resetting stateblock\n");
7235 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7236 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7238 /* Note: No parent needed for initial internal stateblock */
7239 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7240 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7241 else TRACE("Created stateblock %p\n", This->stateBlock);
7242 This->updateStateBlock = This->stateBlock;
7243 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7245 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7247 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7250 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7251 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7253 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7259 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7261 /** FIXME: always true at the moment **/
7262 if(!bEnableDialogs) {
7263 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7269 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7271 TRACE("(%p) : pParameters %p\n", This, pParameters);
7273 *pParameters = This->createParms;
7277 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7278 IWineD3DSwapChain *swapchain;
7280 TRACE("Relaying to swapchain\n");
7282 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7283 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7284 IWineD3DSwapChain_Release(swapchain);
7289 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7290 IWineD3DSwapChain *swapchain;
7292 TRACE("Relaying to swapchain\n");
7294 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7295 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7296 IWineD3DSwapChain_Release(swapchain);
7302 /** ********************************************************
7303 * Notification functions
7304 ** ********************************************************/
7305 /** This function must be called in the release of a resource when ref == 0,
7306 * the contents of resource must still be correct,
7307 * any handles to other resource held by the caller must be closed
7308 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7309 *****************************************************/
7310 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7312 TRACE("(%p) : Adding resource %p\n", This, resource);
7314 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7317 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7319 TRACE("(%p) : Removing resource %p\n", This, resource);
7321 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7324 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7326 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7329 TRACE("(%p) : resource %p\n", This, resource);
7331 context_resource_released((IWineD3DDevice *)This, resource, type);
7334 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7335 case WINED3DRTYPE_SURFACE: {
7338 if (This->d3d_initialized)
7340 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7341 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7342 This->render_targets[i] = NULL;
7345 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7346 This->stencilBufferTarget = NULL;
7352 case WINED3DRTYPE_TEXTURE:
7353 case WINED3DRTYPE_CUBETEXTURE:
7354 case WINED3DRTYPE_VOLUMETEXTURE:
7355 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7356 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7357 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7358 This->stateBlock->textures[counter] = NULL;
7360 if (This->updateStateBlock != This->stateBlock ){
7361 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7362 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7363 This->updateStateBlock->textures[counter] = NULL;
7368 case WINED3DRTYPE_VOLUME:
7369 /* TODO: nothing really? */
7371 case WINED3DRTYPE_BUFFER:
7374 TRACE("Cleaning up stream pointers\n");
7376 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7377 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7378 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7380 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7381 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7382 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7383 This->updateStateBlock->streamSource[streamNumber] = 0;
7384 /* Set changed flag? */
7387 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) */
7388 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7389 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7390 This->stateBlock->streamSource[streamNumber] = 0;
7395 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7396 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7397 This->updateStateBlock->pIndexData = NULL;
7400 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7401 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7402 This->stateBlock->pIndexData = NULL;
7409 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7414 /* Remove the resource from the resourceStore */
7415 device_resource_remove(This, resource);
7417 TRACE("Resource released\n");
7421 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7423 IWineD3DResourceImpl *resource, *cursor;
7425 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7427 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7428 TRACE("enumerating resource %p\n", resource);
7429 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7430 ret = pCallback((IWineD3DResource *) resource, pData);
7431 if(ret == S_FALSE) {
7432 TRACE("Canceling enumeration\n");
7439 /**********************************************************
7440 * IWineD3DDevice VTbl follows
7441 **********************************************************/
7443 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7445 /*** IUnknown methods ***/
7446 IWineD3DDeviceImpl_QueryInterface,
7447 IWineD3DDeviceImpl_AddRef,
7448 IWineD3DDeviceImpl_Release,
7449 /*** IWineD3DDevice methods ***/
7450 IWineD3DDeviceImpl_GetParent,
7451 /*** Creation methods**/
7452 IWineD3DDeviceImpl_CreateBuffer,
7453 IWineD3DDeviceImpl_CreateVertexBuffer,
7454 IWineD3DDeviceImpl_CreateIndexBuffer,
7455 IWineD3DDeviceImpl_CreateStateBlock,
7456 IWineD3DDeviceImpl_CreateSurface,
7457 IWineD3DDeviceImpl_CreateRendertargetView,
7458 IWineD3DDeviceImpl_CreateTexture,
7459 IWineD3DDeviceImpl_CreateVolumeTexture,
7460 IWineD3DDeviceImpl_CreateVolume,
7461 IWineD3DDeviceImpl_CreateCubeTexture,
7462 IWineD3DDeviceImpl_CreateQuery,
7463 IWineD3DDeviceImpl_CreateSwapChain,
7464 IWineD3DDeviceImpl_CreateVertexDeclaration,
7465 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7466 IWineD3DDeviceImpl_CreateVertexShader,
7467 IWineD3DDeviceImpl_CreatePixelShader,
7468 IWineD3DDeviceImpl_CreatePalette,
7469 /*** Odd functions **/
7470 IWineD3DDeviceImpl_Init3D,
7471 IWineD3DDeviceImpl_InitGDI,
7472 IWineD3DDeviceImpl_Uninit3D,
7473 IWineD3DDeviceImpl_UninitGDI,
7474 IWineD3DDeviceImpl_SetMultithreaded,
7475 IWineD3DDeviceImpl_EvictManagedResources,
7476 IWineD3DDeviceImpl_GetAvailableTextureMem,
7477 IWineD3DDeviceImpl_GetBackBuffer,
7478 IWineD3DDeviceImpl_GetCreationParameters,
7479 IWineD3DDeviceImpl_GetDeviceCaps,
7480 IWineD3DDeviceImpl_GetDirect3D,
7481 IWineD3DDeviceImpl_GetDisplayMode,
7482 IWineD3DDeviceImpl_SetDisplayMode,
7483 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7484 IWineD3DDeviceImpl_GetRasterStatus,
7485 IWineD3DDeviceImpl_GetSwapChain,
7486 IWineD3DDeviceImpl_Reset,
7487 IWineD3DDeviceImpl_SetDialogBoxMode,
7488 IWineD3DDeviceImpl_SetCursorProperties,
7489 IWineD3DDeviceImpl_SetCursorPosition,
7490 IWineD3DDeviceImpl_ShowCursor,
7491 IWineD3DDeviceImpl_TestCooperativeLevel,
7492 /*** Getters and setters **/
7493 IWineD3DDeviceImpl_SetClipPlane,
7494 IWineD3DDeviceImpl_GetClipPlane,
7495 IWineD3DDeviceImpl_SetClipStatus,
7496 IWineD3DDeviceImpl_GetClipStatus,
7497 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7498 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7499 IWineD3DDeviceImpl_SetDepthStencilSurface,
7500 IWineD3DDeviceImpl_GetDepthStencilSurface,
7501 IWineD3DDeviceImpl_SetGammaRamp,
7502 IWineD3DDeviceImpl_GetGammaRamp,
7503 IWineD3DDeviceImpl_SetIndices,
7504 IWineD3DDeviceImpl_GetIndices,
7505 IWineD3DDeviceImpl_SetBaseVertexIndex,
7506 IWineD3DDeviceImpl_GetBaseVertexIndex,
7507 IWineD3DDeviceImpl_SetLight,
7508 IWineD3DDeviceImpl_GetLight,
7509 IWineD3DDeviceImpl_SetLightEnable,
7510 IWineD3DDeviceImpl_GetLightEnable,
7511 IWineD3DDeviceImpl_SetMaterial,
7512 IWineD3DDeviceImpl_GetMaterial,
7513 IWineD3DDeviceImpl_SetNPatchMode,
7514 IWineD3DDeviceImpl_GetNPatchMode,
7515 IWineD3DDeviceImpl_SetPaletteEntries,
7516 IWineD3DDeviceImpl_GetPaletteEntries,
7517 IWineD3DDeviceImpl_SetPixelShader,
7518 IWineD3DDeviceImpl_GetPixelShader,
7519 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7520 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7521 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7522 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7523 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7524 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7525 IWineD3DDeviceImpl_SetRenderState,
7526 IWineD3DDeviceImpl_GetRenderState,
7527 IWineD3DDeviceImpl_SetRenderTarget,
7528 IWineD3DDeviceImpl_GetRenderTarget,
7529 IWineD3DDeviceImpl_SetFrontBackBuffers,
7530 IWineD3DDeviceImpl_SetSamplerState,
7531 IWineD3DDeviceImpl_GetSamplerState,
7532 IWineD3DDeviceImpl_SetScissorRect,
7533 IWineD3DDeviceImpl_GetScissorRect,
7534 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7535 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7536 IWineD3DDeviceImpl_SetStreamSource,
7537 IWineD3DDeviceImpl_GetStreamSource,
7538 IWineD3DDeviceImpl_SetStreamSourceFreq,
7539 IWineD3DDeviceImpl_GetStreamSourceFreq,
7540 IWineD3DDeviceImpl_SetTexture,
7541 IWineD3DDeviceImpl_GetTexture,
7542 IWineD3DDeviceImpl_SetTextureStageState,
7543 IWineD3DDeviceImpl_GetTextureStageState,
7544 IWineD3DDeviceImpl_SetTransform,
7545 IWineD3DDeviceImpl_GetTransform,
7546 IWineD3DDeviceImpl_SetVertexDeclaration,
7547 IWineD3DDeviceImpl_GetVertexDeclaration,
7548 IWineD3DDeviceImpl_SetVertexShader,
7549 IWineD3DDeviceImpl_GetVertexShader,
7550 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7551 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7552 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7553 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7554 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7555 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7556 IWineD3DDeviceImpl_SetViewport,
7557 IWineD3DDeviceImpl_GetViewport,
7558 IWineD3DDeviceImpl_MultiplyTransform,
7559 IWineD3DDeviceImpl_ValidateDevice,
7560 IWineD3DDeviceImpl_ProcessVertices,
7561 /*** State block ***/
7562 IWineD3DDeviceImpl_BeginStateBlock,
7563 IWineD3DDeviceImpl_EndStateBlock,
7564 /*** Scene management ***/
7565 IWineD3DDeviceImpl_BeginScene,
7566 IWineD3DDeviceImpl_EndScene,
7567 IWineD3DDeviceImpl_Present,
7568 IWineD3DDeviceImpl_Clear,
7569 IWineD3DDeviceImpl_ClearRendertargetView,
7571 IWineD3DDeviceImpl_SetPrimitiveType,
7572 IWineD3DDeviceImpl_GetPrimitiveType,
7573 IWineD3DDeviceImpl_DrawPrimitive,
7574 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7575 IWineD3DDeviceImpl_DrawPrimitiveUP,
7576 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7577 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7578 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7579 IWineD3DDeviceImpl_DrawRectPatch,
7580 IWineD3DDeviceImpl_DrawTriPatch,
7581 IWineD3DDeviceImpl_DeletePatch,
7582 IWineD3DDeviceImpl_ColorFill,
7583 IWineD3DDeviceImpl_UpdateTexture,
7584 IWineD3DDeviceImpl_UpdateSurface,
7585 IWineD3DDeviceImpl_GetFrontBufferData,
7586 /*** object tracking ***/
7587 IWineD3DDeviceImpl_EnumResources
7590 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7591 WINED3DRS_ALPHABLENDENABLE ,
7592 WINED3DRS_ALPHAFUNC ,
7593 WINED3DRS_ALPHAREF ,
7594 WINED3DRS_ALPHATESTENABLE ,
7596 WINED3DRS_COLORWRITEENABLE ,
7597 WINED3DRS_DESTBLEND ,
7598 WINED3DRS_DITHERENABLE ,
7599 WINED3DRS_FILLMODE ,
7600 WINED3DRS_FOGDENSITY ,
7602 WINED3DRS_FOGSTART ,
7603 WINED3DRS_LASTPIXEL ,
7604 WINED3DRS_SHADEMODE ,
7605 WINED3DRS_SRCBLEND ,
7606 WINED3DRS_STENCILENABLE ,
7607 WINED3DRS_STENCILFAIL ,
7608 WINED3DRS_STENCILFUNC ,
7609 WINED3DRS_STENCILMASK ,
7610 WINED3DRS_STENCILPASS ,
7611 WINED3DRS_STENCILREF ,
7612 WINED3DRS_STENCILWRITEMASK ,
7613 WINED3DRS_STENCILZFAIL ,
7614 WINED3DRS_TEXTUREFACTOR ,
7625 WINED3DRS_ZWRITEENABLE
7628 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7629 WINED3DTSS_ALPHAARG0 ,
7630 WINED3DTSS_ALPHAARG1 ,
7631 WINED3DTSS_ALPHAARG2 ,
7632 WINED3DTSS_ALPHAOP ,
7633 WINED3DTSS_BUMPENVLOFFSET ,
7634 WINED3DTSS_BUMPENVLSCALE ,
7635 WINED3DTSS_BUMPENVMAT00 ,
7636 WINED3DTSS_BUMPENVMAT01 ,
7637 WINED3DTSS_BUMPENVMAT10 ,
7638 WINED3DTSS_BUMPENVMAT11 ,
7639 WINED3DTSS_COLORARG0 ,
7640 WINED3DTSS_COLORARG1 ,
7641 WINED3DTSS_COLORARG2 ,
7642 WINED3DTSS_COLOROP ,
7643 WINED3DTSS_RESULTARG ,
7644 WINED3DTSS_TEXCOORDINDEX ,
7645 WINED3DTSS_TEXTURETRANSFORMFLAGS
7648 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7649 WINED3DSAMP_ADDRESSU ,
7650 WINED3DSAMP_ADDRESSV ,
7651 WINED3DSAMP_ADDRESSW ,
7652 WINED3DSAMP_BORDERCOLOR ,
7653 WINED3DSAMP_MAGFILTER ,
7654 WINED3DSAMP_MINFILTER ,
7655 WINED3DSAMP_MIPFILTER ,
7656 WINED3DSAMP_MIPMAPLODBIAS ,
7657 WINED3DSAMP_MAXMIPLEVEL ,
7658 WINED3DSAMP_MAXANISOTROPY ,
7659 WINED3DSAMP_SRGBTEXTURE ,
7660 WINED3DSAMP_ELEMENTINDEX
7663 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7665 WINED3DRS_AMBIENTMATERIALSOURCE ,
7666 WINED3DRS_CLIPPING ,
7667 WINED3DRS_CLIPPLANEENABLE ,
7668 WINED3DRS_COLORVERTEX ,
7669 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7670 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7671 WINED3DRS_FOGDENSITY ,
7673 WINED3DRS_FOGSTART ,
7674 WINED3DRS_FOGTABLEMODE ,
7675 WINED3DRS_FOGVERTEXMODE ,
7676 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7677 WINED3DRS_LIGHTING ,
7678 WINED3DRS_LOCALVIEWER ,
7679 WINED3DRS_MULTISAMPLEANTIALIAS ,
7680 WINED3DRS_MULTISAMPLEMASK ,
7681 WINED3DRS_NORMALIZENORMALS ,
7682 WINED3DRS_PATCHEDGESTYLE ,
7683 WINED3DRS_POINTSCALE_A ,
7684 WINED3DRS_POINTSCALE_B ,
7685 WINED3DRS_POINTSCALE_C ,
7686 WINED3DRS_POINTSCALEENABLE ,
7687 WINED3DRS_POINTSIZE ,
7688 WINED3DRS_POINTSIZE_MAX ,
7689 WINED3DRS_POINTSIZE_MIN ,
7690 WINED3DRS_POINTSPRITEENABLE ,
7691 WINED3DRS_RANGEFOGENABLE ,
7692 WINED3DRS_SPECULARMATERIALSOURCE ,
7693 WINED3DRS_TWEENFACTOR ,
7694 WINED3DRS_VERTEXBLEND ,
7695 WINED3DRS_CULLMODE ,
7699 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7700 WINED3DTSS_TEXCOORDINDEX ,
7701 WINED3DTSS_TEXTURETRANSFORMFLAGS
7704 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7705 WINED3DSAMP_DMAPOFFSET
7708 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7709 DWORD rep = This->StateTable[state].representative;
7713 WineD3DContext *context;
7716 for(i = 0; i < This->numContexts; i++) {
7717 context = This->contexts[i];
7718 if(isStateDirty(context, rep)) continue;
7720 context->dirtyArray[context->numDirtyEntries++] = rep;
7723 context->isStateDirty[idx] |= (1 << shift);
7727 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7728 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7729 /* The drawable size of a pbuffer render target is the current pbuffer size
7731 *width = dev->pbufferWidth;
7732 *height = dev->pbufferHeight;
7735 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7736 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7738 *width = This->pow2Width;
7739 *height = This->pow2Height;
7742 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7743 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7744 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7745 * current context's drawable, which is the size of the back buffer of the swapchain
7746 * the active context belongs to. The back buffer of the swapchain is stored as the
7747 * surface the context belongs to.
7749 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7750 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;