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
12 * Copyright 2009 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
37 #define GLINFO_LOCATION This->adapter->gl_info
39 /* Define the default light parameters as specified by MSDN */
40 const WINED3DLIGHT WINED3D_default_light = {
42 WINED3DLIGHT_DIRECTIONAL, /* Type */
43 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
45 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
46 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
47 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
50 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
55 /**********************************************************
56 * Global variable / Constants follow
57 **********************************************************/
58 const float identity[] =
60 1.0f, 0.0f, 0.0f, 0.0f,
61 0.0f, 1.0f, 0.0f, 0.0f,
62 0.0f, 0.0f, 1.0f, 0.0f,
63 0.0f, 0.0f, 0.0f, 1.0f,
64 }; /* When needed for comparisons */
66 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
67 * actually have the same values in GL and D3D. */
68 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
70 switch(primitive_type)
72 case WINED3DPT_POINTLIST:
75 case WINED3DPT_LINELIST:
78 case WINED3DPT_LINESTRIP:
81 case WINED3DPT_TRIANGLELIST:
84 case WINED3DPT_TRIANGLESTRIP:
85 return GL_TRIANGLE_STRIP;
87 case WINED3DPT_TRIANGLEFAN:
88 return GL_TRIANGLE_FAN;
90 case WINED3DPT_LINELIST_ADJ:
91 return GL_LINES_ADJACENCY_ARB;
93 case WINED3DPT_LINESTRIP_ADJ:
94 return GL_LINE_STRIP_ADJACENCY_ARB;
96 case WINED3DPT_TRIANGLELIST_ADJ:
97 return GL_TRIANGLES_ADJACENCY_ARB;
99 case WINED3DPT_TRIANGLESTRIP_ADJ:
100 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
103 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
108 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
110 switch(primitive_type)
113 return WINED3DPT_POINTLIST;
116 return WINED3DPT_LINELIST;
119 return WINED3DPT_LINESTRIP;
122 return WINED3DPT_TRIANGLELIST;
124 case GL_TRIANGLE_STRIP:
125 return WINED3DPT_TRIANGLESTRIP;
127 case GL_TRIANGLE_FAN:
128 return WINED3DPT_TRIANGLEFAN;
130 case GL_LINES_ADJACENCY_ARB:
131 return WINED3DPT_LINELIST_ADJ;
133 case GL_LINE_STRIP_ADJACENCY_ARB:
134 return WINED3DPT_LINESTRIP_ADJ;
136 case GL_TRIANGLES_ADJACENCY_ARB:
137 return WINED3DPT_TRIANGLELIST_ADJ;
139 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
140 return WINED3DPT_TRIANGLESTRIP_ADJ;
143 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
144 return WINED3DPT_UNDEFINED;
148 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
150 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
151 *regnum = WINED3D_FFP_POSITION;
152 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
153 *regnum = WINED3D_FFP_BLENDWEIGHT;
154 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
155 *regnum = WINED3D_FFP_BLENDINDICES;
156 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
157 *regnum = WINED3D_FFP_NORMAL;
158 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
159 *regnum = WINED3D_FFP_PSIZE;
160 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
161 *regnum = WINED3D_FFP_DIFFUSE;
162 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
163 *regnum = WINED3D_FFP_SPECULAR;
164 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
165 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
168 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
176 /* Context activation is done by the caller. */
177 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
178 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
180 /* We need to deal with frequency data! */
181 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
182 UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
183 const DWORD *streams = declaration->streams;
186 stream_info->use_map = 0;
187 stream_info->swizzle_map = 0;
189 /* Check for transformed vertices, disable vertex shader if present. */
190 stream_info->position_transformed = declaration->position_transformed;
191 if (declaration->position_transformed) use_vshader = FALSE;
193 /* Translate the declaration into strided data. */
194 for (i = 0; i < declaration->element_count; ++i)
196 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
197 GLuint buffer_object = 0;
198 const BYTE *data = NULL;
203 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
204 element, i + 1, declaration->element_count);
206 if (!This->stateBlock->streamSource[element->input_slot]) continue;
208 stride = This->stateBlock->streamStride[element->input_slot];
209 if (This->stateBlock->streamIsUP)
211 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
213 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
217 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
218 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
220 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
221 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
222 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
223 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
224 * not, drawStridedSlow is needed, including a vertex buffer path. */
225 if (This->stateBlock->loadBaseVertexIndex < 0)
227 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
229 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
230 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
232 FIXME("System memory vertex data load offset is negative!\n");
238 if (buffer_object) *fixup = TRUE;
239 else if (*fixup && !use_vshader
240 && (element->usage == WINED3DDECLUSAGE_COLOR
241 || element->usage == WINED3DDECLUSAGE_POSITIONT))
243 static BOOL warned = FALSE;
246 /* This may be bad with the fixed function pipeline. */
247 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
253 data += element->offset;
255 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
259 if (element->output_slot == ~0U)
261 /* TODO: Assuming vertexdeclarations are usually used with the
262 * same or a similar shader, it might be worth it to store the
263 * last used output slot and try that one first. */
264 stride_used = vshader_get_input(This->stateBlock->vertexShader,
265 element->usage, element->usage_idx, &idx);
269 idx = element->output_slot;
275 if (!element->ffp_valid)
277 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
278 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
283 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
289 TRACE("Load %s array %u [usage %s, usage_idx %u, "
290 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
291 use_vshader ? "shader": "fixed function", idx,
292 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
293 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
295 stream_info->elements[idx].format_desc = element->format_desc;
296 stream_info->elements[idx].stride = stride;
297 stream_info->elements[idx].data = data;
298 stream_info->elements[idx].stream_idx = element->input_slot;
299 stream_info->elements[idx].buffer_object = buffer_object;
301 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
303 stream_info->swizzle_map |= 1 << idx;
305 stream_info->use_map |= 1 << idx;
309 /* Now call PreLoad on all the vertex buffers. In the very rare case
310 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
311 * The vertex buffer can now use the strided structure in the device instead of finding its
314 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
316 for (i = 0; i < stream_count; ++i)
318 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
319 if (vb) IWineD3DBuffer_PreLoad(vb);
323 static void stream_info_element_from_strided(IWineD3DDeviceImpl *This,
324 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
326 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, &This->adapter->gl_info);
327 e->format_desc = format_desc;
328 e->stride = strided->dwStride;
329 e->data = strided->lpData;
331 e->buffer_object = 0;
334 void device_stream_info_from_strided(IWineD3DDeviceImpl *This,
335 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
339 memset(stream_info, 0, sizeof(*stream_info));
341 if (strided->position.lpData)
342 stream_info_element_from_strided(This, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
343 if (strided->normal.lpData)
344 stream_info_element_from_strided(This, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
345 if (strided->diffuse.lpData)
346 stream_info_element_from_strided(This, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
347 if (strided->specular.lpData)
348 stream_info_element_from_strided(This, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
350 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
352 if (strided->texCoords[i].lpData)
353 stream_info_element_from_strided(This, &strided->texCoords[i],
354 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
357 stream_info->position_transformed = strided->position_transformed;
359 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
361 if (!stream_info->elements[i].format_desc) continue;
363 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA)
364 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
366 stream_info->swizzle_map |= 1 << i;
368 stream_info->use_map |= 1 << i;
372 /**********************************************************
373 * IUnknown parts follows
374 **********************************************************/
376 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
380 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
381 if (IsEqualGUID(riid, &IID_IUnknown)
382 || IsEqualGUID(riid, &IID_IWineD3DBase)
383 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
384 IUnknown_AddRef(iface);
389 return E_NOINTERFACE;
392 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
394 ULONG refCount = InterlockedIncrement(&This->ref);
396 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
400 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
402 ULONG refCount = InterlockedDecrement(&This->ref);
404 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
409 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
410 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
411 This->multistate_funcs[i] = NULL;
414 /* TODO: Clean up all the surfaces and textures! */
415 /* NOTE: You must release the parent if the object was created via a callback
416 ** ***************************/
418 if (!list_empty(&This->resources)) {
419 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
420 dumpResources(&This->resources);
423 if(This->contexts) ERR("Context array not freed!\n");
424 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
425 This->haveHardwareCursor = FALSE;
427 IWineD3D_Release(This->wineD3D);
428 This->wineD3D = NULL;
429 HeapFree(GetProcessHeap(), 0, This);
430 TRACE("Freed device %p\n", This);
436 /**********************************************************
437 * IWineD3DDevice implementation follows
438 **********************************************************/
439 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
441 *pParent = This->parent;
442 IUnknown_AddRef(This->parent);
446 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
447 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
449 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
450 struct wined3d_buffer *object;
453 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
455 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
458 ERR("Failed to allocate memory\n");
459 return E_OUTOFMEMORY;
462 FIXME("Ignoring access flags (pool)\n");
464 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
465 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
468 WARN("Failed to initialize buffer, hr %#x.\n", hr);
469 HeapFree(GetProcessHeap(), 0, object);
472 object->desc = *desc;
474 TRACE("Created buffer %p.\n", object);
476 *buffer = (IWineD3DBuffer *)object;
481 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size,
482 DWORD Usage, DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
483 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
486 struct wined3d_buffer *object;
487 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
491 if (Pool == WINED3DPOOL_SCRATCH)
493 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
494 * anyway, SCRATCH vertex buffers aren't usable anywhere
496 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
497 *ppVertexBuffer = NULL;
498 return WINED3DERR_INVALIDCALL;
501 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
504 ERR("Out of memory\n");
505 *ppVertexBuffer = NULL;
506 return WINED3DERR_OUTOFVIDEOMEMORY;
509 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
510 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
513 WARN("Failed to initialize buffer, hr %#x.\n", hr);
514 HeapFree(GetProcessHeap(), 0, object);
518 TRACE("Created buffer %p.\n", object);
519 TRACE("FVF %#x, Pool %#x.\n", FVF, Pool);
520 *ppVertexBuffer = (IWineD3DBuffer *)object;
522 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
523 * drawStridedFast (half-life 2).
525 * Basically converting the vertices in the buffer is quite expensive, and observations
526 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
527 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
529 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
530 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
531 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
532 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
534 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
535 * more. In this call we can convert dx7 buffers too.
537 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
538 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
539 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
540 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
541 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
542 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
543 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
544 } else if(dxVersion <= 7 && conv) {
545 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
547 object->flags |= WINED3D_BUFFER_CREATEBO;
552 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
553 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
554 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
557 struct wined3d_buffer *object;
560 TRACE("(%p) Creating index buffer\n", This);
562 /* Allocate the storage for the device */
563 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
566 ERR("Out of memory\n");
567 *ppIndexBuffer = NULL;
568 return WINED3DERR_OUTOFVIDEOMEMORY;
571 hr = buffer_init(object, This, Length, Usage, WINED3DFMT_UNKNOWN,
572 Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
575 WARN("Failed to initialize buffer, hr %#x\n", hr);
576 HeapFree(GetProcessHeap(), 0, object);
580 TRACE("Created buffer %p.\n", object);
582 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
583 object->flags |= WINED3D_BUFFER_CREATEBO;
586 *ppIndexBuffer = (IWineD3DBuffer *) object;
591 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
592 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
595 IWineD3DStateBlockImpl *object;
598 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
601 ERR("Failed to allocate stateblock memory.\n");
602 return E_OUTOFMEMORY;
605 hr = stateblock_init(object, This, type, parent);
608 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
609 HeapFree(GetProcessHeap(), 0, object);
613 TRACE("Created stateblock %p.\n", object);
614 *stateblock = (IWineD3DStateBlock *)object;
619 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
620 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
621 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
622 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
625 IWineD3DSurfaceImpl *object;
628 TRACE("(%p) Create surface\n",This);
630 if (Impl == SURFACE_OPENGL && !This->adapter)
632 ERR("OpenGL surfaces are not available without OpenGL.\n");
633 return WINED3DERR_NOTAVAILABLE;
636 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
639 ERR("Failed to allocate surface memory.\n");
641 return WINED3DERR_OUTOFVIDEOMEMORY;
644 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
645 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
648 WARN("Failed to initialize surface, returning %#x.\n", hr);
649 HeapFree(GetProcessHeap(), 0, object);
654 TRACE("(%p) : Created surface %p\n", This, object);
656 *ppSurface = (IWineD3DSurface *)object;
661 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
662 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
664 struct wined3d_rendertarget_view *object;
666 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
669 ERR("Failed to allocate memory\n");
670 return E_OUTOFMEMORY;
673 object->vtbl = &wined3d_rendertarget_view_vtbl;
674 object->refcount = 1;
675 IWineD3DResource_AddRef(resource);
676 object->resource = resource;
677 object->parent = parent;
679 *rendertarget_view = (IWineD3DRendertargetView *)object;
684 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
685 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
686 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
689 IWineD3DTextureImpl *object;
692 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
693 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
694 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
696 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
699 ERR("Out of memory\n");
701 return WINED3DERR_OUTOFVIDEOMEMORY;
704 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
707 WARN("Failed to initialize texture, returning %#x\n", hr);
708 HeapFree(GetProcessHeap(), 0, object);
713 *ppTexture = (IWineD3DTexture *)object;
715 TRACE("(%p) : Created texture %p\n", This, object);
720 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
721 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
722 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
725 IWineD3DVolumeTextureImpl *object;
728 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
729 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
731 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
734 ERR("Out of memory\n");
735 *ppVolumeTexture = NULL;
736 return WINED3DERR_OUTOFVIDEOMEMORY;
739 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
742 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
743 HeapFree(GetProcessHeap(), 0, object);
744 *ppVolumeTexture = NULL;
748 TRACE("(%p) : Created volume texture %p.\n", This, object);
749 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
754 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
755 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
756 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
759 IWineD3DVolumeImpl *object;
762 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
763 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
765 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
768 ERR("Out of memory\n");
770 return WINED3DERR_OUTOFVIDEOMEMORY;
773 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
776 WARN("Failed to initialize volume, returning %#x.\n", hr);
777 HeapFree(GetProcessHeap(), 0, object);
781 TRACE("(%p) : Created volume %p.\n", This, object);
782 *ppVolume = (IWineD3DVolume *)object;
787 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
788 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
789 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
792 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
795 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
798 ERR("Out of memory\n");
799 *ppCubeTexture = NULL;
800 return WINED3DERR_OUTOFVIDEOMEMORY;
803 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
806 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
807 HeapFree(GetProcessHeap(), 0, object);
808 *ppCubeTexture = NULL;
812 TRACE("(%p) : Created Cube Texture %p\n", This, object);
813 *ppCubeTexture = (IWineD3DCubeTexture *)object;
818 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
820 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
821 HRESULT hr = WINED3DERR_NOTAVAILABLE;
822 const IWineD3DQueryVtbl *vtable;
824 /* Just a check to see if we support this type of query */
826 case WINED3DQUERYTYPE_OCCLUSION:
827 TRACE("(%p) occlusion query\n", This);
828 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
831 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
833 vtable = &IWineD3DOcclusionQuery_Vtbl;
836 case WINED3DQUERYTYPE_EVENT:
837 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
838 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
839 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
841 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
843 vtable = &IWineD3DEventQuery_Vtbl;
847 case WINED3DQUERYTYPE_VCACHE:
848 case WINED3DQUERYTYPE_RESOURCEMANAGER:
849 case WINED3DQUERYTYPE_VERTEXSTATS:
850 case WINED3DQUERYTYPE_TIMESTAMP:
851 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
852 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
853 case WINED3DQUERYTYPE_PIPELINETIMINGS:
854 case WINED3DQUERYTYPE_INTERFACETIMINGS:
855 case WINED3DQUERYTYPE_VERTEXTIMINGS:
856 case WINED3DQUERYTYPE_PIXELTIMINGS:
857 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
858 case WINED3DQUERYTYPE_CACHEUTILIZATION:
860 /* Use the base Query vtable until we have a special one for each query */
861 vtable = &IWineD3DQuery_Vtbl;
862 FIXME("(%p) Unhandled query type %d\n", This, Type);
864 if(NULL == ppQuery || hr != WINED3D_OK) {
868 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
871 ERR("Out of memory\n");
873 return WINED3DERR_OUTOFVIDEOMEMORY;
876 object->lpVtbl = vtable;
878 object->state = QUERY_CREATED;
879 object->wineD3DDevice = This;
880 object->parent = parent;
883 *ppQuery = (IWineD3DQuery *)object;
885 /* allocated the 'extended' data based on the type of query requested */
887 case WINED3DQUERYTYPE_OCCLUSION:
888 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
889 ((struct wined3d_occlusion_query *)object->extendedData)->context = NULL;
892 case WINED3DQUERYTYPE_EVENT:
893 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query));
894 ((struct wined3d_event_query *)object->extendedData)->context = NULL;
897 case WINED3DQUERYTYPE_VCACHE:
898 case WINED3DQUERYTYPE_RESOURCEMANAGER:
899 case WINED3DQUERYTYPE_VERTEXSTATS:
900 case WINED3DQUERYTYPE_TIMESTAMP:
901 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
902 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
903 case WINED3DQUERYTYPE_PIPELINETIMINGS:
904 case WINED3DQUERYTYPE_INTERFACETIMINGS:
905 case WINED3DQUERYTYPE_VERTEXTIMINGS:
906 case WINED3DQUERYTYPE_PIXELTIMINGS:
907 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
908 case WINED3DQUERYTYPE_CACHEUTILIZATION:
910 object->extendedData = 0;
911 FIXME("(%p) Unhandled query type %d\n",This , Type);
913 TRACE("(%p) : Created Query %p\n", This, object);
917 /*****************************************************************************
918 * IWineD3DDeviceImpl_SetupFullscreenWindow
920 * Helper function that modifies a HWND's Style and ExStyle for proper
924 * iface: Pointer to the IWineD3DDevice interface
925 * window: Window to setup
927 *****************************************************************************/
928 static LONG fullscreen_style(LONG orig_style) {
929 LONG style = orig_style;
930 style &= ~WS_CAPTION;
931 style &= ~WS_THICKFRAME;
933 /* Make sure the window is managed, otherwise we won't get keyboard input */
934 style |= WS_POPUP | WS_SYSMENU;
939 static LONG fullscreen_exStyle(LONG orig_exStyle) {
940 LONG exStyle = orig_exStyle;
942 /* Filter out window decorations */
943 exStyle &= ~WS_EX_WINDOWEDGE;
944 exStyle &= ~WS_EX_CLIENTEDGE;
949 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
953 /* Don't do anything if an original style is stored.
954 * That shouldn't happen
956 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
957 if (This->style || This->exStyle) {
958 ERR("(%p): Want to change the window parameters of HWND %p, but "
959 "another style is stored for restoration afterwards\n", This, window);
962 /* Get the parameters and save them */
963 style = GetWindowLongW(window, GWL_STYLE);
964 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
966 This->exStyle = exStyle;
968 style = fullscreen_style(style);
969 exStyle = fullscreen_exStyle(exStyle);
971 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
972 This->style, This->exStyle, style, exStyle);
974 SetWindowLongW(window, GWL_STYLE, style);
975 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
977 /* Inform the window about the update. */
978 SetWindowPos(window, HWND_TOP, 0, 0,
979 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
982 /*****************************************************************************
983 * IWineD3DDeviceImpl_RestoreWindow
985 * Helper function that restores a windows' properties when taking it out
989 * iface: Pointer to the IWineD3DDevice interface
990 * window: Window to setup
992 *****************************************************************************/
993 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
997 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1000 if (!This->style && !This->exStyle) return;
1002 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1003 This, window, This->style, This->exStyle);
1005 style = GetWindowLongW(window, GWL_STYLE);
1006 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1008 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1009 * Some applications change it before calling Reset() when switching between windowed and
1010 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1012 if(style == fullscreen_style(This->style) &&
1013 exStyle == fullscreen_style(This->exStyle)) {
1014 SetWindowLongW(window, GWL_STYLE, This->style);
1015 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1018 /* Delete the old values */
1022 /* Inform the window about the update */
1023 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1024 0, 0, 0, 0, /* Pos, Size, ignored */
1025 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1028 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1029 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1030 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1031 IUnknown *parent, WINED3DSURFTYPE surface_type)
1033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1036 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1038 BOOL displaymode_set = FALSE;
1039 WINED3DDISPLAYMODE Mode;
1040 const struct GlPixelFormatDesc *format_desc;
1042 TRACE("(%p) : Created Additional Swap Chain\n", This);
1044 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1045 * does a device hold a reference to a swap chain giving them a lifetime of the device
1046 * or does the swap chain notify the device of its destruction.
1047 *******************************/
1049 /* Check the params */
1050 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1051 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1052 return WINED3DERR_INVALIDCALL;
1053 } else if (pPresentationParameters->BackBufferCount > 1) {
1054 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");
1057 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1060 ERR("Out of memory\n");
1061 *ppSwapChain = NULL;
1062 return WINED3DERR_OUTOFVIDEOMEMORY;
1065 switch(surface_type) {
1067 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1069 case SURFACE_OPENGL:
1070 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1072 case SURFACE_UNKNOWN:
1073 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1074 HeapFree(GetProcessHeap(), 0, object);
1075 return WINED3DERR_INVALIDCALL;
1077 object->wineD3DDevice = This;
1078 object->parent = parent;
1081 *ppSwapChain = (IWineD3DSwapChain *)object;
1083 /*********************
1084 * Lookup the window Handle and the relating X window handle
1085 ********************/
1087 /* Setup hwnd we are using, plus which display this equates to */
1088 object->win_handle = pPresentationParameters->hDeviceWindow;
1089 if (!object->win_handle) {
1090 object->win_handle = This->createParms.hFocusWindow;
1092 if(!pPresentationParameters->Windowed && object->win_handle) {
1093 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1094 pPresentationParameters->BackBufferWidth,
1095 pPresentationParameters->BackBufferHeight);
1098 hDc = GetDC(object->win_handle);
1099 TRACE("Using hDc %p\n", hDc);
1102 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1103 return WINED3DERR_NOTAVAILABLE;
1106 /* Get info on the current display setup */
1107 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1108 object->orig_width = Mode.Width;
1109 object->orig_height = Mode.Height;
1110 object->orig_fmt = Mode.Format;
1111 format_desc = getFormatDescEntry(Mode.Format, &This->adapter->gl_info);
1113 if (pPresentationParameters->Windowed &&
1114 ((pPresentationParameters->BackBufferWidth == 0) ||
1115 (pPresentationParameters->BackBufferHeight == 0) ||
1116 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1119 GetClientRect(object->win_handle, &Rect);
1121 if (pPresentationParameters->BackBufferWidth == 0) {
1122 pPresentationParameters->BackBufferWidth = Rect.right;
1123 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1125 if (pPresentationParameters->BackBufferHeight == 0) {
1126 pPresentationParameters->BackBufferHeight = Rect.bottom;
1127 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1129 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1130 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1131 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1135 /* Put the correct figures in the presentation parameters */
1136 TRACE("Copying across presentation parameters\n");
1137 object->presentParms = *pPresentationParameters;
1139 TRACE("calling rendertarget CB\n");
1140 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1141 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1142 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1143 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1144 if (SUCCEEDED(hr)) {
1145 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1146 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1147 if(surface_type == SURFACE_OPENGL) {
1148 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1151 ERR("Failed to create the front buffer\n");
1155 /*********************
1156 * Windowed / Fullscreen
1157 *******************/
1160 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1161 * so we should really check to see if there is a fullscreen swapchain already
1162 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1163 **************************************/
1165 if (!pPresentationParameters->Windowed) {
1166 WINED3DDISPLAYMODE mode;
1169 /* Change the display settings */
1170 mode.Width = pPresentationParameters->BackBufferWidth;
1171 mode.Height = pPresentationParameters->BackBufferHeight;
1172 mode.Format = pPresentationParameters->BackBufferFormat;
1173 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1175 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1176 displaymode_set = TRUE;
1180 * Create an opengl context for the display visual
1181 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1182 * use different properties after that point in time. FIXME: How to handle when requested format
1183 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1184 * it chooses is identical to the one already being used!
1185 **********************************/
1186 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1188 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1189 if(!object->context) {
1190 ERR("Failed to create the context array\n");
1194 object->num_contexts = 1;
1196 if (surface_type == SURFACE_OPENGL)
1198 object->context[0] = context_create(This, (IWineD3DSurfaceImpl *)object->frontBuffer,
1199 object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1200 if (!object->context[0]) {
1201 ERR("Failed to create a new context\n");
1202 hr = WINED3DERR_NOTAVAILABLE;
1205 TRACE("Context created (HWND=%p, glContext=%p)\n",
1206 object->win_handle, object->context[0]->glCtx);
1210 /*********************
1211 * Create the back, front and stencil buffers
1212 *******************/
1213 if(object->presentParms.BackBufferCount > 0) {
1216 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1217 if(!object->backBuffer) {
1218 ERR("Out of memory\n");
1223 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1224 TRACE("calling rendertarget CB\n");
1225 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1226 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1227 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1228 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1230 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1231 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1233 ERR("Cannot create new back buffer\n");
1236 if(surface_type == SURFACE_OPENGL) {
1238 glDrawBuffer(GL_BACK);
1239 checkGLcall("glDrawBuffer(GL_BACK)");
1244 object->backBuffer = NULL;
1246 /* Single buffering - draw to front buffer */
1247 if(surface_type == SURFACE_OPENGL) {
1249 glDrawBuffer(GL_FRONT);
1250 checkGLcall("glDrawBuffer(GL_FRONT)");
1255 if (object->context[0]) context_release(object->context[0]);
1257 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1258 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1259 TRACE("Creating depth stencil buffer\n");
1260 if (This->auto_depth_stencil_buffer == NULL ) {
1261 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1262 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1263 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1264 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1265 &This->auto_depth_stencil_buffer);
1266 if (SUCCEEDED(hr)) {
1267 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1269 ERR("Failed to create the auto depth stencil\n");
1275 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1277 TRACE("Created swapchain %p\n", object);
1278 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1282 if (displaymode_set) {
1286 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1289 /* Change the display settings */
1290 memset(&devmode, 0, sizeof(devmode));
1291 devmode.dmSize = sizeof(devmode);
1292 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1293 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1294 devmode.dmPelsWidth = object->orig_width;
1295 devmode.dmPelsHeight = object->orig_height;
1296 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1299 if (object->backBuffer) {
1301 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1302 if (object->backBuffer[i]) IWineD3DSurface_Release(object->backBuffer[i]);
1304 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1305 object->backBuffer = NULL;
1307 if(object->context && object->context[0])
1309 context_release(object->context[0]);
1310 context_destroy(This, object->context[0]);
1312 if (object->frontBuffer) IWineD3DSurface_Release(object->frontBuffer);
1313 HeapFree(GetProcessHeap(), 0, object);
1317 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1318 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1320 TRACE("(%p)\n", This);
1322 return This->NumberOfSwapChains;
1325 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1327 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1329 if(iSwapChain < This->NumberOfSwapChains) {
1330 *pSwapChain = This->swapchains[iSwapChain];
1331 IWineD3DSwapChain_AddRef(*pSwapChain);
1332 TRACE("(%p) returning %p\n", This, *pSwapChain);
1335 TRACE("Swapchain out of range\n");
1337 return WINED3DERR_INVALIDCALL;
1341 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1342 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1343 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1346 IWineD3DVertexDeclarationImpl *object = NULL;
1349 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1350 iface, declaration, parent, elements, element_count);
1352 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1355 ERR("Failed to allocate vertex declaration memory.\n");
1356 return E_OUTOFMEMORY;
1359 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1362 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1363 HeapFree(GetProcessHeap(), 0, object);
1367 TRACE("Created vertex declaration %p.\n", object);
1368 *declaration = (IWineD3DVertexDeclaration *)object;
1373 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1374 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1376 unsigned int idx, idx2;
1377 unsigned int offset;
1378 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1379 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1380 BOOL has_blend_idx = has_blend &&
1381 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1382 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1383 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1384 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1385 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1386 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1387 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1389 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1390 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1391 WINED3DVERTEXELEMENT *elements = NULL;
1394 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1395 if (has_blend_idx) num_blends--;
1397 /* Compute declaration size */
1398 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1399 has_psize + has_diffuse + has_specular + num_textures;
1401 /* convert the declaration */
1402 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1403 if (!elements) return ~0U;
1407 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1408 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1409 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1411 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1412 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1413 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1416 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1417 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1419 elements[idx].usage_idx = 0;
1422 if (has_blend && (num_blends > 0)) {
1423 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1424 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1426 switch(num_blends) {
1427 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1428 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1429 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1430 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1432 ERR("Unexpected amount of blend values: %u\n", num_blends);
1435 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1436 elements[idx].usage_idx = 0;
1439 if (has_blend_idx) {
1440 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1441 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1442 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1443 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1444 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1446 elements[idx].format = WINED3DFMT_R32_FLOAT;
1447 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1448 elements[idx].usage_idx = 0;
1452 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1453 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1454 elements[idx].usage_idx = 0;
1458 elements[idx].format = WINED3DFMT_R32_FLOAT;
1459 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1460 elements[idx].usage_idx = 0;
1464 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1465 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1466 elements[idx].usage_idx = 0;
1470 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1471 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1472 elements[idx].usage_idx = 1;
1475 for (idx2 = 0; idx2 < num_textures; idx2++) {
1476 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1477 switch (numcoords) {
1478 case WINED3DFVF_TEXTUREFORMAT1:
1479 elements[idx].format = WINED3DFMT_R32_FLOAT;
1481 case WINED3DFVF_TEXTUREFORMAT2:
1482 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1484 case WINED3DFVF_TEXTUREFORMAT3:
1485 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1487 case WINED3DFVF_TEXTUREFORMAT4:
1488 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1491 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1492 elements[idx].usage_idx = idx2;
1496 /* Now compute offsets, and initialize the rest of the fields */
1497 for (idx = 0, offset = 0; idx < size; ++idx)
1499 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1500 elements[idx].input_slot = 0;
1501 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1502 elements[idx].offset = offset;
1503 offset += format_desc->component_count * format_desc->component_size;
1506 *ppVertexElements = elements;
1510 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1511 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1512 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1515 WINED3DVERTEXELEMENT *elements;
1519 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1521 size = ConvertFvfToDeclaration(This, fvf, &elements);
1522 if (size == ~0U) return E_OUTOFMEMORY;
1524 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1525 HeapFree(GetProcessHeap(), 0, elements);
1529 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1530 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1531 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1532 const struct wined3d_parent_ops *parent_ops)
1534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1535 IWineD3DVertexShaderImpl *object;
1538 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1541 ERR("Failed to allocate shader memory.\n");
1542 return E_OUTOFMEMORY;
1545 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1548 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1549 HeapFree(GetProcessHeap(), 0, object);
1553 TRACE("Created vertex shader %p.\n", object);
1554 *ppVertexShader = (IWineD3DVertexShader *)object;
1559 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1560 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1561 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1562 const struct wined3d_parent_ops *parent_ops)
1564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1565 IWineD3DPixelShaderImpl *object;
1568 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1571 ERR("Failed to allocate shader memory.\n");
1572 return E_OUTOFMEMORY;
1575 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1578 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1579 HeapFree(GetProcessHeap(), 0, object);
1583 TRACE("Created pixel shader %p.\n", object);
1584 *ppPixelShader = (IWineD3DPixelShader *)object;
1589 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1590 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1593 IWineD3DPaletteImpl *object;
1595 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1597 /* Create the new object */
1598 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1600 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1601 return E_OUTOFMEMORY;
1604 object->lpVtbl = &IWineD3DPalette_Vtbl;
1606 object->Flags = Flags;
1607 object->parent = Parent;
1608 object->wineD3DDevice = This;
1609 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1610 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1613 HeapFree( GetProcessHeap(), 0, object);
1614 return E_OUTOFMEMORY;
1617 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1619 IWineD3DPalette_Release((IWineD3DPalette *) object);
1623 *Palette = (IWineD3DPalette *) object;
1628 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1632 HDC dcb = NULL, dcs = NULL;
1633 WINEDDCOLORKEY colorkey;
1635 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1638 GetObjectA(hbm, sizeof(BITMAP), &bm);
1639 dcb = CreateCompatibleDC(NULL);
1641 SelectObject(dcb, hbm);
1645 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1646 * couldn't be loaded
1648 memset(&bm, 0, sizeof(bm));
1653 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1654 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1655 NULL, &wined3d_null_parent_ops);
1657 ERR("Wine logo requested, but failed to create surface\n");
1662 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1663 if(FAILED(hr)) goto out;
1664 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1665 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1667 colorkey.dwColorSpaceLowValue = 0;
1668 colorkey.dwColorSpaceHighValue = 0;
1669 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1671 /* Fill the surface with a white color to show that wined3d is there */
1672 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1685 /* Context activation is done by the caller. */
1686 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1688 /* Under DirectX you can have texture stage operations even if no texture is
1689 bound, whereas opengl will only do texture operations when a valid texture is
1690 bound. We emulate this by creating dummy textures and binding them to each
1691 texture stage, but disable all stages by default. Hence if a stage is enabled
1692 then the default texture will kick in until replaced by a SetTexture call */
1695 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1696 /* The dummy texture does not have client storage backing */
1697 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1698 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1701 for (i = 0; i < This->adapter->gl_info.max_textures; ++i)
1703 GLubyte white = 255;
1705 /* Make appropriate texture active */
1706 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1707 checkGLcall("glActiveTextureARB");
1709 /* Generate an opengl texture name */
1710 glGenTextures(1, &This->dummyTextureName[i]);
1711 checkGLcall("glGenTextures");
1712 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1714 /* Generate a dummy 2d texture (not using 1d because they cause many
1715 * DRI drivers fall back to sw) */
1716 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1717 checkGLcall("glBindTexture");
1719 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1720 checkGLcall("glTexImage2D");
1722 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1723 /* Reenable because if supported it is enabled by default */
1724 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1725 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1731 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1732 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1735 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1736 IWineD3DSwapChainImpl *swapchain = NULL;
1737 struct wined3d_context *context;
1742 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1744 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1745 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1747 /* TODO: Test if OpenGL is compiled in and loaded */
1749 TRACE("(%p) : Creating stateblock\n", This);
1750 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1751 hr = IWineD3DDevice_CreateStateBlock(iface,
1753 (IWineD3DStateBlock **)&This->stateBlock,
1755 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1756 WARN("Failed to create stateblock\n");
1759 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1760 This->updateStateBlock = This->stateBlock;
1761 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1763 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1764 sizeof(IWineD3DSurface *) * gl_info->max_buffers);
1765 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1766 sizeof(GLenum) * gl_info->max_buffers);
1768 This->NumberOfPalettes = 1;
1769 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1770 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1771 ERR("Out of memory!\n");
1774 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1775 if(!This->palettes[0]) {
1776 ERR("Out of memory!\n");
1779 for (i = 0; i < 256; ++i) {
1780 This->palettes[0][i].peRed = 0xFF;
1781 This->palettes[0][i].peGreen = 0xFF;
1782 This->palettes[0][i].peBlue = 0xFF;
1783 This->palettes[0][i].peFlags = 0xFF;
1785 This->currentPalette = 0;
1787 /* Initialize the texture unit mapping to a 1:1 mapping */
1788 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1790 if (state < gl_info->max_fragment_samplers)
1792 This->texUnitMap[state] = state;
1793 This->rev_tex_unit_map[state] = state;
1795 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1796 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1800 /* Setup the implicit swapchain. This also initializes a context. */
1801 TRACE("Creating implicit swapchain\n");
1802 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1803 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1806 WARN("Failed to create implicit swapchain\n");
1810 This->NumberOfSwapChains = 1;
1811 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1812 if(!This->swapchains) {
1813 ERR("Out of memory!\n");
1816 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1818 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1819 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1820 This->render_targets[0] = swapchain->backBuffer[0];
1823 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1824 This->render_targets[0] = swapchain->frontBuffer;
1826 IWineD3DSurface_AddRef(This->render_targets[0]);
1828 /* Depth Stencil support */
1829 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1830 if (NULL != This->stencilBufferTarget) {
1831 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1834 hr = This->shader_backend->shader_alloc_private(iface);
1836 TRACE("Shader private data couldn't be allocated\n");
1839 hr = This->frag_pipe->alloc_private(iface);
1841 TRACE("Fragment pipeline private data couldn't be allocated\n");
1844 hr = This->blitter->alloc_private(iface);
1846 TRACE("Blitter private data couldn't be allocated\n");
1850 /* Set up some starting GL setup */
1852 /* Setup all the devices defaults */
1853 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1855 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1857 create_dummy_textures(This);
1861 /* Initialize the current view state */
1862 This->view_ident = 1;
1863 This->contexts[0]->last_was_rhw = 0;
1864 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1865 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1867 switch(wined3d_settings.offscreen_rendering_mode) {
1870 This->offscreenBuffer = GL_BACK;
1873 case ORM_BACKBUFFER:
1875 if (context_get_current()->aux_buffers > 0)
1877 TRACE("Using auxilliary buffer for offscreen rendering\n");
1878 This->offscreenBuffer = GL_AUX0;
1880 TRACE("Using back buffer for offscreen rendering\n");
1881 This->offscreenBuffer = GL_BACK;
1886 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1889 context_release(context);
1891 /* Clear the screen */
1892 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1893 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1896 This->d3d_initialized = TRUE;
1898 if(wined3d_settings.logo) {
1899 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1901 This->highest_dirty_ps_const = 0;
1902 This->highest_dirty_vs_const = 0;
1906 HeapFree(GetProcessHeap(), 0, This->render_targets);
1907 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1908 HeapFree(GetProcessHeap(), 0, This->swapchains);
1909 This->NumberOfSwapChains = 0;
1910 if(This->palettes) {
1911 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1912 HeapFree(GetProcessHeap(), 0, This->palettes);
1914 This->NumberOfPalettes = 0;
1916 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1918 if(This->stateBlock) {
1919 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1920 This->stateBlock = NULL;
1922 if (This->blit_priv) {
1923 This->blitter->free_private(iface);
1925 if (This->fragment_priv) {
1926 This->frag_pipe->free_private(iface);
1928 if (This->shader_priv) {
1929 This->shader_backend->shader_free_private(iface);
1934 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1935 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1938 IWineD3DSwapChainImpl *swapchain = NULL;
1941 /* Setup the implicit swapchain */
1942 TRACE("Creating implicit swapchain\n");
1943 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1944 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1947 WARN("Failed to create implicit swapchain\n");
1951 This->NumberOfSwapChains = 1;
1952 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1953 if(!This->swapchains) {
1954 ERR("Out of memory!\n");
1957 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1961 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1965 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1967 IWineD3DResource_UnLoad(resource);
1968 IWineD3DResource_Release(resource);
1972 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1973 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1976 const struct wined3d_gl_info *gl_info;
1977 struct wined3d_context *context;
1980 TRACE("(%p)\n", This);
1982 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1984 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1985 * it was created. Thus make sure a context is active for the glDelete* calls
1987 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1988 gl_info = context->gl_info;
1990 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1992 /* Unload resources */
1993 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1995 TRACE("Deleting high order patches\n");
1996 for(i = 0; i < PATCHMAP_SIZE; i++) {
1997 struct list *e1, *e2;
1998 struct WineD3DRectPatch *patch;
1999 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2000 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2001 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2005 /* Delete the palette conversion shader if it is around */
2006 if(This->paletteConversionShader) {
2008 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2010 This->paletteConversionShader = 0;
2013 /* Delete the pbuffer context if there is any */
2014 if(This->pbufferContext) context_destroy(This, This->pbufferContext);
2016 /* Delete the mouse cursor texture */
2017 if(This->cursorTexture) {
2019 glDeleteTextures(1, &This->cursorTexture);
2021 This->cursorTexture = 0;
2024 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2025 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2027 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2028 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2031 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2032 * private data, it might contain opengl pointers
2034 if(This->depth_blt_texture) {
2036 glDeleteTextures(1, &This->depth_blt_texture);
2038 This->depth_blt_texture = 0;
2040 if (This->depth_blt_rb) {
2042 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2044 This->depth_blt_rb = 0;
2045 This->depth_blt_rb_w = 0;
2046 This->depth_blt_rb_h = 0;
2049 /* Release the update stateblock */
2050 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2051 if(This->updateStateBlock != This->stateBlock)
2052 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2054 This->updateStateBlock = NULL;
2056 { /* because were not doing proper internal refcounts releasing the primary state block
2057 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2058 to set this->stateBlock = NULL; first */
2059 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2060 This->stateBlock = NULL;
2062 /* Release the stateblock */
2063 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2064 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2068 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2069 This->blitter->free_private(iface);
2070 This->frag_pipe->free_private(iface);
2071 This->shader_backend->shader_free_private(iface);
2073 /* Release the buffers (with sanity checks)*/
2074 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2075 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2076 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2077 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2079 This->stencilBufferTarget = NULL;
2081 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2082 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2083 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2085 TRACE("Setting rendertarget to NULL\n");
2086 This->render_targets[0] = NULL;
2088 if (This->auto_depth_stencil_buffer) {
2089 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
2091 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2093 This->auto_depth_stencil_buffer = NULL;
2096 context_release(context);
2098 for(i=0; i < This->NumberOfSwapChains; i++) {
2099 TRACE("Releasing the implicit swapchain %d\n", i);
2100 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2101 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2105 HeapFree(GetProcessHeap(), 0, This->swapchains);
2106 This->swapchains = NULL;
2107 This->NumberOfSwapChains = 0;
2109 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2110 HeapFree(GetProcessHeap(), 0, This->palettes);
2111 This->palettes = NULL;
2112 This->NumberOfPalettes = 0;
2114 HeapFree(GetProcessHeap(), 0, This->render_targets);
2115 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2116 This->render_targets = NULL;
2117 This->draw_buffers = NULL;
2119 This->d3d_initialized = FALSE;
2123 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2127 for(i=0; i < This->NumberOfSwapChains; i++) {
2128 TRACE("Releasing the implicit swapchain %d\n", i);
2129 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2130 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2134 HeapFree(GetProcessHeap(), 0, This->swapchains);
2135 This->swapchains = NULL;
2136 This->NumberOfSwapChains = 0;
2140 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2141 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2142 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2144 * There is no way to deactivate thread safety once it is enabled.
2146 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2149 /*For now just store the flag(needed in case of ddraw) */
2150 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2155 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2156 const WINED3DDISPLAYMODE* pMode) {
2158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2160 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
2163 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2165 /* Resize the screen even without a window:
2166 * The app could have unset it with SetCooperativeLevel, but not called
2167 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2168 * but we don't have any hwnd
2171 memset(&devmode, 0, sizeof(devmode));
2172 devmode.dmSize = sizeof(devmode);
2173 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2174 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2175 devmode.dmPelsWidth = pMode->Width;
2176 devmode.dmPelsHeight = pMode->Height;
2178 devmode.dmDisplayFrequency = pMode->RefreshRate;
2179 if (pMode->RefreshRate != 0) {
2180 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2183 /* Only change the mode if necessary */
2184 if( (This->ddraw_width == pMode->Width) &&
2185 (This->ddraw_height == pMode->Height) &&
2186 (This->ddraw_format == pMode->Format) &&
2187 (pMode->RefreshRate == 0) ) {
2191 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2192 if (ret != DISP_CHANGE_SUCCESSFUL) {
2193 if(devmode.dmDisplayFrequency != 0) {
2194 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2195 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2196 devmode.dmDisplayFrequency = 0;
2197 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2199 if(ret != DISP_CHANGE_SUCCESSFUL) {
2200 return WINED3DERR_NOTAVAILABLE;
2204 /* Store the new values */
2205 This->ddraw_width = pMode->Width;
2206 This->ddraw_height = pMode->Height;
2207 This->ddraw_format = pMode->Format;
2209 /* And finally clip mouse to our screen */
2210 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2211 ClipCursor(&clip_rc);
2216 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2218 *ppD3D= This->wineD3D;
2219 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2220 IWineD3D_AddRef(*ppD3D);
2224 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2227 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2228 (This->adapter->TextureRam/(1024*1024)),
2229 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2230 /* return simulated texture memory left */
2231 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2235 * Get / Set Stream Source
2237 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2238 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2241 IWineD3DBuffer *oldSrc;
2243 if (StreamNumber >= MAX_STREAMS) {
2244 WARN("Stream out of range %d\n", StreamNumber);
2245 return WINED3DERR_INVALIDCALL;
2246 } else if(OffsetInBytes & 0x3) {
2247 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2248 return WINED3DERR_INVALIDCALL;
2251 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2252 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2254 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2256 if(oldSrc == pStreamData &&
2257 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2258 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2259 TRACE("Application is setting the old values over, nothing to do\n");
2263 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2265 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2266 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2269 /* Handle recording of state blocks */
2270 if (This->isRecordingState) {
2271 TRACE("Recording... not performing anything\n");
2272 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2273 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2277 if (pStreamData != NULL) {
2278 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2279 IWineD3DBuffer_AddRef(pStreamData);
2281 if (oldSrc != NULL) {
2282 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2283 IWineD3DBuffer_Release(oldSrc);
2286 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2291 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2292 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2296 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2297 This->stateBlock->streamSource[StreamNumber],
2298 This->stateBlock->streamOffset[StreamNumber],
2299 This->stateBlock->streamStride[StreamNumber]);
2301 if (StreamNumber >= MAX_STREAMS) {
2302 WARN("Stream out of range %d\n", StreamNumber);
2303 return WINED3DERR_INVALIDCALL;
2305 *pStream = This->stateBlock->streamSource[StreamNumber];
2306 *pStride = This->stateBlock->streamStride[StreamNumber];
2308 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2311 if (*pStream != NULL) {
2312 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2317 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2319 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2320 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2322 /* Verify input at least in d3d9 this is invalid*/
2323 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2324 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2325 return WINED3DERR_INVALIDCALL;
2327 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2328 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2329 return WINED3DERR_INVALIDCALL;
2332 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2333 return WINED3DERR_INVALIDCALL;
2336 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2337 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2339 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2340 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2342 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2343 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2344 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2350 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2353 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2354 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2356 TRACE("(%p) : returning %d\n", This, *Divider);
2362 * Get / Set & Multiply Transform
2364 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2367 /* Most of this routine, comments included copied from ddraw tree initially: */
2368 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2370 /* Handle recording of state blocks */
2371 if (This->isRecordingState) {
2372 TRACE("Recording... not performing anything\n");
2373 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2374 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2379 * If the new matrix is the same as the current one,
2380 * we cut off any further processing. this seems to be a reasonable
2381 * optimization because as was noticed, some apps (warcraft3 for example)
2382 * tend towards setting the same matrix repeatedly for some reason.
2384 * From here on we assume that the new matrix is different, wherever it matters.
2386 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2387 TRACE("The app is setting the same matrix over again\n");
2390 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2394 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2395 where ViewMat = Camera space, WorldMat = world space.
2397 In OpenGL, camera and world space is combined into GL_MODELVIEW
2398 matrix. The Projection matrix stay projection matrix.
2401 /* Capture the times we can just ignore the change for now */
2402 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2403 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2404 /* Handled by the state manager */
2407 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2411 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2413 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2414 *pMatrix = This->stateBlock->transforms[State];
2418 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2419 const WINED3DMATRIX *mat = NULL;
2422 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2423 * below means it will be recorded in a state block change, but it
2424 * works regardless where it is recorded.
2425 * If this is found to be wrong, change to StateBlock.
2427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2428 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2430 if (State <= HIGHEST_TRANSFORMSTATE)
2432 mat = &This->updateStateBlock->transforms[State];
2434 FIXME("Unhandled transform state!!\n");
2437 multiply_matrix(&temp, mat, pMatrix);
2439 /* Apply change via set transform - will reapply to eg. lights this way */
2440 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2446 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2447 you can reference any indexes you want as long as that number max are enabled at any
2448 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2449 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2450 but when recording, just build a chain pretty much of commands to be replayed. */
2452 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2454 struct wined3d_light_info *object = NULL;
2455 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2459 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2461 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2465 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2466 return WINED3DERR_INVALIDCALL;
2469 switch(pLight->Type) {
2470 case WINED3DLIGHT_POINT:
2471 case WINED3DLIGHT_SPOT:
2472 case WINED3DLIGHT_PARALLELPOINT:
2473 case WINED3DLIGHT_GLSPOT:
2474 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2477 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2479 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2480 return WINED3DERR_INVALIDCALL;
2484 case WINED3DLIGHT_DIRECTIONAL:
2485 /* Ignores attenuation */
2489 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2490 return WINED3DERR_INVALIDCALL;
2493 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2495 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2496 if(object->OriginalIndex == Index) break;
2501 TRACE("Adding new light\n");
2502 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2504 ERR("Out of memory error when allocating a light\n");
2505 return E_OUTOFMEMORY;
2507 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2508 object->glIndex = -1;
2509 object->OriginalIndex = Index;
2512 /* Initialize the object */
2513 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,
2514 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2515 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2516 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2517 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2518 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2519 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2521 /* Save away the information */
2522 object->OriginalParms = *pLight;
2524 switch (pLight->Type) {
2525 case WINED3DLIGHT_POINT:
2527 object->lightPosn[0] = pLight->Position.x;
2528 object->lightPosn[1] = pLight->Position.y;
2529 object->lightPosn[2] = pLight->Position.z;
2530 object->lightPosn[3] = 1.0f;
2531 object->cutoff = 180.0f;
2535 case WINED3DLIGHT_DIRECTIONAL:
2537 object->lightPosn[0] = -pLight->Direction.x;
2538 object->lightPosn[1] = -pLight->Direction.y;
2539 object->lightPosn[2] = -pLight->Direction.z;
2540 object->lightPosn[3] = 0.0f;
2541 object->exponent = 0.0f;
2542 object->cutoff = 180.0f;
2545 case WINED3DLIGHT_SPOT:
2547 object->lightPosn[0] = pLight->Position.x;
2548 object->lightPosn[1] = pLight->Position.y;
2549 object->lightPosn[2] = pLight->Position.z;
2550 object->lightPosn[3] = 1.0f;
2553 object->lightDirn[0] = pLight->Direction.x;
2554 object->lightDirn[1] = pLight->Direction.y;
2555 object->lightDirn[2] = pLight->Direction.z;
2556 object->lightDirn[3] = 1.0f;
2559 * opengl-ish and d3d-ish spot lights use too different models for the
2560 * light "intensity" as a function of the angle towards the main light direction,
2561 * so we only can approximate very roughly.
2562 * however spot lights are rather rarely used in games (if ever used at all).
2563 * furthermore if still used, probably nobody pays attention to such details.
2565 if (pLight->Falloff == 0) {
2566 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2567 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2568 * will always be 1.0 for both of them, and we don't have to care for the
2569 * rest of the rather complex calculation
2571 object->exponent = 0.0f;
2573 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2574 if (rho < 0.0001f) rho = 0.0001f;
2575 object->exponent = -0.3f/logf(cosf(rho/2));
2577 if (object->exponent > 128.0f)
2579 object->exponent = 128.0f;
2581 object->cutoff = pLight->Phi*90/M_PI;
2587 FIXME("Unrecognized light type %d\n", pLight->Type);
2590 /* Update the live definitions if the light is currently assigned a glIndex */
2591 if (object->glIndex != -1 && !This->isRecordingState) {
2592 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2597 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2599 struct wined3d_light_info *lightInfo = NULL;
2600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2601 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2603 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2605 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2607 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2608 if(lightInfo->OriginalIndex == Index) break;
2612 if (lightInfo == NULL) {
2613 TRACE("Light information requested but light not defined\n");
2614 return WINED3DERR_INVALIDCALL;
2617 *pLight = lightInfo->OriginalParms;
2622 * Get / Set Light Enable
2623 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2625 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2627 struct wined3d_light_info *lightInfo = NULL;
2628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2629 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2631 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2633 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2635 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2636 if(lightInfo->OriginalIndex == Index) break;
2639 TRACE("Found light: %p\n", lightInfo);
2641 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2642 if (lightInfo == NULL) {
2644 TRACE("Light enabled requested but light not defined, so defining one!\n");
2645 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2647 /* Search for it again! Should be fairly quick as near head of list */
2648 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2650 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2651 if(lightInfo->OriginalIndex == Index) break;
2654 if (lightInfo == NULL) {
2655 FIXME("Adding default lights has failed dismally\n");
2656 return WINED3DERR_INVALIDCALL;
2661 if(lightInfo->glIndex != -1) {
2662 if(!This->isRecordingState) {
2663 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2666 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2667 lightInfo->glIndex = -1;
2669 TRACE("Light already disabled, nothing to do\n");
2671 lightInfo->enabled = FALSE;
2673 lightInfo->enabled = TRUE;
2674 if (lightInfo->glIndex != -1) {
2676 TRACE("Nothing to do as light was enabled\n");
2679 /* Find a free gl light */
2680 for(i = 0; i < This->maxConcurrentLights; i++) {
2681 if(This->updateStateBlock->activeLights[i] == NULL) {
2682 This->updateStateBlock->activeLights[i] = lightInfo;
2683 lightInfo->glIndex = i;
2687 if(lightInfo->glIndex == -1) {
2688 /* Our tests show that Windows returns D3D_OK in this situation, even with
2689 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2690 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2691 * as well for those lights.
2693 * TODO: Test how this affects rendering
2695 WARN("Too many concurrently active lights\n");
2699 /* i == lightInfo->glIndex */
2700 if(!This->isRecordingState) {
2701 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2709 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2711 struct wined3d_light_info *lightInfo = NULL;
2712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2714 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2715 TRACE("(%p) : for idx(%d)\n", This, Index);
2717 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2719 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2720 if(lightInfo->OriginalIndex == Index) break;
2724 if (lightInfo == NULL) {
2725 TRACE("Light enabled state requested but light not defined\n");
2726 return WINED3DERR_INVALIDCALL;
2728 /* true is 128 according to SetLightEnable */
2729 *pEnable = lightInfo->enabled ? 128 : 0;
2734 * Get / Set Clip Planes
2736 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2737 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2738 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2740 /* Validate Index */
2741 if (Index >= This->adapter->gl_info.max_clipplanes)
2743 TRACE("Application has requested clipplane this device doesn't support\n");
2744 return WINED3DERR_INVALIDCALL;
2747 This->updateStateBlock->changed.clipplane |= 1 << Index;
2749 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2750 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2751 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2752 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2753 TRACE("Application is setting old values over, nothing to do\n");
2757 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2758 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2759 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2760 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2762 /* Handle recording of state blocks */
2763 if (This->isRecordingState) {
2764 TRACE("Recording... not performing anything\n");
2768 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2773 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2775 TRACE("(%p) : for idx %d\n", This, Index);
2777 /* Validate Index */
2778 if (Index >= This->adapter->gl_info.max_clipplanes)
2780 TRACE("Application has requested clipplane this device doesn't support\n");
2781 return WINED3DERR_INVALIDCALL;
2784 pPlane[0] = This->stateBlock->clipplane[Index][0];
2785 pPlane[1] = This->stateBlock->clipplane[Index][1];
2786 pPlane[2] = This->stateBlock->clipplane[Index][2];
2787 pPlane[3] = This->stateBlock->clipplane[Index][3];
2792 * Get / Set Clip Plane Status
2793 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2795 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2797 FIXME("(%p) : stub\n", This);
2798 if (NULL == pClipStatus) {
2799 return WINED3DERR_INVALIDCALL;
2801 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2802 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2806 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2808 FIXME("(%p) : stub\n", This);
2809 if (NULL == pClipStatus) {
2810 return WINED3DERR_INVALIDCALL;
2812 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2813 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2818 * Get / Set Material
2820 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2823 This->updateStateBlock->changed.material = TRUE;
2824 This->updateStateBlock->material = *pMaterial;
2826 /* Handle recording of state blocks */
2827 if (This->isRecordingState) {
2828 TRACE("Recording... not performing anything\n");
2832 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2836 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2838 *pMaterial = This->updateStateBlock->material;
2839 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2840 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2841 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2842 pMaterial->Ambient.b, pMaterial->Ambient.a);
2843 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2844 pMaterial->Specular.b, pMaterial->Specular.a);
2845 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2846 pMaterial->Emissive.b, pMaterial->Emissive.a);
2847 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2855 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2856 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2859 IWineD3DBuffer *oldIdxs;
2861 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2862 oldIdxs = This->updateStateBlock->pIndexData;
2864 This->updateStateBlock->changed.indices = TRUE;
2865 This->updateStateBlock->pIndexData = pIndexData;
2866 This->updateStateBlock->IndexFmt = fmt;
2868 /* Handle recording of state blocks */
2869 if (This->isRecordingState) {
2870 TRACE("Recording... not performing anything\n");
2871 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2872 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2876 if(oldIdxs != pIndexData) {
2877 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2879 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2880 IWineD3DBuffer_AddRef(pIndexData);
2883 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2884 IWineD3DBuffer_Release(oldIdxs);
2891 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2895 *ppIndexData = This->stateBlock->pIndexData;
2897 /* up ref count on ppindexdata */
2899 IWineD3DBuffer_AddRef(*ppIndexData);
2900 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2902 TRACE("(%p) No index data set\n", This);
2904 TRACE("Returning %p\n", *ppIndexData);
2909 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2910 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2912 TRACE("(%p)->(%d)\n", This, BaseIndex);
2914 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2915 TRACE("Application is setting the old value over, nothing to do\n");
2919 This->updateStateBlock->baseVertexIndex = BaseIndex;
2921 if (This->isRecordingState) {
2922 TRACE("Recording... not performing anything\n");
2925 /* The base vertex index affects the stream sources */
2926 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2930 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2932 TRACE("(%p) : base_index %p\n", This, base_index);
2934 *base_index = This->stateBlock->baseVertexIndex;
2936 TRACE("Returning %u\n", *base_index);
2942 * Get / Set Viewports
2944 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2947 TRACE("(%p)\n", This);
2948 This->updateStateBlock->changed.viewport = TRUE;
2949 This->updateStateBlock->viewport = *pViewport;
2951 /* Handle recording of state blocks */
2952 if (This->isRecordingState) {
2953 TRACE("Recording... not performing anything\n");
2957 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2958 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2960 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2965 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2967 TRACE("(%p)\n", This);
2968 *pViewport = This->stateBlock->viewport;
2973 * Get / Set Render States
2974 * TODO: Verify against dx9 definitions
2976 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2979 DWORD oldValue = This->stateBlock->renderState[State];
2981 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2983 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2984 This->updateStateBlock->renderState[State] = Value;
2986 /* Handle recording of state blocks */
2987 if (This->isRecordingState) {
2988 TRACE("Recording... not performing anything\n");
2992 /* Compared here and not before the assignment to allow proper stateblock recording */
2993 if(Value == oldValue) {
2994 TRACE("Application is setting the old value over, nothing to do\n");
2996 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3002 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3004 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3005 *pValue = This->stateBlock->renderState[State];
3010 * Get / Set Sampler States
3011 * TODO: Verify against dx9 definitions
3014 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3018 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3019 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3021 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3022 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3025 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3026 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3027 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3030 * SetSampler is designed to allow for more than the standard up to 8 textures
3031 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3032 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3034 * http://developer.nvidia.com/object/General_FAQ.html#t6
3036 * There are two new settings for GForce
3038 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3039 * and the texture one:
3040 * GL_MAX_TEXTURE_COORDS_ARB.
3041 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3044 oldValue = This->stateBlock->samplerState[Sampler][Type];
3045 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3046 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3048 /* Handle recording of state blocks */
3049 if (This->isRecordingState) {
3050 TRACE("Recording... not performing anything\n");
3054 if(oldValue == Value) {
3055 TRACE("Application is setting the old value over, nothing to do\n");
3059 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3064 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3067 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3068 This, Sampler, debug_d3dsamplerstate(Type), Type);
3070 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3071 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3074 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3075 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3076 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3078 *Value = This->stateBlock->samplerState[Sampler][Type];
3079 TRACE("(%p) : Returning %#x\n", This, *Value);
3084 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3087 This->updateStateBlock->changed.scissorRect = TRUE;
3088 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3089 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3092 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3094 if(This->isRecordingState) {
3095 TRACE("Recording... not performing anything\n");
3099 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3104 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3107 *pRect = This->updateStateBlock->scissorRect;
3108 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3112 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3114 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3116 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3118 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3119 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3121 This->updateStateBlock->vertexDecl = pDecl;
3122 This->updateStateBlock->changed.vertexDecl = TRUE;
3124 if (This->isRecordingState) {
3125 TRACE("Recording... not performing anything\n");
3127 } else if(pDecl == oldDecl) {
3128 /* Checked after the assignment to allow proper stateblock recording */
3129 TRACE("Application is setting the old declaration over, nothing to do\n");
3133 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3137 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3140 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3142 *ppDecl = This->stateBlock->vertexDecl;
3143 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3147 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3149 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3151 This->updateStateBlock->vertexShader = pShader;
3152 This->updateStateBlock->changed.vertexShader = TRUE;
3154 if (This->isRecordingState) {
3155 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3156 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3157 TRACE("Recording... not performing anything\n");
3159 } else if(oldShader == pShader) {
3160 /* Checked here to allow proper stateblock recording */
3161 TRACE("App is setting the old shader over, nothing to do\n");
3165 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3166 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3167 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3169 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3174 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3177 if (NULL == ppShader) {
3178 return WINED3DERR_INVALIDCALL;
3180 *ppShader = This->stateBlock->vertexShader;
3181 if( NULL != *ppShader)
3182 IWineD3DVertexShader_AddRef(*ppShader);
3184 TRACE("(%p) : returning %p\n", This, *ppShader);
3188 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3189 IWineD3DDevice *iface,
3191 CONST BOOL *srcData,
3194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3195 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3197 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3198 iface, srcData, start, count);
3200 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3202 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3203 for (i = 0; i < cnt; i++)
3204 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3206 for (i = start; i < cnt + start; ++i) {
3207 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3210 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3215 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3216 IWineD3DDevice *iface,
3221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3222 int cnt = min(count, MAX_CONST_B - start);
3224 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3225 iface, dstData, start, count);
3227 if (dstData == NULL || cnt < 0)
3228 return WINED3DERR_INVALIDCALL;
3230 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3234 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3235 IWineD3DDevice *iface,
3240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3241 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3243 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3244 iface, srcData, start, count);
3246 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3248 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3249 for (i = 0; i < cnt; i++)
3250 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3251 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3253 for (i = start; i < cnt + start; ++i) {
3254 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3257 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3262 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3263 IWineD3DDevice *iface,
3268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3269 int cnt = min(count, MAX_CONST_I - start);
3271 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3272 iface, dstData, start, count);
3274 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3275 return WINED3DERR_INVALIDCALL;
3277 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3281 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3282 IWineD3DDevice *iface,
3284 CONST float *srcData,
3287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3290 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3291 iface, srcData, start, count);
3293 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3294 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3295 return WINED3DERR_INVALIDCALL;
3297 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3299 for (i = 0; i < count; i++)
3300 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3301 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3304 if (!This->isRecordingState)
3306 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3307 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3310 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3311 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3316 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3317 IWineD3DDevice *iface,
3322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3323 int cnt = min(count, This->d3d_vshader_constantF - start);
3325 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3326 iface, dstData, start, count);
3328 if (dstData == NULL || cnt < 0)
3329 return WINED3DERR_INVALIDCALL;
3331 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3335 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3337 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3339 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3343 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3345 DWORD i = This->rev_tex_unit_map[unit];
3346 DWORD j = This->texUnitMap[stage];
3348 This->texUnitMap[stage] = unit;
3349 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3351 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3354 This->rev_tex_unit_map[unit] = stage;
3355 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3357 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3361 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3364 This->fixed_function_usage_map = 0;
3365 for (i = 0; i < MAX_TEXTURES; ++i) {
3366 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3367 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3368 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3369 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3370 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3371 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3372 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3373 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3375 if (color_op == WINED3DTOP_DISABLE) {
3376 /* Not used, and disable higher stages */
3380 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3381 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3382 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3383 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3384 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3385 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3386 This->fixed_function_usage_map |= (1 << i);
3389 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3390 This->fixed_function_usage_map |= (1 << (i + 1));
3395 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3396 unsigned int i, tex;
3399 device_update_fixed_function_usage_map(This);
3400 ffu_map = This->fixed_function_usage_map;
3402 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3403 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3404 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3406 if (!(ffu_map & 1)) continue;
3408 if (This->texUnitMap[i] != i) {
3409 device_map_stage(This, i, i);
3410 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3411 markTextureStagesDirty(This, i);
3417 /* Now work out the mapping */
3419 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3421 if (!(ffu_map & 1)) continue;
3423 if (This->texUnitMap[i] != tex) {
3424 device_map_stage(This, i, tex);
3425 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3426 markTextureStagesDirty(This, i);
3433 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3434 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3435 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3438 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3439 if (sampler_type[i] && This->texUnitMap[i] != i)
3441 device_map_stage(This, i, i);
3442 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3443 if (i < MAX_TEXTURES) {
3444 markTextureStagesDirty(This, i);
3450 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3451 const DWORD *vshader_sampler_tokens, DWORD unit)
3453 DWORD current_mapping = This->rev_tex_unit_map[unit];
3455 /* Not currently used */
3456 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3458 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3459 /* Used by a fragment sampler */
3461 if (!pshader_sampler_tokens) {
3462 /* No pixel shader, check fixed function */
3463 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3466 /* Pixel shader, check the shader's sampler map */
3467 return !pshader_sampler_tokens[current_mapping];
3470 /* Used by a vertex sampler */
3471 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3474 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3475 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3476 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3477 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3478 int start = min(MAX_COMBINED_SAMPLERS, This->adapter->gl_info.max_combined_samplers) - 1;
3482 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3484 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3485 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3486 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3489 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3490 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3491 if (vshader_sampler_type[i])
3493 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3495 /* Already mapped somewhere */
3499 while (start >= 0) {
3500 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3502 device_map_stage(This, vsampler_idx, start);
3503 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3515 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3516 BOOL vs = use_vs(This->stateBlock);
3517 BOOL ps = use_ps(This->stateBlock);
3520 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3521 * that would be really messy and require shader recompilation
3522 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3523 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3526 device_map_psamplers(This);
3528 device_map_fixed_function_samplers(This);
3532 device_map_vsamplers(This, ps);
3536 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3538 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3539 This->updateStateBlock->pixelShader = pShader;
3540 This->updateStateBlock->changed.pixelShader = TRUE;
3542 /* Handle recording of state blocks */
3543 if (This->isRecordingState) {
3544 TRACE("Recording... not performing anything\n");
3547 if (This->isRecordingState) {
3548 TRACE("Recording... not performing anything\n");
3549 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3550 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3554 if(pShader == oldShader) {
3555 TRACE("App is setting the old pixel shader over, nothing to do\n");
3559 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3560 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3562 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3563 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3568 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3571 if (NULL == ppShader) {
3572 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3573 return WINED3DERR_INVALIDCALL;
3576 *ppShader = This->stateBlock->pixelShader;
3577 if (NULL != *ppShader) {
3578 IWineD3DPixelShader_AddRef(*ppShader);
3580 TRACE("(%p) : returning %p\n", This, *ppShader);
3584 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3585 IWineD3DDevice *iface,
3587 CONST BOOL *srcData,
3590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3591 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3593 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3594 iface, srcData, start, count);
3596 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3598 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3599 for (i = 0; i < cnt; i++)
3600 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3602 for (i = start; i < cnt + start; ++i) {
3603 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3606 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3611 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3612 IWineD3DDevice *iface,
3617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3618 int cnt = min(count, MAX_CONST_B - start);
3620 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3621 iface, dstData, start, count);
3623 if (dstData == NULL || cnt < 0)
3624 return WINED3DERR_INVALIDCALL;
3626 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3630 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3631 IWineD3DDevice *iface,
3636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3637 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3639 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3640 iface, srcData, start, count);
3642 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3644 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3645 for (i = 0; i < cnt; i++)
3646 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3647 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3649 for (i = start; i < cnt + start; ++i) {
3650 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3653 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3658 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3659 IWineD3DDevice *iface,
3664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3665 int cnt = min(count, MAX_CONST_I - start);
3667 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3668 iface, dstData, start, count);
3670 if (dstData == NULL || cnt < 0)
3671 return WINED3DERR_INVALIDCALL;
3673 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3677 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3678 IWineD3DDevice *iface,
3680 CONST float *srcData,
3683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3686 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3687 iface, srcData, start, count);
3689 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3690 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3691 return WINED3DERR_INVALIDCALL;
3693 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3695 for (i = 0; i < count; i++)
3696 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3697 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3700 if (!This->isRecordingState)
3702 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3703 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3706 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3707 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3712 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3713 IWineD3DDevice *iface,
3718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3719 int cnt = min(count, This->d3d_pshader_constantF - start);
3721 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3722 iface, dstData, start, count);
3724 if (dstData == NULL || cnt < 0)
3725 return WINED3DERR_INVALIDCALL;
3727 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3731 /* Context activation is done by the caller. */
3732 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3733 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3734 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3737 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3740 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3744 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3746 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3749 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3751 ERR("Source has no position mask\n");
3752 return WINED3DERR_INVALIDCALL;
3755 /* We might access VBOs from this code, so hold the lock */
3758 if (dest->resource.allocatedMemory == NULL) {
3759 buffer_get_sysmem(dest);
3762 /* Get a pointer into the destination vbo(create one if none exists) and
3763 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3765 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
3767 dest->flags |= WINED3D_BUFFER_CREATEBO;
3768 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3771 if (dest->buffer_object)
3773 unsigned char extrabytes = 0;
3774 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3775 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3776 * this may write 4 extra bytes beyond the area that should be written
3778 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3779 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3780 if(!dest_conv_addr) {
3781 ERR("Out of memory\n");
3782 /* Continue without storing converted vertices */
3784 dest_conv = dest_conv_addr;
3788 * a) WINED3DRS_CLIPPING is enabled
3789 * b) WINED3DVOP_CLIP is passed
3791 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3792 static BOOL warned = FALSE;
3794 * The clipping code is not quite correct. Some things need
3795 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3796 * so disable clipping for now.
3797 * (The graphics in Half-Life are broken, and my processvertices
3798 * test crashes with IDirect3DDevice3)
3804 FIXME("Clipping is broken and disabled for now\n");
3806 } else doClip = FALSE;
3807 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3809 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3812 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3813 WINED3DTS_PROJECTION,
3815 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3816 WINED3DTS_WORLDMATRIX(0),
3819 TRACE("View mat:\n");
3820 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);
3821 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);
3822 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);
3823 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);
3825 TRACE("Proj mat:\n");
3826 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);
3827 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);
3828 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);
3829 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);
3831 TRACE("World mat:\n");
3832 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);
3833 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);
3834 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);
3835 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);
3837 /* Get the viewport */
3838 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3839 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3840 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3842 multiply_matrix(&mat,&view_mat,&world_mat);
3843 multiply_matrix(&mat,&proj_mat,&mat);
3845 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3847 for (i = 0; i < dwCount; i+= 1) {
3848 unsigned int tex_index;
3850 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3851 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3852 /* The position first */
3853 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3854 const float *p = (const float *)(element->data + i * element->stride);
3856 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3858 /* Multiplication with world, view and projection matrix */
3859 x = (p[0] * mat.u.s._11) + (p[1] * mat.u.s._21) + (p[2] * mat.u.s._31) + (1.0f * mat.u.s._41);
3860 y = (p[0] * mat.u.s._12) + (p[1] * mat.u.s._22) + (p[2] * mat.u.s._32) + (1.0f * mat.u.s._42);
3861 z = (p[0] * mat.u.s._13) + (p[1] * mat.u.s._23) + (p[2] * mat.u.s._33) + (1.0f * mat.u.s._43);
3862 rhw = (p[0] * mat.u.s._14) + (p[1] * mat.u.s._24) + (p[2] * mat.u.s._34) + (1.0f * mat.u.s._44);
3864 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3866 /* WARNING: The following things are taken from d3d7 and were not yet checked
3867 * against d3d8 or d3d9!
3870 /* Clipping conditions: From msdn
3872 * A vertex is clipped if it does not match the following requirements
3876 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3878 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3879 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3884 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3885 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3888 /* "Normal" viewport transformation (not clipped)
3889 * 1) The values are divided by rhw
3890 * 2) The y axis is negative, so multiply it with -1
3891 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3892 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3893 * 4) Multiply x with Width/2 and add Width/2
3894 * 5) The same for the height
3895 * 6) Add the viewpoint X and Y to the 2D coordinates and
3896 * The minimum Z value to z
3897 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3899 * Well, basically it's simply a linear transformation into viewport
3911 z *= vp.MaxZ - vp.MinZ;
3913 x += vp.Width / 2 + vp.X;
3914 y += vp.Height / 2 + vp.Y;
3919 /* That vertex got clipped
3920 * Contrary to OpenGL it is not dropped completely, it just
3921 * undergoes a different calculation.
3923 TRACE("Vertex got clipped\n");
3930 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3931 * outside of the main vertex buffer memory. That needs some more
3936 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3939 ( (float *) dest_ptr)[0] = x;
3940 ( (float *) dest_ptr)[1] = y;
3941 ( (float *) dest_ptr)[2] = z;
3942 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3944 dest_ptr += 3 * sizeof(float);
3946 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3947 dest_ptr += sizeof(float);
3952 ( (float *) dest_conv)[0] = x * w;
3953 ( (float *) dest_conv)[1] = y * w;
3954 ( (float *) dest_conv)[2] = z * w;
3955 ( (float *) dest_conv)[3] = w;
3957 dest_conv += 3 * sizeof(float);
3959 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3960 dest_conv += sizeof(float);
3964 if (DestFVF & WINED3DFVF_PSIZE) {
3965 dest_ptr += sizeof(DWORD);
3966 if(dest_conv) dest_conv += sizeof(DWORD);
3968 if (DestFVF & WINED3DFVF_NORMAL) {
3969 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3970 const float *normal = (const float *)(element->data + i * element->stride);
3971 /* AFAIK this should go into the lighting information */
3972 FIXME("Didn't expect the destination to have a normal\n");
3973 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3975 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3979 if (DestFVF & WINED3DFVF_DIFFUSE) {
3980 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3981 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3982 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3984 static BOOL warned = FALSE;
3987 ERR("No diffuse color in source, but destination has one\n");
3991 *( (DWORD *) dest_ptr) = 0xffffffff;
3992 dest_ptr += sizeof(DWORD);
3995 *( (DWORD *) dest_conv) = 0xffffffff;
3996 dest_conv += sizeof(DWORD);
4000 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4002 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4003 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4004 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4005 dest_conv += sizeof(DWORD);
4010 if (DestFVF & WINED3DFVF_SPECULAR)
4012 /* What's the color value in the feedback buffer? */
4013 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4014 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4015 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4017 static BOOL warned = FALSE;
4020 ERR("No specular color in source, but destination has one\n");
4024 *( (DWORD *) dest_ptr) = 0xFF000000;
4025 dest_ptr += sizeof(DWORD);
4028 *( (DWORD *) dest_conv) = 0xFF000000;
4029 dest_conv += sizeof(DWORD);
4033 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4035 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4036 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4037 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4038 dest_conv += sizeof(DWORD);
4043 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4044 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4045 const float *tex_coord = (const float *)(element->data + i * element->stride);
4046 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4048 ERR("No source texture, but destination requests one\n");
4049 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4050 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4053 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4055 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4062 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4063 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4064 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4065 dwCount * get_flexible_vertex_size(DestFVF),
4067 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4068 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4075 #undef copy_and_next
4077 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4078 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4082 struct wined3d_stream_info stream_info;
4083 struct wined3d_context *context;
4084 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4087 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4090 ERR("Output vertex declaration not implemented yet\n");
4093 /* Need any context to write to the vbo. */
4094 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4096 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4097 * control the streamIsUP flag, thus restore it afterwards.
4099 This->stateBlock->streamIsUP = FALSE;
4100 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4101 This->stateBlock->streamIsUP = streamWasUP;
4103 if(vbo || SrcStartIndex) {
4105 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4106 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4108 * Also get the start index in, but only loop over all elements if there's something to add at all.
4110 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4112 struct wined3d_stream_info_element *e;
4114 if (!(stream_info.use_map & (1 << i))) continue;
4116 e = &stream_info.elements[i];
4117 if (e->buffer_object)
4119 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4120 e->buffer_object = 0;
4121 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4123 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4124 vb->buffer_object = 0;
4127 if (e->data) e->data += e->stride * SrcStartIndex;
4131 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4132 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4134 context_release(context);
4140 * Get / Set Texture Stage States
4141 * TODO: Verify against dx9 definitions
4143 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4145 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4147 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4149 if (Stage >= MAX_TEXTURES) {
4150 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4154 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4155 This->updateStateBlock->textureState[Stage][Type] = Value;
4157 if (This->isRecordingState) {
4158 TRACE("Recording... not performing anything\n");
4162 /* Checked after the assignments to allow proper stateblock recording */
4163 if(oldValue == Value) {
4164 TRACE("App is setting the old value over, nothing to do\n");
4168 if(Stage > This->stateBlock->lowest_disabled_stage &&
4169 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4170 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4171 * Changes in other states are important on disabled stages too
4176 if(Type == WINED3DTSS_COLOROP) {
4179 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4180 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4181 * they have to be disabled
4183 * The current stage is dirtified below.
4185 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4186 TRACE("Additionally dirtifying stage %u\n", i);
4187 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4189 This->stateBlock->lowest_disabled_stage = Stage;
4190 TRACE("New lowest disabled: %u\n", Stage);
4191 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4192 /* Previously disabled stage enabled. Stages above it may need enabling
4193 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4194 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4196 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4199 for (i = Stage + 1; i < This->adapter->gl_info.max_texture_stages; ++i)
4201 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4204 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4205 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4207 This->stateBlock->lowest_disabled_stage = i;
4208 TRACE("New lowest disabled: %u\n", i);
4212 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4217 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4218 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4219 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4220 *pValue = This->updateStateBlock->textureState[Stage][Type];
4227 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4228 DWORD stage, IWineD3DBaseTexture *texture)
4230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4231 IWineD3DBaseTexture *prev;
4233 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4235 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4236 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4238 /* Windows accepts overflowing this array... we do not. */
4239 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4241 WARN("Ignoring invalid stage %u.\n", stage);
4245 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4246 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4248 WARN("Rejecting attempt to set scratch texture.\n");
4249 return WINED3DERR_INVALIDCALL;
4252 This->updateStateBlock->changed.textures |= 1 << stage;
4254 prev = This->updateStateBlock->textures[stage];
4255 TRACE("Previous texture %p.\n", prev);
4257 if (texture == prev)
4259 TRACE("App is setting the same texture again, nothing to do.\n");
4263 TRACE("Setting new texture to %p.\n", texture);
4264 This->updateStateBlock->textures[stage] = texture;
4266 if (This->isRecordingState)
4268 TRACE("Recording... not performing anything\n");
4270 if (texture) IWineD3DBaseTexture_AddRef(texture);
4271 if (prev) IWineD3DBaseTexture_Release(prev);
4278 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4279 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4280 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4282 IWineD3DBaseTexture_AddRef(texture);
4284 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4286 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4289 if (!prev && stage < MAX_TEXTURES)
4291 /* The source arguments for color and alpha ops have different
4292 * meanings when a NULL texture is bound, so the COLOROP and
4293 * ALPHAOP have to be dirtified. */
4294 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4295 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4298 if (bind_count == 1) t->baseTexture.sampler = stage;
4303 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4304 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4306 IWineD3DBaseTexture_Release(prev);
4308 if (!texture && stage < MAX_TEXTURES)
4310 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4311 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4314 if (bind_count && t->baseTexture.sampler == stage)
4318 /* Search for other stages the texture is bound to. Shouldn't
4319 * happen if applications bind textures to a single stage only. */
4320 TRACE("Searching for other stages the texture is bound to.\n");
4321 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4323 if (This->updateStateBlock->textures[i] == prev)
4325 TRACE("Texture is also bound to stage %u.\n", i);
4326 t->baseTexture.sampler = i;
4333 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4338 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4341 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4343 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4344 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4347 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4348 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4349 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4352 *ppTexture=This->stateBlock->textures[Stage];
4354 IWineD3DBaseTexture_AddRef(*ppTexture);
4356 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4364 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4365 IWineD3DSurface **ppBackBuffer) {
4366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4367 IWineD3DSwapChain *swapChain;
4370 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4372 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4373 if (hr == WINED3D_OK) {
4374 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4375 IWineD3DSwapChain_Release(swapChain);
4377 *ppBackBuffer = NULL;
4382 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4384 WARN("(%p) : stub, calling idirect3d for now\n", This);
4385 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4388 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4390 IWineD3DSwapChain *swapChain;
4393 if(iSwapChain > 0) {
4394 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4395 if (hr == WINED3D_OK) {
4396 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4397 IWineD3DSwapChain_Release(swapChain);
4399 FIXME("(%p) Error getting display mode\n", This);
4402 /* Don't read the real display mode,
4403 but return the stored mode instead. X11 can't change the color
4404 depth, and some apps are pretty angry if they SetDisplayMode from
4405 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4407 Also don't relay to the swapchain because with ddraw it's possible
4408 that there isn't a swapchain at all */
4409 pMode->Width = This->ddraw_width;
4410 pMode->Height = This->ddraw_height;
4411 pMode->Format = This->ddraw_format;
4412 pMode->RefreshRate = 0;
4420 * Stateblock related functions
4423 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4425 IWineD3DStateBlock *stateblock;
4428 TRACE("(%p)\n", This);
4430 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4432 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4433 if (FAILED(hr)) return hr;
4435 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4436 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4437 This->isRecordingState = TRUE;
4439 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4444 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4446 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4448 if (!This->isRecordingState) {
4449 WARN("(%p) not recording! returning error\n", This);
4450 *ppStateBlock = NULL;
4451 return WINED3DERR_INVALIDCALL;
4454 stateblock_init_contained_states(object);
4456 *ppStateBlock = (IWineD3DStateBlock*) object;
4457 This->isRecordingState = FALSE;
4458 This->updateStateBlock = This->stateBlock;
4459 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4460 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4461 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4466 * Scene related functions
4468 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4469 /* At the moment we have no need for any functionality at the beginning
4471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4472 TRACE("(%p)\n", This);
4475 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4476 return WINED3DERR_INVALIDCALL;
4478 This->inScene = TRUE;
4482 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4485 struct wined3d_context *context;
4487 TRACE("(%p)\n", This);
4489 if(!This->inScene) {
4490 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4491 return WINED3DERR_INVALIDCALL;
4494 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4495 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4497 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4499 context_release(context);
4501 This->inScene = FALSE;
4505 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4506 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4507 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4509 IWineD3DSwapChain *swapChain = NULL;
4511 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4513 TRACE("(%p) Presenting the frame\n", This);
4515 for(i = 0 ; i < swapchains ; i ++) {
4517 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4518 TRACE("presentinng chain %d, %p\n", i, swapChain);
4519 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4520 IWineD3DSwapChain_Release(swapChain);
4526 /* Not called from the VTable (internal subroutine) */
4527 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4528 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4529 float Z, DWORD Stencil) {
4530 GLbitfield glMask = 0;
4532 WINED3DRECT curRect;
4534 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4535 UINT drawable_width, drawable_height;
4536 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4537 IWineD3DSwapChainImpl *swapchain = NULL;
4538 struct wined3d_context *context;
4540 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4541 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4542 * for the cleared parts, and the untouched parts.
4544 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4545 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4546 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4547 * checking all this if the dest surface is in the drawable anyway.
4549 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4551 if(vp->X != 0 || vp->Y != 0 ||
4552 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4553 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4556 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4557 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4558 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4559 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4560 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4563 if(Count > 0 && pRects && (
4564 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4565 pRects[0].x2 < target->currentDesc.Width ||
4566 pRects[0].y2 < target->currentDesc.Height)) {
4567 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4574 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4576 target->get_drawable_size(context, &drawable_width, &drawable_height);
4580 /* Only set the values up once, as they are not changing */
4581 if (Flags & WINED3DCLEAR_STENCIL) {
4582 glClearStencil(Stencil);
4583 checkGLcall("glClearStencil");
4584 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4585 glStencilMask(0xFFFFFFFF);
4588 if (Flags & WINED3DCLEAR_ZBUFFER) {
4589 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4590 glDepthMask(GL_TRUE);
4592 checkGLcall("glClearDepth");
4593 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4594 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4596 if (vp->X != 0 || vp->Y != 0 ||
4597 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4598 surface_load_ds_location(This->stencilBufferTarget, context, location);
4600 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4601 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4602 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4603 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4604 surface_load_ds_location(This->stencilBufferTarget, context, location);
4606 else if (Count > 0 && pRects && (
4607 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4608 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4609 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4610 surface_load_ds_location(This->stencilBufferTarget, context, location);
4614 if (Flags & WINED3DCLEAR_TARGET) {
4615 TRACE("Clearing screen with glClear to color %x\n", Color);
4616 glClearColor(D3DCOLOR_R(Color),
4620 checkGLcall("glClearColor");
4622 /* Clear ALL colors! */
4623 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4624 glMask = glMask | GL_COLOR_BUFFER_BIT;
4627 vp_rect.left = vp->X;
4628 vp_rect.top = vp->Y;
4629 vp_rect.right = vp->X + vp->Width;
4630 vp_rect.bottom = vp->Y + vp->Height;
4631 if (!(Count > 0 && pRects)) {
4632 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4633 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4635 if (context->render_offscreen)
4637 glScissor(vp_rect.left, vp_rect.top,
4638 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4640 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4641 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4643 checkGLcall("glScissor");
4645 checkGLcall("glClear");
4647 /* Now process each rect in turn */
4648 for (i = 0; i < Count; i++) {
4649 /* Note gl uses lower left, width/height */
4650 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4651 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4652 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4654 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4655 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4656 curRect.x1, (target->currentDesc.Height - curRect.y2),
4657 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4659 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4660 * The rectangle is not cleared, no error is returned, but further rectanlges are
4661 * still cleared if they are valid
4663 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4664 TRACE("Rectangle with negative dimensions, ignoring\n");
4668 if (context->render_offscreen)
4670 glScissor(curRect.x1, curRect.y1,
4671 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4673 glScissor(curRect.x1, drawable_height - curRect.y2,
4674 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4676 checkGLcall("glScissor");
4679 checkGLcall("glClear");
4683 /* Restore the old values (why..?) */
4684 if (Flags & WINED3DCLEAR_STENCIL) {
4685 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4687 if (Flags & WINED3DCLEAR_TARGET) {
4688 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4689 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4690 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4691 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4692 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4694 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4695 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4697 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4699 if (Flags & WINED3DCLEAR_ZBUFFER) {
4700 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4701 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4702 surface_modify_ds_location(This->stencilBufferTarget, location);
4707 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
4708 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
4711 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
4714 context_release(context);
4719 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4720 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4722 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4724 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4725 Count, pRects, Flags, Color, Z, Stencil);
4727 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4728 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4729 /* TODO: What about depth stencil buffers without stencil bits? */
4730 return WINED3DERR_INVALIDCALL;
4733 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4740 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4741 WINED3DPRIMITIVETYPE primitive_type)
4743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4745 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4747 This->updateStateBlock->changed.primitive_type = TRUE;
4748 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4751 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4752 WINED3DPRIMITIVETYPE *primitive_type)
4754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4756 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4758 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4760 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4763 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4765 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4767 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4769 if(!This->stateBlock->vertexDecl) {
4770 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4771 return WINED3DERR_INVALIDCALL;
4774 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4775 if(This->stateBlock->streamIsUP) {
4776 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4777 This->stateBlock->streamIsUP = FALSE;
4780 if(This->stateBlock->loadBaseVertexIndex != 0) {
4781 This->stateBlock->loadBaseVertexIndex = 0;
4782 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4784 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4785 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4789 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4793 IWineD3DBuffer *pIB;
4796 pIB = This->stateBlock->pIndexData;
4798 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4799 * without an index buffer set. (The first time at least...)
4800 * D3D8 simply dies, but I doubt it can do much harm to return
4801 * D3DERR_INVALIDCALL there as well. */
4802 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4803 return WINED3DERR_INVALIDCALL;
4806 if(!This->stateBlock->vertexDecl) {
4807 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4808 return WINED3DERR_INVALIDCALL;
4811 if(This->stateBlock->streamIsUP) {
4812 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4813 This->stateBlock->streamIsUP = FALSE;
4815 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4817 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4819 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4825 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4826 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4827 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4830 drawPrimitive(iface, index_count, startIndex, idxStride,
4831 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4836 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4837 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4842 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4843 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4845 if(!This->stateBlock->vertexDecl) {
4846 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4847 return WINED3DERR_INVALIDCALL;
4850 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4851 vb = This->stateBlock->streamSource[0];
4852 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4853 if (vb) IWineD3DBuffer_Release(vb);
4854 This->stateBlock->streamOffset[0] = 0;
4855 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4856 This->stateBlock->streamIsUP = TRUE;
4857 This->stateBlock->loadBaseVertexIndex = 0;
4859 /* TODO: Only mark dirty if drawing from a different UP address */
4860 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4862 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4864 /* MSDN specifies stream zero settings must be set to NULL */
4865 This->stateBlock->streamStride[0] = 0;
4866 This->stateBlock->streamSource[0] = NULL;
4868 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4869 * the new stream sources or use UP drawing again
4874 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4875 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4876 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4883 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4884 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4886 if(!This->stateBlock->vertexDecl) {
4887 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4888 return WINED3DERR_INVALIDCALL;
4891 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4897 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4898 vb = This->stateBlock->streamSource[0];
4899 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4900 if (vb) IWineD3DBuffer_Release(vb);
4901 This->stateBlock->streamIsUP = TRUE;
4902 This->stateBlock->streamOffset[0] = 0;
4903 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4905 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4906 This->stateBlock->baseVertexIndex = 0;
4907 This->stateBlock->loadBaseVertexIndex = 0;
4908 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4909 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4910 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4912 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4914 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4915 This->stateBlock->streamSource[0] = NULL;
4916 This->stateBlock->streamStride[0] = 0;
4917 ib = This->stateBlock->pIndexData;
4919 IWineD3DBuffer_Release(ib);
4920 This->stateBlock->pIndexData = NULL;
4922 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4923 * SetStreamSource to specify a vertex buffer
4929 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4930 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4934 /* Mark the state dirty until we have nicer tracking
4935 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4938 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4939 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4940 This->stateBlock->baseVertexIndex = 0;
4941 This->up_strided = DrawPrimStrideData;
4942 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4943 This->up_strided = NULL;
4947 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4948 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4949 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4952 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4954 /* Mark the state dirty until we have nicer tracking
4955 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4958 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4959 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4960 This->stateBlock->streamIsUP = TRUE;
4961 This->stateBlock->baseVertexIndex = 0;
4962 This->up_strided = DrawPrimStrideData;
4963 drawPrimitive(iface, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData);
4964 This->up_strided = NULL;
4968 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
4969 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
4970 * not callable by the app directly no parameter validation checks are needed here.
4972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4973 WINED3DLOCKED_BOX src;
4974 WINED3DLOCKED_BOX dst;
4976 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
4978 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4979 * dirtification to improve loading performance.
4981 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4982 if(FAILED(hr)) return hr;
4983 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4985 IWineD3DVolume_UnlockBox(pSourceVolume);
4989 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4991 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4993 IWineD3DVolume_UnlockBox(pSourceVolume);
4995 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5000 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
5001 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
5003 unsigned int level_count, i;
5004 WINED3DRESOURCETYPE type;
5007 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
5009 /* Verify that the source and destination textures are non-NULL. */
5010 if (!src_texture || !dst_texture)
5012 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5013 return WINED3DERR_INVALIDCALL;
5016 if (src_texture == dst_texture)
5018 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5019 return WINED3DERR_INVALIDCALL;
5022 /* Verify that the source and destination textures are the same type. */
5023 type = IWineD3DBaseTexture_GetType(src_texture);
5024 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
5026 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5027 return WINED3DERR_INVALIDCALL;
5030 /* Check that both textures have the identical numbers of levels. */
5031 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
5032 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
5034 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5035 return WINED3DERR_INVALIDCALL;
5038 /* Make sure that the destination texture is loaded. */
5039 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
5041 /* Update every surface level of the texture. */
5044 case WINED3DRTYPE_TEXTURE:
5046 IWineD3DSurface *src_surface;
5047 IWineD3DSurface *dst_surface;
5049 for (i = 0; i < level_count; ++i)
5051 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
5052 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
5053 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5054 IWineD3DSurface_Release(dst_surface);
5055 IWineD3DSurface_Release(src_surface);
5058 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5065 case WINED3DRTYPE_CUBETEXTURE:
5067 IWineD3DSurface *src_surface;
5068 IWineD3DSurface *dst_surface;
5069 WINED3DCUBEMAP_FACES face;
5071 for (i = 0; i < level_count; ++i)
5073 /* Update each cube face. */
5074 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
5076 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
5077 face, i, &src_surface);
5078 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5079 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
5080 face, i, &dst_surface);
5081 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5082 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5083 IWineD3DSurface_Release(dst_surface);
5084 IWineD3DSurface_Release(src_surface);
5087 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5095 case WINED3DRTYPE_VOLUMETEXTURE:
5097 IWineD3DVolume *src_volume;
5098 IWineD3DVolume *dst_volume;
5100 for (i = 0; i < level_count; ++i)
5102 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5103 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5104 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5105 IWineD3DVolume_Release(dst_volume);
5106 IWineD3DVolume_Release(src_volume);
5109 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5117 FIXME("Unsupported texture type %#x.\n", type);
5118 return WINED3DERR_INVALIDCALL;
5124 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5125 IWineD3DSwapChain *swapChain;
5127 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5128 if(hr == WINED3D_OK) {
5129 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5130 IWineD3DSwapChain_Release(swapChain);
5135 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5137 IWineD3DBaseTextureImpl *texture;
5140 TRACE("(%p) : %p\n", This, pNumPasses);
5142 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5143 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5144 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5145 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5147 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5148 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5149 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5152 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5153 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5155 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5156 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5159 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5160 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5163 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5164 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5165 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5170 /* return a sensible default */
5173 TRACE("returning D3D_OK\n");
5177 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5181 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5183 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5184 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
5185 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
5187 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5192 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5196 PALETTEENTRY **palettes;
5198 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5200 if (PaletteNumber >= MAX_PALETTES) {
5201 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5202 return WINED3DERR_INVALIDCALL;
5205 if (PaletteNumber >= This->NumberOfPalettes) {
5206 NewSize = This->NumberOfPalettes;
5209 } while(PaletteNumber >= NewSize);
5210 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5212 ERR("Out of memory!\n");
5213 return E_OUTOFMEMORY;
5215 This->palettes = palettes;
5216 This->NumberOfPalettes = NewSize;
5219 if (!This->palettes[PaletteNumber]) {
5220 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5221 if (!This->palettes[PaletteNumber]) {
5222 ERR("Out of memory!\n");
5223 return E_OUTOFMEMORY;
5227 for (j = 0; j < 256; ++j) {
5228 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5229 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5230 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5231 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5233 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5234 TRACE("(%p) : returning\n", This);
5238 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5241 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5242 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5243 /* What happens in such situation isn't documented; Native seems to silently abort
5244 on such conditions. Return Invalid Call. */
5245 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5246 return WINED3DERR_INVALIDCALL;
5248 for (j = 0; j < 256; ++j) {
5249 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5250 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5251 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5252 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5254 TRACE("(%p) : returning\n", This);
5258 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5260 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5261 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5262 (tested with reference rasterizer). Return Invalid Call. */
5263 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5264 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5265 return WINED3DERR_INVALIDCALL;
5267 /*TODO: stateblocks */
5268 if (This->currentPalette != PaletteNumber) {
5269 This->currentPalette = PaletteNumber;
5270 dirtify_p8_texture_samplers(This);
5272 TRACE("(%p) : returning\n", This);
5276 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5278 if (PaletteNumber == NULL) {
5279 WARN("(%p) : returning Invalid Call\n", This);
5280 return WINED3DERR_INVALIDCALL;
5282 /*TODO: stateblocks */
5283 *PaletteNumber = This->currentPalette;
5284 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5288 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5293 FIXME("(%p) : stub\n", This);
5297 This->softwareVertexProcessing = bSoftware;
5302 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5307 FIXME("(%p) : stub\n", This);
5310 return This->softwareVertexProcessing;
5314 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5316 IWineD3DSwapChain *swapChain;
5319 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5321 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5322 if(hr == WINED3D_OK){
5323 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5324 IWineD3DSwapChain_Release(swapChain);
5326 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5332 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5335 if(nSegments != 0.0f) {
5338 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5345 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5350 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5356 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5358 /** TODO: remove casts to IWineD3DSurfaceImpl
5359 * NOTE: move code to surface to accomplish this
5360 ****************************************/
5361 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5362 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5363 int srcWidth, srcHeight;
5364 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5365 WINED3DFORMAT destFormat, srcFormat;
5367 int srcLeft, destLeft, destTop;
5368 WINED3DPOOL srcPool, destPool;
5370 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5371 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5375 CONVERT_TYPES convert = NO_CONVERSION;
5376 struct wined3d_context *context;
5378 WINED3DSURFACE_DESC winedesc;
5380 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5382 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5383 srcSurfaceWidth = winedesc.width;
5384 srcSurfaceHeight = winedesc.height;
5385 srcPool = winedesc.pool;
5386 srcFormat = winedesc.format;
5388 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5389 destSurfaceWidth = winedesc.width;
5390 destSurfaceHeight = winedesc.height;
5391 destPool = winedesc.pool;
5392 destFormat = winedesc.format;
5393 destSize = winedesc.size;
5395 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5396 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5397 return WINED3DERR_INVALIDCALL;
5400 /* This call loads the opengl surface directly, instead of copying the surface to the
5401 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5402 * copy in sysmem and use regular surface loading.
5404 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5405 if(convert != NO_CONVERSION) {
5406 return IWineD3DSurface_BltFast(pDestinationSurface,
5407 pDestPoint ? pDestPoint->x : 0,
5408 pDestPoint ? pDestPoint->y : 0,
5409 pSourceSurface, pSourceRect, 0);
5412 if (destFormat == WINED3DFMT_UNKNOWN) {
5413 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5414 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5416 /* Get the update surface description */
5417 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5420 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5423 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5424 checkGLcall("glActiveTextureARB");
5427 /* Make sure the surface is loaded and up to date */
5428 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5429 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5431 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5432 dst_format_desc = dst_impl->resource.format_desc;
5434 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5435 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5436 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5437 srcLeft = pSourceRect ? pSourceRect->left : 0;
5438 destLeft = pDestPoint ? pDestPoint->x : 0;
5439 destTop = pDestPoint ? pDestPoint->y : 0;
5442 /* This function doesn't support compressed textures
5443 the pitch is just bytesPerPixel * width */
5444 if(srcWidth != srcSurfaceWidth || srcLeft ){
5445 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5446 offset += srcLeft * src_format_desc->byte_count;
5447 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5449 /* TODO DXT formats */
5451 if(pSourceRect != NULL && pSourceRect->top != 0){
5452 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5454 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5455 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5456 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5459 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5461 /* need to lock the surface to get the data */
5462 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5467 /* TODO: Cube and volume support */
5469 /* not a whole row so we have to do it a line at a time */
5472 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5473 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5475 for (j = destTop; j < (srcHeight + destTop); ++j)
5477 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5478 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5482 } else { /* Full width, so just write out the whole texture */
5483 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5485 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5487 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5489 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5490 FIXME("Updating part of a compressed texture is not supported.\n");
5492 if (destFormat != srcFormat)
5494 FIXME("Updating mixed format compressed textures is not supported.\n");
5498 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5499 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5504 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5505 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5508 checkGLcall("glTexSubImage2D");
5511 context_release(context);
5513 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5514 sampler = This->rev_tex_unit_map[0];
5515 if (sampler != WINED3D_UNMAPPED_STAGE)
5517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5523 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5525 struct WineD3DRectPatch *patch;
5526 GLenum old_primitive_type;
5530 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5532 if(!(Handle || pRectPatchInfo)) {
5533 /* TODO: Write a test for the return value, thus the FIXME */
5534 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5535 return WINED3DERR_INVALIDCALL;
5539 i = PATCHMAP_HASHFUNC(Handle);
5541 LIST_FOR_EACH(e, &This->patches[i]) {
5542 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5543 if(patch->Handle == Handle) {
5550 TRACE("Patch does not exist. Creating a new one\n");
5551 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5552 patch->Handle = Handle;
5553 list_add_head(&This->patches[i], &patch->entry);
5555 TRACE("Found existing patch %p\n", patch);
5558 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5559 * attributes we have to tesselate, read back, and draw. This needs a patch
5560 * management structure instance. Create one.
5562 * A possible improvement is to check if a vertex shader is used, and if not directly
5565 FIXME("Drawing an uncached patch. This is slow\n");
5566 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5569 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5570 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5571 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5573 TRACE("Tesselation density or patch info changed, retesselating\n");
5575 if(pRectPatchInfo) {
5576 patch->RectPatchInfo = *pRectPatchInfo;
5578 patch->numSegs[0] = pNumSegs[0];
5579 patch->numSegs[1] = pNumSegs[1];
5580 patch->numSegs[2] = pNumSegs[2];
5581 patch->numSegs[3] = pNumSegs[3];
5583 hr = tesselate_rectpatch(This, patch);
5585 WARN("Patch tesselation failed\n");
5587 /* Do not release the handle to store the params of the patch */
5589 HeapFree(GetProcessHeap(), 0, patch);
5595 This->currentPatch = patch;
5596 old_primitive_type = This->stateBlock->gl_primitive_type;
5597 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5598 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5599 This->stateBlock->gl_primitive_type = old_primitive_type;
5600 This->currentPatch = NULL;
5602 /* Destroy uncached patches */
5604 HeapFree(GetProcessHeap(), 0, patch->mem);
5605 HeapFree(GetProcessHeap(), 0, patch);
5610 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5612 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5613 FIXME("(%p) : Stub\n", This);
5617 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5620 struct WineD3DRectPatch *patch;
5622 TRACE("(%p) Handle(%d)\n", This, Handle);
5624 i = PATCHMAP_HASHFUNC(Handle);
5625 LIST_FOR_EACH(e, &This->patches[i]) {
5626 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5627 if(patch->Handle == Handle) {
5628 TRACE("Deleting patch %p\n", patch);
5629 list_remove(&patch->entry);
5630 HeapFree(GetProcessHeap(), 0, patch->mem);
5631 HeapFree(GetProcessHeap(), 0, patch);
5636 /* TODO: Write a test for the return value */
5637 FIXME("Attempt to destroy nonexistent patch\n");
5638 return WINED3DERR_INVALIDCALL;
5641 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5643 IWineD3DSwapChain *swapchain;
5645 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5646 if (SUCCEEDED(hr)) {
5647 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5654 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5655 const WINED3DRECT *rect, const float color[4])
5657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5658 struct wined3d_context *context;
5659 IWineD3DSwapChain *swapchain;
5661 swapchain = get_swapchain(surface);
5665 TRACE("Surface %p is onscreen\n", surface);
5667 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5669 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5670 buffer = surface_get_gl_buffer(surface, swapchain);
5671 glDrawBuffer(buffer);
5672 checkGLcall("glDrawBuffer()");
5674 TRACE("Surface %p is offscreen\n", surface);
5676 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5678 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5679 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5680 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5684 glEnable(GL_SCISSOR_TEST);
5686 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5688 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5689 rect->x2 - rect->x1, rect->y2 - rect->y1);
5691 checkGLcall("glScissor");
5692 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5694 glDisable(GL_SCISSOR_TEST);
5696 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5698 glDisable(GL_BLEND);
5699 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5701 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5702 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5704 glClearColor(color[0], color[1], color[2], color[3]);
5705 glClear(GL_COLOR_BUFFER_BIT);
5706 checkGLcall("glClear");
5708 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5709 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5710 glDrawBuffer(GL_BACK);
5711 checkGLcall("glDrawBuffer()");
5715 context_release(context);
5718 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5719 unsigned int r, g, b, a;
5722 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5723 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5724 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5727 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5729 a = (color & 0xff000000) >> 24;
5730 r = (color & 0x00ff0000) >> 16;
5731 g = (color & 0x0000ff00) >> 8;
5732 b = (color & 0x000000ff) >> 0;
5736 case WINED3DFMT_B5G6R5_UNORM:
5737 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5744 TRACE("Returning %08x\n", ret);
5747 case WINED3DFMT_B5G5R5X1_UNORM:
5748 case WINED3DFMT_B5G5R5A1_UNORM:
5757 TRACE("Returning %08x\n", ret);
5760 case WINED3DFMT_A8_UNORM:
5761 TRACE("Returning %08x\n", a);
5764 case WINED3DFMT_B4G4R4X4_UNORM:
5765 case WINED3DFMT_B4G4R4A4_UNORM:
5774 TRACE("Returning %08x\n", ret);
5777 case WINED3DFMT_B2G3R3_UNORM:
5784 TRACE("Returning %08x\n", ret);
5787 case WINED3DFMT_R8G8B8X8_UNORM:
5788 case WINED3DFMT_R8G8B8A8_UNORM:
5793 TRACE("Returning %08x\n", ret);
5796 case WINED3DFMT_B10G10R10A2_UNORM:
5798 r = (r * 1024) / 256;
5799 g = (g * 1024) / 256;
5800 b = (b * 1024) / 256;
5805 TRACE("Returning %08x\n", ret);
5808 case WINED3DFMT_R10G10B10A2_UNORM:
5810 r = (r * 1024) / 256;
5811 g = (g * 1024) / 256;
5812 b = (b * 1024) / 256;
5817 TRACE("Returning %08x\n", ret);
5821 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5826 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5828 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5830 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5832 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5833 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5834 return WINED3DERR_INVALIDCALL;
5837 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5838 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5839 color_fill_fbo(iface, pSurface, pRect, c);
5842 /* Just forward this to the DirectDraw blitting engine */
5843 memset(&BltFx, 0, sizeof(BltFx));
5844 BltFx.dwSize = sizeof(BltFx);
5845 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5846 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5847 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5851 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5852 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5854 IWineD3DResource *resource;
5855 IWineD3DSurface *surface;
5858 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5861 ERR("Failed to get resource, hr %#x\n", hr);
5865 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5867 FIXME("Only supported on surface resources\n");
5868 IWineD3DResource_Release(resource);
5872 surface = (IWineD3DSurface *)resource;
5874 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5876 color_fill_fbo(iface, surface, NULL, color);
5883 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5885 c = ((DWORD)(color[2] * 255.0f));
5886 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5887 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5888 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5890 /* Just forward this to the DirectDraw blitting engine */
5891 memset(&BltFx, 0, sizeof(BltFx));
5892 BltFx.dwSize = sizeof(BltFx);
5893 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5894 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5897 ERR("Blt failed, hr %#x\n", hr);
5901 IWineD3DResource_Release(resource);
5904 /* rendertarget and depth stencil functions */
5905 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5908 if (RenderTargetIndex >= This->adapter->gl_info.max_buffers)
5910 ERR("(%p) : Only %d render targets are supported.\n",
5911 This, This->adapter->gl_info.max_buffers);
5912 return WINED3DERR_INVALIDCALL;
5915 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5916 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5917 /* Note inc ref on returned surface */
5918 if(*ppRenderTarget != NULL)
5919 IWineD3DSurface_AddRef(*ppRenderTarget);
5923 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5925 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5926 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5927 IWineD3DSwapChainImpl *Swapchain;
5930 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5932 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5933 if(hr != WINED3D_OK) {
5934 ERR("Can't get the swapchain\n");
5938 /* Make sure to release the swapchain */
5939 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5941 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5942 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5943 return WINED3DERR_INVALIDCALL;
5945 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5946 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5947 return WINED3DERR_INVALIDCALL;
5950 if(Swapchain->frontBuffer != Front) {
5951 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5953 if(Swapchain->frontBuffer)
5955 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5956 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5958 Swapchain->frontBuffer = Front;
5960 if(Swapchain->frontBuffer) {
5961 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5962 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5966 if(Back && !Swapchain->backBuffer) {
5967 /* We need memory for the back buffer array - only one back buffer this way */
5968 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5969 if(!Swapchain->backBuffer) {
5970 ERR("Out of memory\n");
5971 return E_OUTOFMEMORY;
5975 if(Swapchain->backBuffer[0] != Back) {
5976 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5978 /* What to do about the context here in the case of multithreading? Not sure.
5979 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5981 WARN("No active context?\n");
5984 if(!Swapchain->backBuffer[0]) {
5985 /* GL was told to draw to the front buffer at creation,
5988 glDrawBuffer(GL_BACK);
5989 checkGLcall("glDrawBuffer(GL_BACK)");
5990 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5991 Swapchain->presentParms.BackBufferCount = 1;
5993 /* That makes problems - disable for now */
5994 /* glDrawBuffer(GL_FRONT); */
5995 checkGLcall("glDrawBuffer(GL_FRONT)");
5996 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5997 Swapchain->presentParms.BackBufferCount = 0;
6001 if(Swapchain->backBuffer[0])
6003 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6004 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6006 Swapchain->backBuffer[0] = Back;
6008 if(Swapchain->backBuffer[0]) {
6009 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6010 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6012 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6013 Swapchain->backBuffer = NULL;
6021 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6023 *ppZStencilSurface = This->stencilBufferTarget;
6024 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6026 if(*ppZStencilSurface != NULL) {
6027 /* Note inc ref on returned surface */
6028 IWineD3DSurface_AddRef(*ppZStencilSurface);
6031 return WINED3DERR_NOTFOUND;
6035 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6036 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6039 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6040 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6041 const struct wined3d_gl_info *gl_info;
6042 struct wined3d_context *context;
6044 POINT offset = {0, 0};
6046 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6047 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6048 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6049 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6052 case WINED3DTEXF_LINEAR:
6053 gl_filter = GL_LINEAR;
6057 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6058 case WINED3DTEXF_NONE:
6059 case WINED3DTEXF_POINT:
6060 gl_filter = GL_NEAREST;
6064 /* Attach src surface to src fbo */
6065 src_swapchain = get_swapchain(src_surface);
6066 dst_swapchain = get_swapchain(dst_surface);
6068 if (src_swapchain) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
6069 else if (dst_swapchain) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6070 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6072 gl_info = context->gl_info;
6074 if (src_swapchain) {
6075 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6077 TRACE("Source surface %p is onscreen\n", src_surface);
6078 /* Make sure the drawable is up to date. In the offscreen case
6079 * attach_surface_fbo() implicitly takes care of this. */
6080 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6082 if(buffer == GL_FRONT) {
6085 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6086 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6087 h = windowsize.bottom - windowsize.top;
6088 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6089 src_rect->y1 = offset.y + h - src_rect->y1;
6090 src_rect->y2 = offset.y + h - src_rect->y2;
6092 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6093 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6097 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
6098 glReadBuffer(buffer);
6099 checkGLcall("glReadBuffer()");
6101 TRACE("Source surface %p is offscreen\n", src_surface);
6103 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
6104 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
6105 glReadBuffer(GL_COLOR_ATTACHMENT0);
6106 checkGLcall("glReadBuffer()");
6107 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
6111 /* Attach dst surface to dst fbo */
6112 if (dst_swapchain) {
6113 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6115 TRACE("Destination surface %p is onscreen\n", dst_surface);
6116 /* Make sure the drawable is up to date. In the offscreen case
6117 * attach_surface_fbo() implicitly takes care of this. */
6118 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6120 if(buffer == GL_FRONT) {
6123 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6124 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6125 h = windowsize.bottom - windowsize.top;
6126 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6127 dst_rect->y1 = offset.y + h - dst_rect->y1;
6128 dst_rect->y2 = offset.y + h - dst_rect->y2;
6130 /* Screen coords = window coords, surface height = window height */
6131 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6132 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6136 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
6137 glDrawBuffer(buffer);
6138 checkGLcall("glDrawBuffer()");
6140 TRACE("Destination surface %p is offscreen\n", dst_surface);
6143 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
6144 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
6145 glDrawBuffer(GL_COLOR_ATTACHMENT0);
6146 checkGLcall("glDrawBuffer()");
6147 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
6149 glDisable(GL_SCISSOR_TEST);
6150 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6153 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6154 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
6155 checkGLcall("glBlitFramebuffer()");
6157 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6158 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
6159 checkGLcall("glBlitFramebuffer()");
6162 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6164 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6165 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6166 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6167 glDrawBuffer(GL_BACK);
6168 checkGLcall("glDrawBuffer()");
6172 context_release(context);
6175 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6177 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
6179 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6181 if (RenderTargetIndex >= This->adapter->gl_info.max_buffers)
6183 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6184 This, RenderTargetIndex, This->adapter->gl_info.max_buffers);
6185 return WINED3DERR_INVALIDCALL;
6188 /* MSDN says that null disables the render target
6189 but a device must always be associated with a render target
6190 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6192 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6193 FIXME("Trying to set render target 0 to NULL\n");
6194 return WINED3DERR_INVALIDCALL;
6196 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6197 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);
6198 return WINED3DERR_INVALIDCALL;
6201 /* If we are trying to set what we already have, don't bother */
6202 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6203 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6206 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6207 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6208 This->render_targets[RenderTargetIndex] = pRenderTarget;
6210 /* Render target 0 is special */
6211 if(RenderTargetIndex == 0 && dxVersion > 7) {
6212 /* Finally, reset the viewport and scissor rect as the MSDN states.
6213 * Tests show that stateblock recording is ignored, the change goes
6214 * directly into the primary stateblock.
6216 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6217 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6218 This->stateBlock->viewport.X = 0;
6219 This->stateBlock->viewport.Y = 0;
6220 This->stateBlock->viewport.MaxZ = 1.0f;
6221 This->stateBlock->viewport.MinZ = 0.0f;
6222 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6224 This->stateBlock->scissorRect.top = 0;
6225 This->stateBlock->scissorRect.left = 0;
6226 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
6227 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
6228 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6233 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6235 HRESULT hr = WINED3D_OK;
6236 IWineD3DSurface *tmp;
6238 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6240 if (pNewZStencil == This->stencilBufferTarget) {
6241 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6243 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6244 * depending on the renter target implementation being used.
6245 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6246 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6247 * stencil buffer and incur an extra memory overhead
6248 ******************************************************/
6250 if (This->stencilBufferTarget) {
6251 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6252 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6253 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6255 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6256 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
6257 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6258 context_release(context);
6262 tmp = This->stencilBufferTarget;
6263 This->stencilBufferTarget = pNewZStencil;
6264 /* should we be calling the parent or the wined3d surface? */
6265 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6266 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6269 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6270 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6271 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6272 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6273 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6280 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6281 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6283 /* TODO: the use of Impl is deprecated. */
6284 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6285 WINED3DLOCKED_RECT lockedRect;
6287 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6289 /* some basic validation checks */
6290 if(This->cursorTexture) {
6291 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6293 glDeleteTextures(1, &This->cursorTexture);
6295 context_release(context);
6296 This->cursorTexture = 0;
6299 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6300 This->haveHardwareCursor = TRUE;
6302 This->haveHardwareCursor = FALSE;
6305 WINED3DLOCKED_RECT rect;
6307 /* MSDN: Cursor must be A8R8G8B8 */
6308 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6310 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6311 return WINED3DERR_INVALIDCALL;
6314 /* MSDN: Cursor must be smaller than the display mode */
6315 if(pSur->currentDesc.Width > This->ddraw_width ||
6316 pSur->currentDesc.Height > This->ddraw_height) {
6317 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);
6318 return WINED3DERR_INVALIDCALL;
6321 if (!This->haveHardwareCursor) {
6322 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6324 /* Do not store the surface's pointer because the application may
6325 * release it after setting the cursor image. Windows doesn't
6326 * addref the set surface, so we can't do this either without
6327 * creating circular refcount dependencies. Copy out the gl texture
6330 This->cursorWidth = pSur->currentDesc.Width;
6331 This->cursorHeight = pSur->currentDesc.Height;
6332 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6334 const struct GlPixelFormatDesc *glDesc =
6335 getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, &This->adapter->gl_info);
6336 struct wined3d_context *context;
6337 char *mem, *bits = rect.pBits;
6338 GLint intfmt = glDesc->glInternal;
6339 GLint format = glDesc->glFormat;
6340 GLint type = glDesc->glType;
6341 INT height = This->cursorHeight;
6342 INT width = This->cursorWidth;
6343 INT bpp = glDesc->byte_count;
6347 /* Reformat the texture memory (pitch and width can be
6349 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6350 for(i = 0; i < height; i++)
6351 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6352 IWineD3DSurface_UnlockRect(pCursorBitmap);
6354 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6358 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6359 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6360 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6363 /* Make sure that a proper texture unit is selected */
6364 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6365 checkGLcall("glActiveTextureARB");
6366 sampler = This->rev_tex_unit_map[0];
6367 if (sampler != WINED3D_UNMAPPED_STAGE)
6369 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6371 /* Create a new cursor texture */
6372 glGenTextures(1, &This->cursorTexture);
6373 checkGLcall("glGenTextures");
6374 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6375 checkGLcall("glBindTexture");
6376 /* Copy the bitmap memory into the cursor texture */
6377 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6378 HeapFree(GetProcessHeap(), 0, mem);
6379 checkGLcall("glTexImage2D");
6381 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6382 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6383 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6388 context_release(context);
6392 FIXME("A cursor texture was not returned.\n");
6393 This->cursorTexture = 0;
6398 /* Draw a hardware cursor */
6399 ICONINFO cursorInfo;
6401 /* Create and clear maskBits because it is not needed for
6402 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6404 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6405 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6406 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6407 WINED3DLOCK_NO_DIRTY_UPDATE |
6408 WINED3DLOCK_READONLY
6410 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6411 pSur->currentDesc.Height);
6413 cursorInfo.fIcon = FALSE;
6414 cursorInfo.xHotspot = XHotSpot;
6415 cursorInfo.yHotspot = YHotSpot;
6416 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6418 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6419 1, 32, lockedRect.pBits);
6420 IWineD3DSurface_UnlockRect(pCursorBitmap);
6421 /* Create our cursor and clean up. */
6422 cursor = CreateIconIndirect(&cursorInfo);
6424 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6425 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6426 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6427 This->hardwareCursor = cursor;
6428 HeapFree(GetProcessHeap(), 0, maskBits);
6432 This->xHotSpot = XHotSpot;
6433 This->yHotSpot = YHotSpot;
6437 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6439 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6441 This->xScreenSpace = XScreenSpace;
6442 This->yScreenSpace = YScreenSpace;
6448 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6449 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6450 BOOL oldVisible = This->bCursorVisible;
6453 TRACE("(%p) : visible(%d)\n", This, bShow);
6456 * When ShowCursor is first called it should make the cursor appear at the OS's last
6457 * known cursor position. Because of this, some applications just repetitively call
6458 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6461 This->xScreenSpace = pt.x;
6462 This->yScreenSpace = pt.y;
6464 if (This->haveHardwareCursor) {
6465 This->bCursorVisible = bShow;
6467 SetCursor(This->hardwareCursor);
6473 if (This->cursorTexture)
6474 This->bCursorVisible = bShow;
6480 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6482 IWineD3DResourceImpl *resource;
6483 TRACE("(%p) : state (%u)\n", This, This->state);
6485 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6486 switch (This->state) {
6489 case WINED3DERR_DEVICELOST:
6491 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6492 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6493 return WINED3DERR_DEVICENOTRESET;
6495 return WINED3DERR_DEVICELOST;
6497 case WINED3DERR_DRIVERINTERNALERROR:
6498 return WINED3DERR_DRIVERINTERNALERROR;
6502 return WINED3DERR_DRIVERINTERNALERROR;
6505 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6506 TRACE("checking resource %p for eviction\n", resource);
6507 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6508 TRACE("Evicting %p\n", resource);
6509 IWineD3DResource_UnLoad(resource);
6511 IWineD3DResource_Release(resource);
6515 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6517 TRACE("(%p)\n", This);
6519 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6523 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6525 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6527 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6528 if(surface->Flags & SFLAG_DIBSECTION) {
6529 /* Release the DC */
6530 SelectObject(surface->hDC, surface->dib.holdbitmap);
6531 DeleteDC(surface->hDC);
6532 /* Release the DIB section */
6533 DeleteObject(surface->dib.DIBsection);
6534 surface->dib.bitmap_data = NULL;
6535 surface->resource.allocatedMemory = NULL;
6536 surface->Flags &= ~SFLAG_DIBSECTION;
6538 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6539 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6540 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6541 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6542 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6543 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6545 surface->pow2Width = surface->pow2Height = 1;
6546 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6547 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6549 surface->glRect.left = 0;
6550 surface->glRect.top = 0;
6551 surface->glRect.right = surface->pow2Width;
6552 surface->glRect.bottom = surface->pow2Height;
6554 if (surface->texture_name)
6556 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6558 glDeleteTextures(1, &surface->texture_name);
6560 context_release(context);
6561 surface->texture_name = 0;
6562 surface->Flags &= ~SFLAG_CLIENT;
6564 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6565 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6566 surface->Flags |= SFLAG_NONPOW2;
6568 surface->Flags &= ~SFLAG_NONPOW2;
6570 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6571 surface->resource.allocatedMemory = NULL;
6572 surface->resource.heapMemory = NULL;
6573 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6574 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6575 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6576 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6578 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6582 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6583 TRACE("Unloading resource %p\n", resource);
6584 IWineD3DResource_UnLoad(resource);
6585 IWineD3DResource_Release(resource);
6589 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6592 WINED3DDISPLAYMODE m;
6595 /* All Windowed modes are supported, as is leaving the current mode */
6596 if(pp->Windowed) return TRUE;
6597 if(!pp->BackBufferWidth) return TRUE;
6598 if(!pp->BackBufferHeight) return TRUE;
6600 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6601 for(i = 0; i < count; i++) {
6602 memset(&m, 0, sizeof(m));
6603 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6605 ERR("EnumAdapterModes failed\n");
6607 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6608 /* Mode found, it is supported */
6612 /* Mode not found -> not supported */
6616 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6618 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6619 const struct wined3d_gl_info *gl_info;
6620 struct wined3d_context *context;
6622 IWineD3DBaseShaderImpl *shader;
6624 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6625 gl_info = context->gl_info;
6627 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6628 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6629 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6633 if(This->depth_blt_texture) {
6634 glDeleteTextures(1, &This->depth_blt_texture);
6635 This->depth_blt_texture = 0;
6637 if (This->depth_blt_rb) {
6638 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6639 This->depth_blt_rb = 0;
6640 This->depth_blt_rb_w = 0;
6641 This->depth_blt_rb_h = 0;
6645 This->blitter->free_private(iface);
6646 This->frag_pipe->free_private(iface);
6647 This->shader_backend->shader_free_private(iface);
6650 for (i = 0; i < This->adapter->gl_info.max_textures; ++i)
6652 /* Textures are recreated below */
6653 glDeleteTextures(1, &This->dummyTextureName[i]);
6654 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6655 This->dummyTextureName[i] = 0;
6659 context_release(context);
6661 while (This->numContexts)
6663 context_destroy(This, This->contexts[0]);
6665 HeapFree(GetProcessHeap(), 0, swapchain->context);
6666 swapchain->context = NULL;
6667 swapchain->num_contexts = 0;
6670 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6672 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6674 IWineD3DSurfaceImpl *target;
6676 /* Recreate the primary swapchain's context */
6677 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6678 if(swapchain->backBuffer) {
6679 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6681 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6683 swapchain->context[0] = context_create(This, target, swapchain->win_handle, FALSE, &swapchain->presentParms);
6684 swapchain->num_contexts = 1;
6686 create_dummy_textures(This);
6688 context_release(swapchain->context[0]);
6690 hr = This->shader_backend->shader_alloc_private(iface);
6692 ERR("Failed to recreate shader private data\n");
6695 hr = This->frag_pipe->alloc_private(iface);
6697 TRACE("Fragment pipeline private data couldn't be allocated\n");
6700 hr = This->blitter->alloc_private(iface);
6702 TRACE("Blitter private data couldn't be allocated\n");
6709 This->blitter->free_private(iface);
6710 This->frag_pipe->free_private(iface);
6711 This->shader_backend->shader_free_private(iface);
6715 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6717 IWineD3DSwapChainImpl *swapchain;
6719 BOOL DisplayModeChanged = FALSE;
6720 WINED3DDISPLAYMODE mode;
6721 TRACE("(%p)\n", This);
6723 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6725 ERR("Failed to get the first implicit swapchain\n");
6729 if(!is_display_mode_supported(This, pPresentationParameters)) {
6730 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6731 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6732 pPresentationParameters->BackBufferHeight);
6733 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6734 return WINED3DERR_INVALIDCALL;
6737 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6738 * on an existing gl context, so there's no real need for recreation.
6740 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6742 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6744 TRACE("New params:\n");
6745 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6746 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6747 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6748 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6749 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6750 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6751 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6752 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6753 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6754 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6755 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6756 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6757 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6759 /* No special treatment of these parameters. Just store them */
6760 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6761 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6762 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6763 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6765 /* What to do about these? */
6766 if(pPresentationParameters->BackBufferCount != 0 &&
6767 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6768 ERR("Cannot change the back buffer count yet\n");
6770 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6771 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6772 ERR("Cannot change the back buffer format yet\n");
6774 if(pPresentationParameters->hDeviceWindow != NULL &&
6775 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6776 ERR("Cannot change the device window yet\n");
6778 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6781 TRACE("Creating the depth stencil buffer\n");
6783 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6785 pPresentationParameters->BackBufferWidth,
6786 pPresentationParameters->BackBufferHeight,
6787 pPresentationParameters->AutoDepthStencilFormat,
6788 pPresentationParameters->MultiSampleType,
6789 pPresentationParameters->MultiSampleQuality,
6791 &This->auto_depth_stencil_buffer);
6794 ERR("Failed to create the depth stencil buffer\n");
6795 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6796 return WINED3DERR_INVALIDCALL;
6800 /* Reset the depth stencil */
6801 if (pPresentationParameters->EnableAutoDepthStencil)
6802 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6804 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6806 TRACE("Resetting stateblock\n");
6807 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6808 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6810 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6812 if(pPresentationParameters->Windowed) {
6813 mode.Width = swapchain->orig_width;
6814 mode.Height = swapchain->orig_height;
6815 mode.RefreshRate = 0;
6816 mode.Format = swapchain->presentParms.BackBufferFormat;
6818 mode.Width = pPresentationParameters->BackBufferWidth;
6819 mode.Height = pPresentationParameters->BackBufferHeight;
6820 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6821 mode.Format = swapchain->presentParms.BackBufferFormat;
6824 /* Should Width == 800 && Height == 0 set 800x600? */
6825 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6826 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6827 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6831 if(!pPresentationParameters->Windowed) {
6832 DisplayModeChanged = TRUE;
6834 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6835 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6837 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6838 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6839 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6841 if(This->auto_depth_stencil_buffer) {
6842 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6846 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6847 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6848 DisplayModeChanged) {
6850 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6852 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
6853 if(swapchain->presentParms.Windowed) {
6854 /* switch from windowed to fs */
6855 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
6856 pPresentationParameters->BackBufferWidth,
6857 pPresentationParameters->BackBufferHeight);
6859 /* Fullscreen -> fullscreen mode change */
6860 MoveWindow(swapchain->win_handle, 0, 0,
6861 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6864 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
6865 /* Fullscreen -> windowed switch */
6866 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
6868 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6869 } else if(!pPresentationParameters->Windowed) {
6870 DWORD style = This->style, exStyle = This->exStyle;
6871 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6872 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6873 * Reset to clear up their mess. Guild Wars also loses the device during that.
6877 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
6878 pPresentationParameters->BackBufferWidth,
6879 pPresentationParameters->BackBufferHeight);
6880 This->style = style;
6881 This->exStyle = exStyle;
6884 /* Note: No parent needed for initial internal stateblock */
6885 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6886 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6887 else TRACE("Created stateblock %p\n", This->stateBlock);
6888 This->updateStateBlock = This->stateBlock;
6889 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6891 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6893 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6896 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6897 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6899 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6905 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6907 /** FIXME: always true at the moment **/
6908 if(!bEnableDialogs) {
6909 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6915 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6917 TRACE("(%p) : pParameters %p\n", This, pParameters);
6919 *pParameters = This->createParms;
6923 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6924 IWineD3DSwapChain *swapchain;
6926 TRACE("Relaying to swapchain\n");
6928 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6929 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6930 IWineD3DSwapChain_Release(swapchain);
6935 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6936 IWineD3DSwapChain *swapchain;
6938 TRACE("Relaying to swapchain\n");
6940 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6941 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6942 IWineD3DSwapChain_Release(swapchain);
6948 /** ********************************************************
6949 * Notification functions
6950 ** ********************************************************/
6951 /** This function must be called in the release of a resource when ref == 0,
6952 * the contents of resource must still be correct,
6953 * any handles to other resource held by the caller must be closed
6954 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6955 *****************************************************/
6956 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6958 TRACE("(%p) : Adding resource %p\n", This, resource);
6960 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6963 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6965 TRACE("(%p) : Removing resource %p\n", This, resource);
6967 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6970 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6972 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6975 TRACE("(%p) : resource %p\n", This, resource);
6977 context_resource_released((IWineD3DDevice *)This, resource, type);
6980 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6981 case WINED3DRTYPE_SURFACE: {
6984 if (This->d3d_initialized)
6986 for (i = 0; i < This->adapter->gl_info.max_buffers; ++i)
6988 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6989 This->render_targets[i] = NULL;
6992 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6993 This->stencilBufferTarget = NULL;
6999 case WINED3DRTYPE_TEXTURE:
7000 case WINED3DRTYPE_CUBETEXTURE:
7001 case WINED3DRTYPE_VOLUMETEXTURE:
7002 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7003 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7004 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7005 This->stateBlock->textures[counter] = NULL;
7007 if (This->updateStateBlock != This->stateBlock ){
7008 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7009 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7010 This->updateStateBlock->textures[counter] = NULL;
7015 case WINED3DRTYPE_VOLUME:
7016 /* TODO: nothing really? */
7018 case WINED3DRTYPE_BUFFER:
7021 TRACE("Cleaning up stream pointers\n");
7023 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7024 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7025 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7027 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7028 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7029 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7030 This->updateStateBlock->streamSource[streamNumber] = 0;
7031 /* Set changed flag? */
7034 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) */
7035 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7036 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7037 This->stateBlock->streamSource[streamNumber] = 0;
7042 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7043 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7044 This->updateStateBlock->pIndexData = NULL;
7047 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7048 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7049 This->stateBlock->pIndexData = NULL;
7056 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7061 /* Remove the resource from the resourceStore */
7062 device_resource_remove(This, resource);
7064 TRACE("Resource released\n");
7068 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7070 IWineD3DResourceImpl *resource, *cursor;
7072 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7074 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7075 TRACE("enumerating resource %p\n", resource);
7076 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7077 ret = pCallback((IWineD3DResource *) resource, pData);
7078 if(ret == S_FALSE) {
7079 TRACE("Canceling enumeration\n");
7086 /**********************************************************
7087 * IWineD3DDevice VTbl follows
7088 **********************************************************/
7090 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7092 /*** IUnknown methods ***/
7093 IWineD3DDeviceImpl_QueryInterface,
7094 IWineD3DDeviceImpl_AddRef,
7095 IWineD3DDeviceImpl_Release,
7096 /*** IWineD3DDevice methods ***/
7097 IWineD3DDeviceImpl_GetParent,
7098 /*** Creation methods**/
7099 IWineD3DDeviceImpl_CreateBuffer,
7100 IWineD3DDeviceImpl_CreateVertexBuffer,
7101 IWineD3DDeviceImpl_CreateIndexBuffer,
7102 IWineD3DDeviceImpl_CreateStateBlock,
7103 IWineD3DDeviceImpl_CreateSurface,
7104 IWineD3DDeviceImpl_CreateRendertargetView,
7105 IWineD3DDeviceImpl_CreateTexture,
7106 IWineD3DDeviceImpl_CreateVolumeTexture,
7107 IWineD3DDeviceImpl_CreateVolume,
7108 IWineD3DDeviceImpl_CreateCubeTexture,
7109 IWineD3DDeviceImpl_CreateQuery,
7110 IWineD3DDeviceImpl_CreateSwapChain,
7111 IWineD3DDeviceImpl_CreateVertexDeclaration,
7112 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7113 IWineD3DDeviceImpl_CreateVertexShader,
7114 IWineD3DDeviceImpl_CreatePixelShader,
7115 IWineD3DDeviceImpl_CreatePalette,
7116 /*** Odd functions **/
7117 IWineD3DDeviceImpl_Init3D,
7118 IWineD3DDeviceImpl_InitGDI,
7119 IWineD3DDeviceImpl_Uninit3D,
7120 IWineD3DDeviceImpl_UninitGDI,
7121 IWineD3DDeviceImpl_SetMultithreaded,
7122 IWineD3DDeviceImpl_EvictManagedResources,
7123 IWineD3DDeviceImpl_GetAvailableTextureMem,
7124 IWineD3DDeviceImpl_GetBackBuffer,
7125 IWineD3DDeviceImpl_GetCreationParameters,
7126 IWineD3DDeviceImpl_GetDeviceCaps,
7127 IWineD3DDeviceImpl_GetDirect3D,
7128 IWineD3DDeviceImpl_GetDisplayMode,
7129 IWineD3DDeviceImpl_SetDisplayMode,
7130 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7131 IWineD3DDeviceImpl_GetRasterStatus,
7132 IWineD3DDeviceImpl_GetSwapChain,
7133 IWineD3DDeviceImpl_Reset,
7134 IWineD3DDeviceImpl_SetDialogBoxMode,
7135 IWineD3DDeviceImpl_SetCursorProperties,
7136 IWineD3DDeviceImpl_SetCursorPosition,
7137 IWineD3DDeviceImpl_ShowCursor,
7138 IWineD3DDeviceImpl_TestCooperativeLevel,
7139 /*** Getters and setters **/
7140 IWineD3DDeviceImpl_SetClipPlane,
7141 IWineD3DDeviceImpl_GetClipPlane,
7142 IWineD3DDeviceImpl_SetClipStatus,
7143 IWineD3DDeviceImpl_GetClipStatus,
7144 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7145 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7146 IWineD3DDeviceImpl_SetDepthStencilSurface,
7147 IWineD3DDeviceImpl_GetDepthStencilSurface,
7148 IWineD3DDeviceImpl_SetGammaRamp,
7149 IWineD3DDeviceImpl_GetGammaRamp,
7150 IWineD3DDeviceImpl_SetIndexBuffer,
7151 IWineD3DDeviceImpl_GetIndexBuffer,
7152 IWineD3DDeviceImpl_SetBaseVertexIndex,
7153 IWineD3DDeviceImpl_GetBaseVertexIndex,
7154 IWineD3DDeviceImpl_SetLight,
7155 IWineD3DDeviceImpl_GetLight,
7156 IWineD3DDeviceImpl_SetLightEnable,
7157 IWineD3DDeviceImpl_GetLightEnable,
7158 IWineD3DDeviceImpl_SetMaterial,
7159 IWineD3DDeviceImpl_GetMaterial,
7160 IWineD3DDeviceImpl_SetNPatchMode,
7161 IWineD3DDeviceImpl_GetNPatchMode,
7162 IWineD3DDeviceImpl_SetPaletteEntries,
7163 IWineD3DDeviceImpl_GetPaletteEntries,
7164 IWineD3DDeviceImpl_SetPixelShader,
7165 IWineD3DDeviceImpl_GetPixelShader,
7166 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7167 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7168 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7169 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7170 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7171 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7172 IWineD3DDeviceImpl_SetRenderState,
7173 IWineD3DDeviceImpl_GetRenderState,
7174 IWineD3DDeviceImpl_SetRenderTarget,
7175 IWineD3DDeviceImpl_GetRenderTarget,
7176 IWineD3DDeviceImpl_SetFrontBackBuffers,
7177 IWineD3DDeviceImpl_SetSamplerState,
7178 IWineD3DDeviceImpl_GetSamplerState,
7179 IWineD3DDeviceImpl_SetScissorRect,
7180 IWineD3DDeviceImpl_GetScissorRect,
7181 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7182 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7183 IWineD3DDeviceImpl_SetStreamSource,
7184 IWineD3DDeviceImpl_GetStreamSource,
7185 IWineD3DDeviceImpl_SetStreamSourceFreq,
7186 IWineD3DDeviceImpl_GetStreamSourceFreq,
7187 IWineD3DDeviceImpl_SetTexture,
7188 IWineD3DDeviceImpl_GetTexture,
7189 IWineD3DDeviceImpl_SetTextureStageState,
7190 IWineD3DDeviceImpl_GetTextureStageState,
7191 IWineD3DDeviceImpl_SetTransform,
7192 IWineD3DDeviceImpl_GetTransform,
7193 IWineD3DDeviceImpl_SetVertexDeclaration,
7194 IWineD3DDeviceImpl_GetVertexDeclaration,
7195 IWineD3DDeviceImpl_SetVertexShader,
7196 IWineD3DDeviceImpl_GetVertexShader,
7197 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7198 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7199 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7200 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7201 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7202 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7203 IWineD3DDeviceImpl_SetViewport,
7204 IWineD3DDeviceImpl_GetViewport,
7205 IWineD3DDeviceImpl_MultiplyTransform,
7206 IWineD3DDeviceImpl_ValidateDevice,
7207 IWineD3DDeviceImpl_ProcessVertices,
7208 /*** State block ***/
7209 IWineD3DDeviceImpl_BeginStateBlock,
7210 IWineD3DDeviceImpl_EndStateBlock,
7211 /*** Scene management ***/
7212 IWineD3DDeviceImpl_BeginScene,
7213 IWineD3DDeviceImpl_EndScene,
7214 IWineD3DDeviceImpl_Present,
7215 IWineD3DDeviceImpl_Clear,
7216 IWineD3DDeviceImpl_ClearRendertargetView,
7218 IWineD3DDeviceImpl_SetPrimitiveType,
7219 IWineD3DDeviceImpl_GetPrimitiveType,
7220 IWineD3DDeviceImpl_DrawPrimitive,
7221 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7222 IWineD3DDeviceImpl_DrawPrimitiveUP,
7223 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7224 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7225 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7226 IWineD3DDeviceImpl_DrawRectPatch,
7227 IWineD3DDeviceImpl_DrawTriPatch,
7228 IWineD3DDeviceImpl_DeletePatch,
7229 IWineD3DDeviceImpl_ColorFill,
7230 IWineD3DDeviceImpl_UpdateTexture,
7231 IWineD3DDeviceImpl_UpdateSurface,
7232 IWineD3DDeviceImpl_GetFrontBufferData,
7233 /*** object tracking ***/
7234 IWineD3DDeviceImpl_EnumResources
7237 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7238 DWORD rep = This->StateTable[state].representative;
7239 struct wined3d_context *context;
7244 for(i = 0; i < This->numContexts; i++) {
7245 context = This->contexts[i];
7246 if(isStateDirty(context, rep)) continue;
7248 context->dirtyArray[context->numDirtyEntries++] = rep;
7251 context->isStateDirty[idx] |= (1 << shift);
7255 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7257 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.wineD3DDevice;
7258 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7259 *width = device->pbufferWidth;
7260 *height = device->pbufferHeight;
7263 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7265 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7266 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7267 *width = surface->pow2Width;
7268 *height = surface->pow2Height;
7271 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7273 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7274 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7275 * current context's drawable, which is the size of the back buffer of the swapchain
7276 * the active context belongs to. The back buffer of the swapchain is stored as the
7277 * surface the context belongs to. */
7278 *width = surface->currentDesc.Width;
7279 *height = surface->currentDesc.Height;