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) {
1197 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1198 if (!object->context[0]) {
1199 ERR("Failed to create a new context\n");
1200 hr = WINED3DERR_NOTAVAILABLE;
1203 TRACE("Context created (HWND=%p, glContext=%p)\n",
1204 object->win_handle, object->context[0]->glCtx);
1208 /*********************
1209 * Create the back, front and stencil buffers
1210 *******************/
1211 if(object->presentParms.BackBufferCount > 0) {
1214 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1215 if(!object->backBuffer) {
1216 ERR("Out of memory\n");
1221 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1222 TRACE("calling rendertarget CB\n");
1223 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1224 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1225 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1226 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1228 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1229 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1231 ERR("Cannot create new back buffer\n");
1234 if(surface_type == SURFACE_OPENGL) {
1236 glDrawBuffer(GL_BACK);
1237 checkGLcall("glDrawBuffer(GL_BACK)");
1242 object->backBuffer = NULL;
1244 /* Single buffering - draw to front buffer */
1245 if(surface_type == SURFACE_OPENGL) {
1247 glDrawBuffer(GL_FRONT);
1248 checkGLcall("glDrawBuffer(GL_FRONT)");
1253 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1254 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1255 TRACE("Creating depth stencil buffer\n");
1256 if (This->auto_depth_stencil_buffer == NULL ) {
1257 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1258 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1259 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1260 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1261 &This->auto_depth_stencil_buffer);
1262 if (SUCCEEDED(hr)) {
1263 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1265 ERR("Failed to create the auto depth stencil\n");
1271 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1273 TRACE("Created swapchain %p\n", object);
1274 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1278 if (displaymode_set) {
1282 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1285 /* Change the display settings */
1286 memset(&devmode, 0, sizeof(devmode));
1287 devmode.dmSize = sizeof(devmode);
1288 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1289 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1290 devmode.dmPelsWidth = object->orig_width;
1291 devmode.dmPelsHeight = object->orig_height;
1292 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1295 if (object->backBuffer) {
1297 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1298 if (object->backBuffer[i]) IWineD3DSurface_Release(object->backBuffer[i]);
1300 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1301 object->backBuffer = NULL;
1303 if(object->context && object->context[0])
1304 DestroyContext(This, object->context[0]);
1305 if (object->frontBuffer) IWineD3DSurface_Release(object->frontBuffer);
1306 HeapFree(GetProcessHeap(), 0, object);
1310 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1311 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1313 TRACE("(%p)\n", This);
1315 return This->NumberOfSwapChains;
1318 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1320 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1322 if(iSwapChain < This->NumberOfSwapChains) {
1323 *pSwapChain = This->swapchains[iSwapChain];
1324 IWineD3DSwapChain_AddRef(*pSwapChain);
1325 TRACE("(%p) returning %p\n", This, *pSwapChain);
1328 TRACE("Swapchain out of range\n");
1330 return WINED3DERR_INVALIDCALL;
1334 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1335 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1336 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1339 IWineD3DVertexDeclarationImpl *object = NULL;
1342 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1343 iface, declaration, parent, elements, element_count);
1345 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1348 ERR("Failed to allocate vertex declaration memory.\n");
1349 return E_OUTOFMEMORY;
1352 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1355 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1356 HeapFree(GetProcessHeap(), 0, object);
1360 TRACE("Created vertex declaration %p.\n", object);
1361 *declaration = (IWineD3DVertexDeclaration *)object;
1366 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1367 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1369 unsigned int idx, idx2;
1370 unsigned int offset;
1371 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1372 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1373 BOOL has_blend_idx = has_blend &&
1374 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1375 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1376 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1377 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1378 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1379 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1380 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1382 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1383 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1384 WINED3DVERTEXELEMENT *elements = NULL;
1387 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1388 if (has_blend_idx) num_blends--;
1390 /* Compute declaration size */
1391 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1392 has_psize + has_diffuse + has_specular + num_textures;
1394 /* convert the declaration */
1395 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1396 if (!elements) return ~0U;
1400 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1401 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1402 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1404 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1405 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1406 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1409 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1410 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1412 elements[idx].usage_idx = 0;
1415 if (has_blend && (num_blends > 0)) {
1416 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1417 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1419 switch(num_blends) {
1420 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1421 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1422 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1423 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1425 ERR("Unexpected amount of blend values: %u\n", num_blends);
1428 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1429 elements[idx].usage_idx = 0;
1432 if (has_blend_idx) {
1433 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1434 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1435 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1436 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1437 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1439 elements[idx].format = WINED3DFMT_R32_FLOAT;
1440 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1441 elements[idx].usage_idx = 0;
1445 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1446 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1447 elements[idx].usage_idx = 0;
1451 elements[idx].format = WINED3DFMT_R32_FLOAT;
1452 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1453 elements[idx].usage_idx = 0;
1457 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1458 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1459 elements[idx].usage_idx = 0;
1463 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1464 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1465 elements[idx].usage_idx = 1;
1468 for (idx2 = 0; idx2 < num_textures; idx2++) {
1469 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1470 switch (numcoords) {
1471 case WINED3DFVF_TEXTUREFORMAT1:
1472 elements[idx].format = WINED3DFMT_R32_FLOAT;
1474 case WINED3DFVF_TEXTUREFORMAT2:
1475 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1477 case WINED3DFVF_TEXTUREFORMAT3:
1478 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1480 case WINED3DFVF_TEXTUREFORMAT4:
1481 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1484 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1485 elements[idx].usage_idx = idx2;
1489 /* Now compute offsets, and initialize the rest of the fields */
1490 for (idx = 0, offset = 0; idx < size; ++idx)
1492 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1493 elements[idx].input_slot = 0;
1494 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1495 elements[idx].offset = offset;
1496 offset += format_desc->component_count * format_desc->component_size;
1499 *ppVertexElements = elements;
1503 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1504 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1505 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1507 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1508 WINED3DVERTEXELEMENT *elements;
1512 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1514 size = ConvertFvfToDeclaration(This, fvf, &elements);
1515 if (size == ~0U) return E_OUTOFMEMORY;
1517 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1518 HeapFree(GetProcessHeap(), 0, elements);
1522 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1523 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1524 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1525 const struct wined3d_parent_ops *parent_ops)
1527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1528 IWineD3DVertexShaderImpl *object;
1531 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1534 ERR("Failed to allocate shader memory.\n");
1535 return E_OUTOFMEMORY;
1538 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1541 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1542 HeapFree(GetProcessHeap(), 0, object);
1546 TRACE("Created vertex shader %p.\n", object);
1547 *ppVertexShader = (IWineD3DVertexShader *)object;
1552 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1553 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1554 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1555 const struct wined3d_parent_ops *parent_ops)
1557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1558 IWineD3DPixelShaderImpl *object;
1561 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1564 ERR("Failed to allocate shader memory.\n");
1565 return E_OUTOFMEMORY;
1568 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1571 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1572 HeapFree(GetProcessHeap(), 0, object);
1576 TRACE("Created pixel shader %p.\n", object);
1577 *ppPixelShader = (IWineD3DPixelShader *)object;
1582 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1583 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1586 IWineD3DPaletteImpl *object;
1588 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1590 /* Create the new object */
1591 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1593 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1594 return E_OUTOFMEMORY;
1597 object->lpVtbl = &IWineD3DPalette_Vtbl;
1599 object->Flags = Flags;
1600 object->parent = Parent;
1601 object->wineD3DDevice = This;
1602 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1603 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1606 HeapFree( GetProcessHeap(), 0, object);
1607 return E_OUTOFMEMORY;
1610 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1612 IWineD3DPalette_Release((IWineD3DPalette *) object);
1616 *Palette = (IWineD3DPalette *) object;
1621 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1625 HDC dcb = NULL, dcs = NULL;
1626 WINEDDCOLORKEY colorkey;
1628 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1631 GetObjectA(hbm, sizeof(BITMAP), &bm);
1632 dcb = CreateCompatibleDC(NULL);
1634 SelectObject(dcb, hbm);
1638 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1639 * couldn't be loaded
1641 memset(&bm, 0, sizeof(bm));
1646 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1647 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1648 NULL, &wined3d_null_parent_ops);
1650 ERR("Wine logo requested, but failed to create surface\n");
1655 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1656 if(FAILED(hr)) goto out;
1657 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1658 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1660 colorkey.dwColorSpaceLowValue = 0;
1661 colorkey.dwColorSpaceHighValue = 0;
1662 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1664 /* Fill the surface with a white color to show that wined3d is there */
1665 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1678 /* Context activation is done by the caller. */
1679 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1681 /* Under DirectX you can have texture stage operations even if no texture is
1682 bound, whereas opengl will only do texture operations when a valid texture is
1683 bound. We emulate this by creating dummy textures and binding them to each
1684 texture stage, but disable all stages by default. Hence if a stage is enabled
1685 then the default texture will kick in until replaced by a SetTexture call */
1688 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1689 /* The dummy texture does not have client storage backing */
1690 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1691 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1694 for (i = 0; i < This->adapter->gl_info.max_textures; ++i)
1696 GLubyte white = 255;
1698 /* Make appropriate texture active */
1699 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1700 checkGLcall("glActiveTextureARB");
1702 /* Generate an opengl texture name */
1703 glGenTextures(1, &This->dummyTextureName[i]);
1704 checkGLcall("glGenTextures");
1705 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1707 /* Generate a dummy 2d texture (not using 1d because they cause many
1708 * DRI drivers fall back to sw) */
1709 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1710 checkGLcall("glBindTexture");
1712 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1713 checkGLcall("glTexImage2D");
1715 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1716 /* Reenable because if supported it is enabled by default */
1717 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1718 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1724 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1725 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1728 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1729 IWineD3DSwapChainImpl *swapchain = NULL;
1734 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1736 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1737 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1739 /* TODO: Test if OpenGL is compiled in and loaded */
1741 TRACE("(%p) : Creating stateblock\n", This);
1742 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1743 hr = IWineD3DDevice_CreateStateBlock(iface,
1745 (IWineD3DStateBlock **)&This->stateBlock,
1747 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1748 WARN("Failed to create stateblock\n");
1751 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1752 This->updateStateBlock = This->stateBlock;
1753 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1755 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1756 sizeof(IWineD3DSurface *) * gl_info->max_buffers);
1757 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1758 sizeof(GLenum) * gl_info->max_buffers);
1760 This->NumberOfPalettes = 1;
1761 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1762 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1763 ERR("Out of memory!\n");
1766 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1767 if(!This->palettes[0]) {
1768 ERR("Out of memory!\n");
1771 for (i = 0; i < 256; ++i) {
1772 This->palettes[0][i].peRed = 0xFF;
1773 This->palettes[0][i].peGreen = 0xFF;
1774 This->palettes[0][i].peBlue = 0xFF;
1775 This->palettes[0][i].peFlags = 0xFF;
1777 This->currentPalette = 0;
1779 /* Initialize the texture unit mapping to a 1:1 mapping */
1780 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1782 if (state < gl_info->max_fragment_samplers)
1784 This->texUnitMap[state] = state;
1785 This->rev_tex_unit_map[state] = state;
1787 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1788 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1792 /* Setup the implicit swapchain. This also initializes a context. */
1793 TRACE("Creating implicit swapchain\n");
1794 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1795 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1798 WARN("Failed to create implicit swapchain\n");
1802 This->NumberOfSwapChains = 1;
1803 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1804 if(!This->swapchains) {
1805 ERR("Out of memory!\n");
1808 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1810 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1811 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1812 This->render_targets[0] = swapchain->backBuffer[0];
1815 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1816 This->render_targets[0] = swapchain->frontBuffer;
1818 IWineD3DSurface_AddRef(This->render_targets[0]);
1820 /* Depth Stencil support */
1821 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1822 if (NULL != This->stencilBufferTarget) {
1823 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1826 hr = This->shader_backend->shader_alloc_private(iface);
1828 TRACE("Shader private data couldn't be allocated\n");
1831 hr = This->frag_pipe->alloc_private(iface);
1833 TRACE("Fragment pipeline private data couldn't be allocated\n");
1836 hr = This->blitter->alloc_private(iface);
1838 TRACE("Blitter private data couldn't be allocated\n");
1842 /* Set up some starting GL setup */
1844 /* Setup all the devices defaults */
1845 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1846 create_dummy_textures(This);
1850 /* Initialize the current view state */
1851 This->view_ident = 1;
1852 This->contexts[0]->last_was_rhw = 0;
1853 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1854 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1856 switch(wined3d_settings.offscreen_rendering_mode) {
1859 This->offscreenBuffer = GL_BACK;
1862 case ORM_BACKBUFFER:
1864 if (context_get_current()->aux_buffers > 0)
1866 TRACE("Using auxilliary buffer for offscreen rendering\n");
1867 This->offscreenBuffer = GL_AUX0;
1869 TRACE("Using back buffer for offscreen rendering\n");
1870 This->offscreenBuffer = GL_BACK;
1875 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1878 /* Clear the screen */
1879 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1880 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1883 This->d3d_initialized = TRUE;
1885 if(wined3d_settings.logo) {
1886 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1888 This->highest_dirty_ps_const = 0;
1889 This->highest_dirty_vs_const = 0;
1893 HeapFree(GetProcessHeap(), 0, This->render_targets);
1894 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1895 HeapFree(GetProcessHeap(), 0, This->swapchains);
1896 This->NumberOfSwapChains = 0;
1897 if(This->palettes) {
1898 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1899 HeapFree(GetProcessHeap(), 0, This->palettes);
1901 This->NumberOfPalettes = 0;
1903 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1905 if(This->stateBlock) {
1906 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1907 This->stateBlock = NULL;
1909 if (This->blit_priv) {
1910 This->blitter->free_private(iface);
1912 if (This->fragment_priv) {
1913 This->frag_pipe->free_private(iface);
1915 if (This->shader_priv) {
1916 This->shader_backend->shader_free_private(iface);
1921 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1922 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1925 IWineD3DSwapChainImpl *swapchain = NULL;
1928 /* Setup the implicit swapchain */
1929 TRACE("Creating implicit swapchain\n");
1930 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1931 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1934 WARN("Failed to create implicit swapchain\n");
1938 This->NumberOfSwapChains = 1;
1939 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1940 if(!This->swapchains) {
1941 ERR("Out of memory!\n");
1944 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1948 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1952 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1954 IWineD3DResource_UnLoad(resource);
1955 IWineD3DResource_Release(resource);
1959 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1960 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1963 const struct wined3d_context *context;
1964 const struct wined3d_gl_info *gl_info;
1967 TRACE("(%p)\n", This);
1969 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1971 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1972 * it was created. Thus make sure a context is active for the glDelete* calls
1974 context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
1975 gl_info = context->gl_info;
1977 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1979 /* Unload resources */
1980 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1982 TRACE("Deleting high order patches\n");
1983 for(i = 0; i < PATCHMAP_SIZE; i++) {
1984 struct list *e1, *e2;
1985 struct WineD3DRectPatch *patch;
1986 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1987 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1988 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1992 /* Delete the palette conversion shader if it is around */
1993 if(This->paletteConversionShader) {
1995 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
1997 This->paletteConversionShader = 0;
2000 /* Delete the pbuffer context if there is any */
2001 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2003 /* Delete the mouse cursor texture */
2004 if(This->cursorTexture) {
2006 glDeleteTextures(1, &This->cursorTexture);
2008 This->cursorTexture = 0;
2011 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2012 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2014 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2015 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2018 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2019 * private data, it might contain opengl pointers
2021 if(This->depth_blt_texture) {
2023 glDeleteTextures(1, &This->depth_blt_texture);
2025 This->depth_blt_texture = 0;
2027 if (This->depth_blt_rb) {
2029 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2031 This->depth_blt_rb = 0;
2032 This->depth_blt_rb_w = 0;
2033 This->depth_blt_rb_h = 0;
2036 /* Release the update stateblock */
2037 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2038 if(This->updateStateBlock != This->stateBlock)
2039 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2041 This->updateStateBlock = NULL;
2043 { /* because were not doing proper internal refcounts releasing the primary state block
2044 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2045 to set this->stateBlock = NULL; first */
2046 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2047 This->stateBlock = NULL;
2049 /* Release the stateblock */
2050 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2051 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2055 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2056 This->blitter->free_private(iface);
2057 This->frag_pipe->free_private(iface);
2058 This->shader_backend->shader_free_private(iface);
2060 /* Release the buffers (with sanity checks)*/
2061 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2062 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2063 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2064 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2066 This->stencilBufferTarget = NULL;
2068 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2069 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2070 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2072 TRACE("Setting rendertarget to NULL\n");
2073 This->render_targets[0] = NULL;
2075 if (This->auto_depth_stencil_buffer) {
2076 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
2078 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2080 This->auto_depth_stencil_buffer = NULL;
2083 for(i=0; i < This->NumberOfSwapChains; i++) {
2084 TRACE("Releasing the implicit swapchain %d\n", i);
2085 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2086 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2090 HeapFree(GetProcessHeap(), 0, This->swapchains);
2091 This->swapchains = NULL;
2092 This->NumberOfSwapChains = 0;
2094 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2095 HeapFree(GetProcessHeap(), 0, This->palettes);
2096 This->palettes = NULL;
2097 This->NumberOfPalettes = 0;
2099 HeapFree(GetProcessHeap(), 0, This->render_targets);
2100 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2101 This->render_targets = NULL;
2102 This->draw_buffers = NULL;
2104 This->d3d_initialized = FALSE;
2108 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2112 for(i=0; i < This->NumberOfSwapChains; i++) {
2113 TRACE("Releasing the implicit swapchain %d\n", i);
2114 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2115 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2119 HeapFree(GetProcessHeap(), 0, This->swapchains);
2120 This->swapchains = NULL;
2121 This->NumberOfSwapChains = 0;
2125 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2126 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2127 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2129 * There is no way to deactivate thread safety once it is enabled.
2131 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2134 /*For now just store the flag(needed in case of ddraw) */
2135 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2140 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2141 const WINED3DDISPLAYMODE* pMode) {
2143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2145 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
2148 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2150 /* Resize the screen even without a window:
2151 * The app could have unset it with SetCooperativeLevel, but not called
2152 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2153 * but we don't have any hwnd
2156 memset(&devmode, 0, sizeof(devmode));
2157 devmode.dmSize = sizeof(devmode);
2158 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2159 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2160 devmode.dmPelsWidth = pMode->Width;
2161 devmode.dmPelsHeight = pMode->Height;
2163 devmode.dmDisplayFrequency = pMode->RefreshRate;
2164 if (pMode->RefreshRate != 0) {
2165 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2168 /* Only change the mode if necessary */
2169 if( (This->ddraw_width == pMode->Width) &&
2170 (This->ddraw_height == pMode->Height) &&
2171 (This->ddraw_format == pMode->Format) &&
2172 (pMode->RefreshRate == 0) ) {
2176 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2177 if (ret != DISP_CHANGE_SUCCESSFUL) {
2178 if(devmode.dmDisplayFrequency != 0) {
2179 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2180 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2181 devmode.dmDisplayFrequency = 0;
2182 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2184 if(ret != DISP_CHANGE_SUCCESSFUL) {
2185 return WINED3DERR_NOTAVAILABLE;
2189 /* Store the new values */
2190 This->ddraw_width = pMode->Width;
2191 This->ddraw_height = pMode->Height;
2192 This->ddraw_format = pMode->Format;
2194 /* And finally clip mouse to our screen */
2195 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2196 ClipCursor(&clip_rc);
2201 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2203 *ppD3D= This->wineD3D;
2204 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2205 IWineD3D_AddRef(*ppD3D);
2209 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2212 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2213 (This->adapter->TextureRam/(1024*1024)),
2214 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2215 /* return simulated texture memory left */
2216 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2220 * Get / Set Stream Source
2222 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2223 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2226 IWineD3DBuffer *oldSrc;
2228 if (StreamNumber >= MAX_STREAMS) {
2229 WARN("Stream out of range %d\n", StreamNumber);
2230 return WINED3DERR_INVALIDCALL;
2231 } else if(OffsetInBytes & 0x3) {
2232 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2233 return WINED3DERR_INVALIDCALL;
2236 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2237 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2239 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2241 if(oldSrc == pStreamData &&
2242 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2243 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2244 TRACE("Application is setting the old values over, nothing to do\n");
2248 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2250 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2251 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2254 /* Handle recording of state blocks */
2255 if (This->isRecordingState) {
2256 TRACE("Recording... not performing anything\n");
2257 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2258 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2262 if (pStreamData != NULL) {
2263 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2264 IWineD3DBuffer_AddRef(pStreamData);
2266 if (oldSrc != NULL) {
2267 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2268 IWineD3DBuffer_Release(oldSrc);
2271 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2276 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2277 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2281 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2282 This->stateBlock->streamSource[StreamNumber],
2283 This->stateBlock->streamOffset[StreamNumber],
2284 This->stateBlock->streamStride[StreamNumber]);
2286 if (StreamNumber >= MAX_STREAMS) {
2287 WARN("Stream out of range %d\n", StreamNumber);
2288 return WINED3DERR_INVALIDCALL;
2290 *pStream = This->stateBlock->streamSource[StreamNumber];
2291 *pStride = This->stateBlock->streamStride[StreamNumber];
2293 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2296 if (*pStream != NULL) {
2297 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2302 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2304 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2305 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2307 /* Verify input at least in d3d9 this is invalid*/
2308 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2309 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2310 return WINED3DERR_INVALIDCALL;
2312 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2313 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2314 return WINED3DERR_INVALIDCALL;
2317 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2318 return WINED3DERR_INVALIDCALL;
2321 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2322 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2324 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2325 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2327 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2328 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2329 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2335 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2338 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2339 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2341 TRACE("(%p) : returning %d\n", This, *Divider);
2347 * Get / Set & Multiply Transform
2349 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2352 /* Most of this routine, comments included copied from ddraw tree initially: */
2353 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2355 /* Handle recording of state blocks */
2356 if (This->isRecordingState) {
2357 TRACE("Recording... not performing anything\n");
2358 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2359 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2364 * If the new matrix is the same as the current one,
2365 * we cut off any further processing. this seems to be a reasonable
2366 * optimization because as was noticed, some apps (warcraft3 for example)
2367 * tend towards setting the same matrix repeatedly for some reason.
2369 * From here on we assume that the new matrix is different, wherever it matters.
2371 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2372 TRACE("The app is setting the same matrix over again\n");
2375 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2379 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2380 where ViewMat = Camera space, WorldMat = world space.
2382 In OpenGL, camera and world space is combined into GL_MODELVIEW
2383 matrix. The Projection matrix stay projection matrix.
2386 /* Capture the times we can just ignore the change for now */
2387 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2388 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2389 /* Handled by the state manager */
2392 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2396 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2398 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2399 *pMatrix = This->stateBlock->transforms[State];
2403 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2404 const WINED3DMATRIX *mat = NULL;
2407 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2408 * below means it will be recorded in a state block change, but it
2409 * works regardless where it is recorded.
2410 * If this is found to be wrong, change to StateBlock.
2412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2413 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2415 if (State <= HIGHEST_TRANSFORMSTATE)
2417 mat = &This->updateStateBlock->transforms[State];
2419 FIXME("Unhandled transform state!!\n");
2422 multiply_matrix(&temp, mat, pMatrix);
2424 /* Apply change via set transform - will reapply to eg. lights this way */
2425 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2431 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2432 you can reference any indexes you want as long as that number max are enabled at any
2433 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2434 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2435 but when recording, just build a chain pretty much of commands to be replayed. */
2437 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2439 struct wined3d_light_info *object = NULL;
2440 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2444 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2446 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2450 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2451 return WINED3DERR_INVALIDCALL;
2454 switch(pLight->Type) {
2455 case WINED3DLIGHT_POINT:
2456 case WINED3DLIGHT_SPOT:
2457 case WINED3DLIGHT_PARALLELPOINT:
2458 case WINED3DLIGHT_GLSPOT:
2459 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2462 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2464 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2465 return WINED3DERR_INVALIDCALL;
2469 case WINED3DLIGHT_DIRECTIONAL:
2470 /* Ignores attenuation */
2474 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2475 return WINED3DERR_INVALIDCALL;
2478 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2480 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2481 if(object->OriginalIndex == Index) break;
2486 TRACE("Adding new light\n");
2487 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2489 ERR("Out of memory error when allocating a light\n");
2490 return E_OUTOFMEMORY;
2492 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2493 object->glIndex = -1;
2494 object->OriginalIndex = Index;
2497 /* Initialize the object */
2498 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,
2499 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2500 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2501 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2502 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2503 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2504 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2506 /* Save away the information */
2507 object->OriginalParms = *pLight;
2509 switch (pLight->Type) {
2510 case WINED3DLIGHT_POINT:
2512 object->lightPosn[0] = pLight->Position.x;
2513 object->lightPosn[1] = pLight->Position.y;
2514 object->lightPosn[2] = pLight->Position.z;
2515 object->lightPosn[3] = 1.0f;
2516 object->cutoff = 180.0f;
2520 case WINED3DLIGHT_DIRECTIONAL:
2522 object->lightPosn[0] = -pLight->Direction.x;
2523 object->lightPosn[1] = -pLight->Direction.y;
2524 object->lightPosn[2] = -pLight->Direction.z;
2525 object->lightPosn[3] = 0.0f;
2526 object->exponent = 0.0f;
2527 object->cutoff = 180.0f;
2530 case WINED3DLIGHT_SPOT:
2532 object->lightPosn[0] = pLight->Position.x;
2533 object->lightPosn[1] = pLight->Position.y;
2534 object->lightPosn[2] = pLight->Position.z;
2535 object->lightPosn[3] = 1.0f;
2538 object->lightDirn[0] = pLight->Direction.x;
2539 object->lightDirn[1] = pLight->Direction.y;
2540 object->lightDirn[2] = pLight->Direction.z;
2541 object->lightDirn[3] = 1.0f;
2544 * opengl-ish and d3d-ish spot lights use too different models for the
2545 * light "intensity" as a function of the angle towards the main light direction,
2546 * so we only can approximate very roughly.
2547 * however spot lights are rather rarely used in games (if ever used at all).
2548 * furthermore if still used, probably nobody pays attention to such details.
2550 if (pLight->Falloff == 0) {
2551 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2552 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2553 * will always be 1.0 for both of them, and we don't have to care for the
2554 * rest of the rather complex calculation
2556 object->exponent = 0.0f;
2558 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2559 if (rho < 0.0001f) rho = 0.0001f;
2560 object->exponent = -0.3f/logf(cosf(rho/2));
2562 if (object->exponent > 128.0f)
2564 object->exponent = 128.0f;
2566 object->cutoff = pLight->Phi*90/M_PI;
2572 FIXME("Unrecognized light type %d\n", pLight->Type);
2575 /* Update the live definitions if the light is currently assigned a glIndex */
2576 if (object->glIndex != -1 && !This->isRecordingState) {
2577 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2582 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2584 struct wined3d_light_info *lightInfo = NULL;
2585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2586 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2588 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2590 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2592 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2593 if(lightInfo->OriginalIndex == Index) break;
2597 if (lightInfo == NULL) {
2598 TRACE("Light information requested but light not defined\n");
2599 return WINED3DERR_INVALIDCALL;
2602 *pLight = lightInfo->OriginalParms;
2607 * Get / Set Light Enable
2608 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2610 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2612 struct wined3d_light_info *lightInfo = NULL;
2613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2614 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2616 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2618 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2620 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2621 if(lightInfo->OriginalIndex == Index) break;
2624 TRACE("Found light: %p\n", lightInfo);
2626 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2627 if (lightInfo == NULL) {
2629 TRACE("Light enabled requested but light not defined, so defining one!\n");
2630 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2632 /* Search for it again! Should be fairly quick as near head of list */
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 if (lightInfo == NULL) {
2640 FIXME("Adding default lights has failed dismally\n");
2641 return WINED3DERR_INVALIDCALL;
2646 if(lightInfo->glIndex != -1) {
2647 if(!This->isRecordingState) {
2648 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2651 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2652 lightInfo->glIndex = -1;
2654 TRACE("Light already disabled, nothing to do\n");
2656 lightInfo->enabled = FALSE;
2658 lightInfo->enabled = TRUE;
2659 if (lightInfo->glIndex != -1) {
2661 TRACE("Nothing to do as light was enabled\n");
2664 /* Find a free gl light */
2665 for(i = 0; i < This->maxConcurrentLights; i++) {
2666 if(This->updateStateBlock->activeLights[i] == NULL) {
2667 This->updateStateBlock->activeLights[i] = lightInfo;
2668 lightInfo->glIndex = i;
2672 if(lightInfo->glIndex == -1) {
2673 /* Our tests show that Windows returns D3D_OK in this situation, even with
2674 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2675 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2676 * as well for those lights.
2678 * TODO: Test how this affects rendering
2680 WARN("Too many concurrently active lights\n");
2684 /* i == lightInfo->glIndex */
2685 if(!This->isRecordingState) {
2686 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2694 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2696 struct wined3d_light_info *lightInfo = NULL;
2697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2699 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2700 TRACE("(%p) : for idx(%d)\n", This, Index);
2702 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2704 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2705 if(lightInfo->OriginalIndex == Index) break;
2709 if (lightInfo == NULL) {
2710 TRACE("Light enabled state requested but light not defined\n");
2711 return WINED3DERR_INVALIDCALL;
2713 /* true is 128 according to SetLightEnable */
2714 *pEnable = lightInfo->enabled ? 128 : 0;
2719 * Get / Set Clip Planes
2721 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2723 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2725 /* Validate Index */
2726 if (Index >= This->adapter->gl_info.max_clipplanes)
2728 TRACE("Application has requested clipplane this device doesn't support\n");
2729 return WINED3DERR_INVALIDCALL;
2732 This->updateStateBlock->changed.clipplane |= 1 << Index;
2734 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2735 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2736 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2737 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2738 TRACE("Application is setting old values over, nothing to do\n");
2742 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2743 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2744 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2745 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2747 /* Handle recording of state blocks */
2748 if (This->isRecordingState) {
2749 TRACE("Recording... not performing anything\n");
2753 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2758 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2760 TRACE("(%p) : for idx %d\n", This, Index);
2762 /* Validate Index */
2763 if (Index >= This->adapter->gl_info.max_clipplanes)
2765 TRACE("Application has requested clipplane this device doesn't support\n");
2766 return WINED3DERR_INVALIDCALL;
2769 pPlane[0] = This->stateBlock->clipplane[Index][0];
2770 pPlane[1] = This->stateBlock->clipplane[Index][1];
2771 pPlane[2] = This->stateBlock->clipplane[Index][2];
2772 pPlane[3] = This->stateBlock->clipplane[Index][3];
2777 * Get / Set Clip Plane Status
2778 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2780 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2782 FIXME("(%p) : stub\n", This);
2783 if (NULL == pClipStatus) {
2784 return WINED3DERR_INVALIDCALL;
2786 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2787 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2791 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2793 FIXME("(%p) : stub\n", This);
2794 if (NULL == pClipStatus) {
2795 return WINED3DERR_INVALIDCALL;
2797 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2798 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2803 * Get / Set Material
2805 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2808 This->updateStateBlock->changed.material = TRUE;
2809 This->updateStateBlock->material = *pMaterial;
2811 /* Handle recording of state blocks */
2812 if (This->isRecordingState) {
2813 TRACE("Recording... not performing anything\n");
2817 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2821 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2823 *pMaterial = This->updateStateBlock->material;
2824 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2825 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2826 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2827 pMaterial->Ambient.b, pMaterial->Ambient.a);
2828 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2829 pMaterial->Specular.b, pMaterial->Specular.a);
2830 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2831 pMaterial->Emissive.b, pMaterial->Emissive.a);
2832 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2840 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2841 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2844 IWineD3DBuffer *oldIdxs;
2846 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2847 oldIdxs = This->updateStateBlock->pIndexData;
2849 This->updateStateBlock->changed.indices = TRUE;
2850 This->updateStateBlock->pIndexData = pIndexData;
2851 This->updateStateBlock->IndexFmt = fmt;
2853 /* Handle recording of state blocks */
2854 if (This->isRecordingState) {
2855 TRACE("Recording... not performing anything\n");
2856 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2857 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2861 if(oldIdxs != pIndexData) {
2862 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2864 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2865 IWineD3DBuffer_AddRef(pIndexData);
2868 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2869 IWineD3DBuffer_Release(oldIdxs);
2876 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2880 *ppIndexData = This->stateBlock->pIndexData;
2882 /* up ref count on ppindexdata */
2884 IWineD3DBuffer_AddRef(*ppIndexData);
2885 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2887 TRACE("(%p) No index data set\n", This);
2889 TRACE("Returning %p\n", *ppIndexData);
2894 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2895 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2897 TRACE("(%p)->(%d)\n", This, BaseIndex);
2899 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2900 TRACE("Application is setting the old value over, nothing to do\n");
2904 This->updateStateBlock->baseVertexIndex = BaseIndex;
2906 if (This->isRecordingState) {
2907 TRACE("Recording... not performing anything\n");
2910 /* The base vertex index affects the stream sources */
2911 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2915 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2917 TRACE("(%p) : base_index %p\n", This, base_index);
2919 *base_index = This->stateBlock->baseVertexIndex;
2921 TRACE("Returning %u\n", *base_index);
2927 * Get / Set Viewports
2929 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2932 TRACE("(%p)\n", This);
2933 This->updateStateBlock->changed.viewport = TRUE;
2934 This->updateStateBlock->viewport = *pViewport;
2936 /* Handle recording of state blocks */
2937 if (This->isRecordingState) {
2938 TRACE("Recording... not performing anything\n");
2942 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2943 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2945 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2950 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2952 TRACE("(%p)\n", This);
2953 *pViewport = This->stateBlock->viewport;
2958 * Get / Set Render States
2959 * TODO: Verify against dx9 definitions
2961 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2964 DWORD oldValue = This->stateBlock->renderState[State];
2966 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2968 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2969 This->updateStateBlock->renderState[State] = Value;
2971 /* Handle recording of state blocks */
2972 if (This->isRecordingState) {
2973 TRACE("Recording... not performing anything\n");
2977 /* Compared here and not before the assignment to allow proper stateblock recording */
2978 if(Value == oldValue) {
2979 TRACE("Application is setting the old value over, nothing to do\n");
2981 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2987 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2989 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2990 *pValue = This->stateBlock->renderState[State];
2995 * Get / Set Sampler States
2996 * TODO: Verify against dx9 definitions
2999 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3003 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3004 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3006 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3007 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3010 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3011 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3012 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3015 * SetSampler is designed to allow for more than the standard up to 8 textures
3016 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3017 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3019 * http://developer.nvidia.com/object/General_FAQ.html#t6
3021 * There are two new settings for GForce
3023 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3024 * and the texture one:
3025 * GL_MAX_TEXTURE_COORDS_ARB.
3026 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3029 oldValue = This->stateBlock->samplerState[Sampler][Type];
3030 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3031 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3033 /* Handle recording of state blocks */
3034 if (This->isRecordingState) {
3035 TRACE("Recording... not performing anything\n");
3039 if(oldValue == Value) {
3040 TRACE("Application is setting the old value over, nothing to do\n");
3044 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3049 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3052 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3053 This, Sampler, debug_d3dsamplerstate(Type), Type);
3055 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3056 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3059 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3060 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3061 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3063 *Value = This->stateBlock->samplerState[Sampler][Type];
3064 TRACE("(%p) : Returning %#x\n", This, *Value);
3069 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3072 This->updateStateBlock->changed.scissorRect = TRUE;
3073 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3074 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3077 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3079 if(This->isRecordingState) {
3080 TRACE("Recording... not performing anything\n");
3084 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3089 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3092 *pRect = This->updateStateBlock->scissorRect;
3093 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3097 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3098 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3099 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3101 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3103 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3104 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3106 This->updateStateBlock->vertexDecl = pDecl;
3107 This->updateStateBlock->changed.vertexDecl = TRUE;
3109 if (This->isRecordingState) {
3110 TRACE("Recording... not performing anything\n");
3112 } else if(pDecl == oldDecl) {
3113 /* Checked after the assignment to allow proper stateblock recording */
3114 TRACE("Application is setting the old declaration over, nothing to do\n");
3118 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3122 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3125 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3127 *ppDecl = This->stateBlock->vertexDecl;
3128 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3132 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3133 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3134 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3136 This->updateStateBlock->vertexShader = pShader;
3137 This->updateStateBlock->changed.vertexShader = TRUE;
3139 if (This->isRecordingState) {
3140 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3141 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3142 TRACE("Recording... not performing anything\n");
3144 } else if(oldShader == pShader) {
3145 /* Checked here to allow proper stateblock recording */
3146 TRACE("App is setting the old shader over, nothing to do\n");
3150 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3151 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3152 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3154 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3159 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3162 if (NULL == ppShader) {
3163 return WINED3DERR_INVALIDCALL;
3165 *ppShader = This->stateBlock->vertexShader;
3166 if( NULL != *ppShader)
3167 IWineD3DVertexShader_AddRef(*ppShader);
3169 TRACE("(%p) : returning %p\n", This, *ppShader);
3173 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3174 IWineD3DDevice *iface,
3176 CONST BOOL *srcData,
3179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3180 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3182 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3183 iface, srcData, start, count);
3185 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3187 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3188 for (i = 0; i < cnt; i++)
3189 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3191 for (i = start; i < cnt + start; ++i) {
3192 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3195 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3200 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3201 IWineD3DDevice *iface,
3206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3207 int cnt = min(count, MAX_CONST_B - start);
3209 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3210 iface, dstData, start, count);
3212 if (dstData == NULL || cnt < 0)
3213 return WINED3DERR_INVALIDCALL;
3215 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3219 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3220 IWineD3DDevice *iface,
3225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3226 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3228 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3229 iface, srcData, start, count);
3231 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3233 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3234 for (i = 0; i < cnt; i++)
3235 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3236 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3238 for (i = start; i < cnt + start; ++i) {
3239 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3242 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3247 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3248 IWineD3DDevice *iface,
3253 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3254 int cnt = min(count, MAX_CONST_I - start);
3256 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3257 iface, dstData, start, count);
3259 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3260 return WINED3DERR_INVALIDCALL;
3262 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3266 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3267 IWineD3DDevice *iface,
3269 CONST float *srcData,
3272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3275 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3276 iface, srcData, start, count);
3278 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3279 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3280 return WINED3DERR_INVALIDCALL;
3282 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3284 for (i = 0; i < count; i++)
3285 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3286 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3289 if (!This->isRecordingState)
3291 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3292 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3295 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3296 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3301 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3302 IWineD3DDevice *iface,
3307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3308 int cnt = min(count, This->d3d_vshader_constantF - start);
3310 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3311 iface, dstData, start, count);
3313 if (dstData == NULL || cnt < 0)
3314 return WINED3DERR_INVALIDCALL;
3316 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3320 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3322 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3324 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3328 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3330 DWORD i = This->rev_tex_unit_map[unit];
3331 DWORD j = This->texUnitMap[stage];
3333 This->texUnitMap[stage] = unit;
3334 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3336 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3339 This->rev_tex_unit_map[unit] = stage;
3340 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3342 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3346 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3349 This->fixed_function_usage_map = 0;
3350 for (i = 0; i < MAX_TEXTURES; ++i) {
3351 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3352 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3353 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3354 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3355 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3356 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3357 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3358 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3360 if (color_op == WINED3DTOP_DISABLE) {
3361 /* Not used, and disable higher stages */
3365 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3366 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3367 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3368 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3369 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3370 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3371 This->fixed_function_usage_map |= (1 << i);
3374 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3375 This->fixed_function_usage_map |= (1 << (i + 1));
3380 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3381 unsigned int i, tex;
3384 device_update_fixed_function_usage_map(This);
3385 ffu_map = This->fixed_function_usage_map;
3387 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3388 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3389 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3391 if (!(ffu_map & 1)) continue;
3393 if (This->texUnitMap[i] != i) {
3394 device_map_stage(This, i, i);
3395 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3396 markTextureStagesDirty(This, i);
3402 /* Now work out the mapping */
3404 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3406 if (!(ffu_map & 1)) continue;
3408 if (This->texUnitMap[i] != tex) {
3409 device_map_stage(This, i, tex);
3410 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3411 markTextureStagesDirty(This, i);
3418 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3419 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3420 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3423 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3424 if (sampler_type[i] && This->texUnitMap[i] != i)
3426 device_map_stage(This, i, i);
3427 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3428 if (i < MAX_TEXTURES) {
3429 markTextureStagesDirty(This, i);
3435 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3436 const DWORD *vshader_sampler_tokens, DWORD unit)
3438 DWORD current_mapping = This->rev_tex_unit_map[unit];
3440 /* Not currently used */
3441 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3443 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3444 /* Used by a fragment sampler */
3446 if (!pshader_sampler_tokens) {
3447 /* No pixel shader, check fixed function */
3448 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3451 /* Pixel shader, check the shader's sampler map */
3452 return !pshader_sampler_tokens[current_mapping];
3455 /* Used by a vertex sampler */
3456 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3459 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3460 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3461 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3462 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3463 int start = min(MAX_COMBINED_SAMPLERS, This->adapter->gl_info.max_combined_samplers) - 1;
3467 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3469 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3470 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3471 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3474 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3475 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3476 if (vshader_sampler_type[i])
3478 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3480 /* Already mapped somewhere */
3484 while (start >= 0) {
3485 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3487 device_map_stage(This, vsampler_idx, start);
3488 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3500 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3501 BOOL vs = use_vs(This->stateBlock);
3502 BOOL ps = use_ps(This->stateBlock);
3505 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3506 * that would be really messy and require shader recompilation
3507 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3508 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3511 device_map_psamplers(This);
3513 device_map_fixed_function_samplers(This);
3517 device_map_vsamplers(This, ps);
3521 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3523 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3524 This->updateStateBlock->pixelShader = pShader;
3525 This->updateStateBlock->changed.pixelShader = TRUE;
3527 /* Handle recording of state blocks */
3528 if (This->isRecordingState) {
3529 TRACE("Recording... not performing anything\n");
3532 if (This->isRecordingState) {
3533 TRACE("Recording... not performing anything\n");
3534 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3535 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3539 if(pShader == oldShader) {
3540 TRACE("App is setting the old pixel shader over, nothing to do\n");
3544 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3545 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3547 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3548 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3553 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3556 if (NULL == ppShader) {
3557 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3558 return WINED3DERR_INVALIDCALL;
3561 *ppShader = This->stateBlock->pixelShader;
3562 if (NULL != *ppShader) {
3563 IWineD3DPixelShader_AddRef(*ppShader);
3565 TRACE("(%p) : returning %p\n", This, *ppShader);
3569 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3570 IWineD3DDevice *iface,
3572 CONST BOOL *srcData,
3575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3576 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3578 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3579 iface, srcData, start, count);
3581 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3583 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3584 for (i = 0; i < cnt; i++)
3585 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3587 for (i = start; i < cnt + start; ++i) {
3588 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3591 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3596 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3597 IWineD3DDevice *iface,
3602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3603 int cnt = min(count, MAX_CONST_B - start);
3605 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3606 iface, dstData, start, count);
3608 if (dstData == NULL || cnt < 0)
3609 return WINED3DERR_INVALIDCALL;
3611 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3615 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3616 IWineD3DDevice *iface,
3621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3622 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3624 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3625 iface, srcData, start, count);
3627 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3629 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3630 for (i = 0; i < cnt; i++)
3631 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3632 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3634 for (i = start; i < cnt + start; ++i) {
3635 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3638 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3643 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3644 IWineD3DDevice *iface,
3649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3650 int cnt = min(count, MAX_CONST_I - start);
3652 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3653 iface, dstData, start, count);
3655 if (dstData == NULL || cnt < 0)
3656 return WINED3DERR_INVALIDCALL;
3658 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3662 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3663 IWineD3DDevice *iface,
3665 CONST float *srcData,
3668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3671 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3672 iface, srcData, start, count);
3674 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3675 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3676 return WINED3DERR_INVALIDCALL;
3678 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3680 for (i = 0; i < count; i++)
3681 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3682 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3685 if (!This->isRecordingState)
3687 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3688 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3691 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3692 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3697 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3698 IWineD3DDevice *iface,
3703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3704 int cnt = min(count, This->d3d_pshader_constantF - start);
3706 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3707 iface, dstData, start, count);
3709 if (dstData == NULL || cnt < 0)
3710 return WINED3DERR_INVALIDCALL;
3712 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3716 /* Context activation is done by the caller. */
3717 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3718 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3719 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3722 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3725 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3729 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3731 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3734 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3736 ERR("Source has no position mask\n");
3737 return WINED3DERR_INVALIDCALL;
3740 /* We might access VBOs from this code, so hold the lock */
3743 if (dest->resource.allocatedMemory == NULL) {
3744 buffer_get_sysmem(dest);
3747 /* Get a pointer into the destination vbo(create one if none exists) and
3748 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3750 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
3752 dest->flags |= WINED3D_BUFFER_CREATEBO;
3753 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3756 if (dest->buffer_object)
3758 unsigned char extrabytes = 0;
3759 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3760 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3761 * this may write 4 extra bytes beyond the area that should be written
3763 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3764 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3765 if(!dest_conv_addr) {
3766 ERR("Out of memory\n");
3767 /* Continue without storing converted vertices */
3769 dest_conv = dest_conv_addr;
3773 * a) WINED3DRS_CLIPPING is enabled
3774 * b) WINED3DVOP_CLIP is passed
3776 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3777 static BOOL warned = FALSE;
3779 * The clipping code is not quite correct. Some things need
3780 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3781 * so disable clipping for now.
3782 * (The graphics in Half-Life are broken, and my processvertices
3783 * test crashes with IDirect3DDevice3)
3789 FIXME("Clipping is broken and disabled for now\n");
3791 } else doClip = FALSE;
3792 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3794 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3797 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3798 WINED3DTS_PROJECTION,
3800 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3801 WINED3DTS_WORLDMATRIX(0),
3804 TRACE("View mat:\n");
3805 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);
3806 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);
3807 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);
3808 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);
3810 TRACE("Proj mat:\n");
3811 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);
3812 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);
3813 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);
3814 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);
3816 TRACE("World mat:\n");
3817 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);
3818 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);
3819 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);
3820 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);
3822 /* Get the viewport */
3823 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3824 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3825 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3827 multiply_matrix(&mat,&view_mat,&world_mat);
3828 multiply_matrix(&mat,&proj_mat,&mat);
3830 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3832 for (i = 0; i < dwCount; i+= 1) {
3833 unsigned int tex_index;
3835 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3836 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3837 /* The position first */
3838 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3839 const float *p = (const float *)(element->data + i * element->stride);
3841 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3843 /* Multiplication with world, view and projection matrix */
3844 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);
3845 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);
3846 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);
3847 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);
3849 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3851 /* WARNING: The following things are taken from d3d7 and were not yet checked
3852 * against d3d8 or d3d9!
3855 /* Clipping conditions: From msdn
3857 * A vertex is clipped if it does not match the following requirements
3861 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3863 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3864 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3869 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3870 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3873 /* "Normal" viewport transformation (not clipped)
3874 * 1) The values are divided by rhw
3875 * 2) The y axis is negative, so multiply it with -1
3876 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3877 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3878 * 4) Multiply x with Width/2 and add Width/2
3879 * 5) The same for the height
3880 * 6) Add the viewpoint X and Y to the 2D coordinates and
3881 * The minimum Z value to z
3882 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3884 * Well, basically it's simply a linear transformation into viewport
3896 z *= vp.MaxZ - vp.MinZ;
3898 x += vp.Width / 2 + vp.X;
3899 y += vp.Height / 2 + vp.Y;
3904 /* That vertex got clipped
3905 * Contrary to OpenGL it is not dropped completely, it just
3906 * undergoes a different calculation.
3908 TRACE("Vertex got clipped\n");
3915 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3916 * outside of the main vertex buffer memory. That needs some more
3921 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3924 ( (float *) dest_ptr)[0] = x;
3925 ( (float *) dest_ptr)[1] = y;
3926 ( (float *) dest_ptr)[2] = z;
3927 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3929 dest_ptr += 3 * sizeof(float);
3931 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3932 dest_ptr += sizeof(float);
3937 ( (float *) dest_conv)[0] = x * w;
3938 ( (float *) dest_conv)[1] = y * w;
3939 ( (float *) dest_conv)[2] = z * w;
3940 ( (float *) dest_conv)[3] = w;
3942 dest_conv += 3 * sizeof(float);
3944 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3945 dest_conv += sizeof(float);
3949 if (DestFVF & WINED3DFVF_PSIZE) {
3950 dest_ptr += sizeof(DWORD);
3951 if(dest_conv) dest_conv += sizeof(DWORD);
3953 if (DestFVF & WINED3DFVF_NORMAL) {
3954 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3955 const float *normal = (const float *)(element->data + i * element->stride);
3956 /* AFAIK this should go into the lighting information */
3957 FIXME("Didn't expect the destination to have a normal\n");
3958 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3960 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3964 if (DestFVF & WINED3DFVF_DIFFUSE) {
3965 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3966 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3967 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3969 static BOOL warned = FALSE;
3972 ERR("No diffuse color in source, but destination has one\n");
3976 *( (DWORD *) dest_ptr) = 0xffffffff;
3977 dest_ptr += sizeof(DWORD);
3980 *( (DWORD *) dest_conv) = 0xffffffff;
3981 dest_conv += sizeof(DWORD);
3985 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3987 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3988 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3989 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3990 dest_conv += sizeof(DWORD);
3995 if (DestFVF & WINED3DFVF_SPECULAR)
3997 /* What's the color value in the feedback buffer? */
3998 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3999 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4000 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4002 static BOOL warned = FALSE;
4005 ERR("No specular color in source, but destination has one\n");
4009 *( (DWORD *) dest_ptr) = 0xFF000000;
4010 dest_ptr += sizeof(DWORD);
4013 *( (DWORD *) dest_conv) = 0xFF000000;
4014 dest_conv += sizeof(DWORD);
4018 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4020 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4021 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4022 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4023 dest_conv += sizeof(DWORD);
4028 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4029 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4030 const float *tex_coord = (const float *)(element->data + i * element->stride);
4031 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4033 ERR("No source texture, but destination requests one\n");
4034 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4035 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4038 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4040 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4047 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4048 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4049 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4050 dwCount * get_flexible_vertex_size(DestFVF),
4052 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4053 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4060 #undef copy_and_next
4062 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4063 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4067 struct wined3d_stream_info stream_info;
4068 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4069 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4072 ERR("Output vertex declaration not implemented yet\n");
4075 /* Need any context to write to the vbo. */
4076 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4078 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4079 * control the streamIsUP flag, thus restore it afterwards.
4081 This->stateBlock->streamIsUP = FALSE;
4082 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4083 This->stateBlock->streamIsUP = streamWasUP;
4085 if(vbo || SrcStartIndex) {
4087 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4088 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4090 * Also get the start index in, but only loop over all elements if there's something to add at all.
4092 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4094 struct wined3d_stream_info_element *e;
4096 if (!(stream_info.use_map & (1 << i))) continue;
4098 e = &stream_info.elements[i];
4099 if (e->buffer_object)
4101 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4102 e->buffer_object = 0;
4103 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4105 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4106 vb->buffer_object = 0;
4109 if (e->data) e->data += e->stride * SrcStartIndex;
4113 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4114 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4118 * Get / Set Texture Stage States
4119 * TODO: Verify against dx9 definitions
4121 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4123 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4125 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4127 if (Stage >= MAX_TEXTURES) {
4128 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4132 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4133 This->updateStateBlock->textureState[Stage][Type] = Value;
4135 if (This->isRecordingState) {
4136 TRACE("Recording... not performing anything\n");
4140 /* Checked after the assignments to allow proper stateblock recording */
4141 if(oldValue == Value) {
4142 TRACE("App is setting the old value over, nothing to do\n");
4146 if(Stage > This->stateBlock->lowest_disabled_stage &&
4147 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4148 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4149 * Changes in other states are important on disabled stages too
4154 if(Type == WINED3DTSS_COLOROP) {
4157 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4158 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4159 * they have to be disabled
4161 * The current stage is dirtified below.
4163 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4164 TRACE("Additionally dirtifying stage %u\n", i);
4165 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4167 This->stateBlock->lowest_disabled_stage = Stage;
4168 TRACE("New lowest disabled: %u\n", Stage);
4169 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4170 /* Previously disabled stage enabled. Stages above it may need enabling
4171 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4172 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4174 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4177 for (i = Stage + 1; i < This->adapter->gl_info.max_texture_stages; ++i)
4179 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4182 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4183 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4185 This->stateBlock->lowest_disabled_stage = i;
4186 TRACE("New lowest disabled: %u\n", i);
4190 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4195 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4197 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4198 *pValue = This->updateStateBlock->textureState[Stage][Type];
4205 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4206 DWORD stage, IWineD3DBaseTexture *texture)
4208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4209 IWineD3DBaseTexture *prev;
4211 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4213 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4214 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4216 /* Windows accepts overflowing this array... we do not. */
4217 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4219 WARN("Ignoring invalid stage %u.\n", stage);
4223 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4224 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4226 WARN("Rejecting attempt to set scratch texture.\n");
4227 return WINED3DERR_INVALIDCALL;
4230 This->updateStateBlock->changed.textures |= 1 << stage;
4232 prev = This->updateStateBlock->textures[stage];
4233 TRACE("Previous texture %p.\n", prev);
4235 if (texture == prev)
4237 TRACE("App is setting the same texture again, nothing to do.\n");
4241 TRACE("Setting new texture to %p.\n", texture);
4242 This->updateStateBlock->textures[stage] = texture;
4244 if (This->isRecordingState)
4246 TRACE("Recording... not performing anything\n");
4248 if (texture) IWineD3DBaseTexture_AddRef(texture);
4249 if (prev) IWineD3DBaseTexture_Release(prev);
4256 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4257 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4258 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4260 IWineD3DBaseTexture_AddRef(texture);
4262 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4267 if (!prev && stage < MAX_TEXTURES)
4269 /* The source arguments for color and alpha ops have different
4270 * meanings when a NULL texture is bound, so the COLOROP and
4271 * ALPHAOP have to be dirtified. */
4272 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4273 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4276 if (bind_count == 1) t->baseTexture.sampler = stage;
4281 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4282 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4284 IWineD3DBaseTexture_Release(prev);
4286 if (!texture && stage < MAX_TEXTURES)
4288 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4289 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4292 if (bind_count && t->baseTexture.sampler == stage)
4296 /* Search for other stages the texture is bound to. Shouldn't
4297 * happen if applications bind textures to a single stage only. */
4298 TRACE("Searching for other stages the texture is bound to.\n");
4299 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4301 if (This->updateStateBlock->textures[i] == prev)
4303 TRACE("Texture is also bound to stage %u.\n", i);
4304 t->baseTexture.sampler = i;
4311 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4316 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4319 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4321 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4322 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4325 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4326 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4327 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4330 *ppTexture=This->stateBlock->textures[Stage];
4332 IWineD3DBaseTexture_AddRef(*ppTexture);
4334 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4342 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4343 IWineD3DSurface **ppBackBuffer) {
4344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4345 IWineD3DSwapChain *swapChain;
4348 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4350 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4351 if (hr == WINED3D_OK) {
4352 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4353 IWineD3DSwapChain_Release(swapChain);
4355 *ppBackBuffer = NULL;
4360 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4362 WARN("(%p) : stub, calling idirect3d for now\n", This);
4363 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4366 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4368 IWineD3DSwapChain *swapChain;
4371 if(iSwapChain > 0) {
4372 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4373 if (hr == WINED3D_OK) {
4374 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4375 IWineD3DSwapChain_Release(swapChain);
4377 FIXME("(%p) Error getting display mode\n", This);
4380 /* Don't read the real display mode,
4381 but return the stored mode instead. X11 can't change the color
4382 depth, and some apps are pretty angry if they SetDisplayMode from
4383 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4385 Also don't relay to the swapchain because with ddraw it's possible
4386 that there isn't a swapchain at all */
4387 pMode->Width = This->ddraw_width;
4388 pMode->Height = This->ddraw_height;
4389 pMode->Format = This->ddraw_format;
4390 pMode->RefreshRate = 0;
4398 * Stateblock related functions
4401 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4403 IWineD3DStateBlock *stateblock;
4406 TRACE("(%p)\n", This);
4408 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4410 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4411 if (FAILED(hr)) return hr;
4413 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4414 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4415 This->isRecordingState = TRUE;
4417 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4422 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4424 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4426 if (!This->isRecordingState) {
4427 WARN("(%p) not recording! returning error\n", This);
4428 *ppStateBlock = NULL;
4429 return WINED3DERR_INVALIDCALL;
4432 stateblock_init_contained_states(object);
4434 *ppStateBlock = (IWineD3DStateBlock*) object;
4435 This->isRecordingState = FALSE;
4436 This->updateStateBlock = This->stateBlock;
4437 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4438 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4439 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4444 * Scene related functions
4446 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4447 /* At the moment we have no need for any functionality at the beginning
4449 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4450 TRACE("(%p)\n", This);
4453 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4454 return WINED3DERR_INVALIDCALL;
4456 This->inScene = TRUE;
4460 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4461 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4462 TRACE("(%p)\n", This);
4464 if(!This->inScene) {
4465 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4466 return WINED3DERR_INVALIDCALL;
4469 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4470 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4472 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4476 This->inScene = FALSE;
4480 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4481 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4482 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4484 IWineD3DSwapChain *swapChain = NULL;
4486 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4488 TRACE("(%p) Presenting the frame\n", This);
4490 for(i = 0 ; i < swapchains ; i ++) {
4492 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4493 TRACE("presentinng chain %d, %p\n", i, swapChain);
4494 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4495 IWineD3DSwapChain_Release(swapChain);
4501 /* Not called from the VTable (internal subroutine) */
4502 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4503 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4504 float Z, DWORD Stencil) {
4505 GLbitfield glMask = 0;
4507 WINED3DRECT curRect;
4509 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4510 UINT drawable_width, drawable_height;
4511 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4512 IWineD3DSwapChainImpl *swapchain = NULL;
4513 struct wined3d_context *context;
4515 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4516 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4517 * for the cleared parts, and the untouched parts.
4519 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4520 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4521 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4522 * checking all this if the dest surface is in the drawable anyway.
4524 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4526 if(vp->X != 0 || vp->Y != 0 ||
4527 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4528 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4531 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4532 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4533 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4534 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4535 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4538 if(Count > 0 && pRects && (
4539 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4540 pRects[0].x2 < target->currentDesc.Width ||
4541 pRects[0].y2 < target->currentDesc.Height)) {
4542 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4549 context = ActivateContext(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4551 target->get_drawable_size(context, &drawable_width, &drawable_height);
4555 /* Only set the values up once, as they are not changing */
4556 if (Flags & WINED3DCLEAR_STENCIL) {
4557 glClearStencil(Stencil);
4558 checkGLcall("glClearStencil");
4559 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4560 glStencilMask(0xFFFFFFFF);
4563 if (Flags & WINED3DCLEAR_ZBUFFER) {
4564 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4565 glDepthMask(GL_TRUE);
4567 checkGLcall("glClearDepth");
4568 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4569 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4571 if (vp->X != 0 || vp->Y != 0 ||
4572 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4573 surface_load_ds_location(This->stencilBufferTarget, context, location);
4575 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4576 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4577 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4578 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4579 surface_load_ds_location(This->stencilBufferTarget, context, location);
4581 else if (Count > 0 && pRects && (
4582 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4583 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4584 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4585 surface_load_ds_location(This->stencilBufferTarget, context, location);
4589 if (Flags & WINED3DCLEAR_TARGET) {
4590 TRACE("Clearing screen with glClear to color %x\n", Color);
4591 glClearColor(D3DCOLOR_R(Color),
4595 checkGLcall("glClearColor");
4597 /* Clear ALL colors! */
4598 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4599 glMask = glMask | GL_COLOR_BUFFER_BIT;
4602 vp_rect.left = vp->X;
4603 vp_rect.top = vp->Y;
4604 vp_rect.right = vp->X + vp->Width;
4605 vp_rect.bottom = vp->Y + vp->Height;
4606 if (!(Count > 0 && pRects)) {
4607 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4608 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4610 if (context->render_offscreen)
4612 glScissor(vp_rect.left, vp_rect.top,
4613 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4615 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4616 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4618 checkGLcall("glScissor");
4620 checkGLcall("glClear");
4622 /* Now process each rect in turn */
4623 for (i = 0; i < Count; i++) {
4624 /* Note gl uses lower left, width/height */
4625 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4626 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4627 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4629 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4630 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4631 curRect.x1, (target->currentDesc.Height - curRect.y2),
4632 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4634 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4635 * The rectangle is not cleared, no error is returned, but further rectanlges are
4636 * still cleared if they are valid
4638 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4639 TRACE("Rectangle with negative dimensions, ignoring\n");
4643 if (context->render_offscreen)
4645 glScissor(curRect.x1, curRect.y1,
4646 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4648 glScissor(curRect.x1, drawable_height - curRect.y2,
4649 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4651 checkGLcall("glScissor");
4654 checkGLcall("glClear");
4658 /* Restore the old values (why..?) */
4659 if (Flags & WINED3DCLEAR_STENCIL) {
4660 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4662 if (Flags & WINED3DCLEAR_TARGET) {
4663 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4664 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4665 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4666 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4667 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4669 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4670 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4672 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4674 if (Flags & WINED3DCLEAR_ZBUFFER) {
4675 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4676 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4677 surface_modify_ds_location(This->stencilBufferTarget, location);
4682 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
4683 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
4686 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
4692 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4693 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4695 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4697 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4698 Count, pRects, Flags, Color, Z, Stencil);
4700 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4701 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4702 /* TODO: What about depth stencil buffers without stencil bits? */
4703 return WINED3DERR_INVALIDCALL;
4706 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4713 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4714 WINED3DPRIMITIVETYPE primitive_type)
4716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4718 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4720 This->updateStateBlock->changed.primitive_type = TRUE;
4721 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4724 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4725 WINED3DPRIMITIVETYPE *primitive_type)
4727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4729 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4731 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4733 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4736 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4740 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4742 if(!This->stateBlock->vertexDecl) {
4743 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4744 return WINED3DERR_INVALIDCALL;
4747 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4748 if(This->stateBlock->streamIsUP) {
4749 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4750 This->stateBlock->streamIsUP = FALSE;
4753 if(This->stateBlock->loadBaseVertexIndex != 0) {
4754 This->stateBlock->loadBaseVertexIndex = 0;
4755 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4757 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4758 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4762 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4766 IWineD3DBuffer *pIB;
4769 pIB = This->stateBlock->pIndexData;
4771 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4772 * without an index buffer set. (The first time at least...)
4773 * D3D8 simply dies, but I doubt it can do much harm to return
4774 * D3DERR_INVALIDCALL there as well. */
4775 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4776 return WINED3DERR_INVALIDCALL;
4779 if(!This->stateBlock->vertexDecl) {
4780 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4781 return WINED3DERR_INVALIDCALL;
4784 if(This->stateBlock->streamIsUP) {
4785 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4786 This->stateBlock->streamIsUP = FALSE;
4788 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4790 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4792 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4798 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4799 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4800 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4803 drawPrimitive(iface, index_count, startIndex, idxStride,
4804 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4809 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4810 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4815 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4816 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4818 if(!This->stateBlock->vertexDecl) {
4819 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4820 return WINED3DERR_INVALIDCALL;
4823 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4824 vb = This->stateBlock->streamSource[0];
4825 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4826 if (vb) IWineD3DBuffer_Release(vb);
4827 This->stateBlock->streamOffset[0] = 0;
4828 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4829 This->stateBlock->streamIsUP = TRUE;
4830 This->stateBlock->loadBaseVertexIndex = 0;
4832 /* TODO: Only mark dirty if drawing from a different UP address */
4833 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4835 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4837 /* MSDN specifies stream zero settings must be set to NULL */
4838 This->stateBlock->streamStride[0] = 0;
4839 This->stateBlock->streamSource[0] = NULL;
4841 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4842 * the new stream sources or use UP drawing again
4847 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4848 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4849 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4856 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4857 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4859 if(!This->stateBlock->vertexDecl) {
4860 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4861 return WINED3DERR_INVALIDCALL;
4864 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4870 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4871 vb = This->stateBlock->streamSource[0];
4872 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4873 if (vb) IWineD3DBuffer_Release(vb);
4874 This->stateBlock->streamIsUP = TRUE;
4875 This->stateBlock->streamOffset[0] = 0;
4876 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4878 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4879 This->stateBlock->baseVertexIndex = 0;
4880 This->stateBlock->loadBaseVertexIndex = 0;
4881 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4882 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4883 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4885 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4887 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4888 This->stateBlock->streamSource[0] = NULL;
4889 This->stateBlock->streamStride[0] = 0;
4890 ib = This->stateBlock->pIndexData;
4892 IWineD3DBuffer_Release(ib);
4893 This->stateBlock->pIndexData = NULL;
4895 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4896 * SetStreamSource to specify a vertex buffer
4902 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4903 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4907 /* Mark the state dirty until we have nicer tracking
4908 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4911 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4912 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4913 This->stateBlock->baseVertexIndex = 0;
4914 This->up_strided = DrawPrimStrideData;
4915 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4916 This->up_strided = NULL;
4920 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4921 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4922 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4925 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4927 /* Mark the state dirty until we have nicer tracking
4928 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4931 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4932 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4933 This->stateBlock->streamIsUP = TRUE;
4934 This->stateBlock->baseVertexIndex = 0;
4935 This->up_strided = DrawPrimStrideData;
4936 drawPrimitive(iface, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData);
4937 This->up_strided = NULL;
4941 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
4942 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
4943 * not callable by the app directly no parameter validation checks are needed here.
4945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4946 WINED3DLOCKED_BOX src;
4947 WINED3DLOCKED_BOX dst;
4949 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
4951 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4952 * dirtification to improve loading performance.
4954 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4955 if(FAILED(hr)) return hr;
4956 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4958 IWineD3DVolume_UnlockBox(pSourceVolume);
4962 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4964 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4966 IWineD3DVolume_UnlockBox(pSourceVolume);
4968 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4973 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4974 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4976 unsigned int level_count, i;
4977 WINED3DRESOURCETYPE type;
4980 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4982 /* Verify that the source and destination textures are non-NULL. */
4983 if (!src_texture || !dst_texture)
4985 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4986 return WINED3DERR_INVALIDCALL;
4989 if (src_texture == dst_texture)
4991 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4992 return WINED3DERR_INVALIDCALL;
4995 /* Verify that the source and destination textures are the same type. */
4996 type = IWineD3DBaseTexture_GetType(src_texture);
4997 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4999 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5000 return WINED3DERR_INVALIDCALL;
5003 /* Check that both textures have the identical numbers of levels. */
5004 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
5005 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
5007 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5008 return WINED3DERR_INVALIDCALL;
5011 /* Make sure that the destination texture is loaded. */
5012 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
5014 /* Update every surface level of the texture. */
5017 case WINED3DRTYPE_TEXTURE:
5019 IWineD3DSurface *src_surface;
5020 IWineD3DSurface *dst_surface;
5022 for (i = 0; i < level_count; ++i)
5024 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
5025 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
5026 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5027 IWineD3DSurface_Release(dst_surface);
5028 IWineD3DSurface_Release(src_surface);
5031 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5038 case WINED3DRTYPE_CUBETEXTURE:
5040 IWineD3DSurface *src_surface;
5041 IWineD3DSurface *dst_surface;
5042 WINED3DCUBEMAP_FACES face;
5044 for (i = 0; i < level_count; ++i)
5046 /* Update each cube face. */
5047 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
5049 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
5050 face, i, &src_surface);
5051 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5052 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
5053 face, i, &dst_surface);
5054 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5055 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5056 IWineD3DSurface_Release(dst_surface);
5057 IWineD3DSurface_Release(src_surface);
5060 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5068 case WINED3DRTYPE_VOLUMETEXTURE:
5070 IWineD3DVolume *src_volume;
5071 IWineD3DVolume *dst_volume;
5073 for (i = 0; i < level_count; ++i)
5075 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5076 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5077 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5078 IWineD3DVolume_Release(dst_volume);
5079 IWineD3DVolume_Release(src_volume);
5082 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5090 FIXME("Unsupported texture type %#x.\n", type);
5091 return WINED3DERR_INVALIDCALL;
5097 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5098 IWineD3DSwapChain *swapChain;
5100 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5101 if(hr == WINED3D_OK) {
5102 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5103 IWineD3DSwapChain_Release(swapChain);
5108 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5110 IWineD3DBaseTextureImpl *texture;
5113 TRACE("(%p) : %p\n", This, pNumPasses);
5115 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5116 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5117 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5118 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5120 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5121 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5122 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5125 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5126 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5128 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5129 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5132 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5133 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5136 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5137 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5138 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5143 /* return a sensible default */
5146 TRACE("returning D3D_OK\n");
5150 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5154 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5156 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5157 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
5158 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
5160 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5165 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5169 PALETTEENTRY **palettes;
5171 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5173 if (PaletteNumber >= MAX_PALETTES) {
5174 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5175 return WINED3DERR_INVALIDCALL;
5178 if (PaletteNumber >= This->NumberOfPalettes) {
5179 NewSize = This->NumberOfPalettes;
5182 } while(PaletteNumber >= NewSize);
5183 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5185 ERR("Out of memory!\n");
5186 return E_OUTOFMEMORY;
5188 This->palettes = palettes;
5189 This->NumberOfPalettes = NewSize;
5192 if (!This->palettes[PaletteNumber]) {
5193 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5194 if (!This->palettes[PaletteNumber]) {
5195 ERR("Out of memory!\n");
5196 return E_OUTOFMEMORY;
5200 for (j = 0; j < 256; ++j) {
5201 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5202 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5203 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5204 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5206 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5207 TRACE("(%p) : returning\n", This);
5211 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5212 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5214 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5215 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5216 /* What happens in such situation isn't documented; Native seems to silently abort
5217 on such conditions. Return Invalid Call. */
5218 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5219 return WINED3DERR_INVALIDCALL;
5221 for (j = 0; j < 256; ++j) {
5222 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5223 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5224 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5225 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5227 TRACE("(%p) : returning\n", This);
5231 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5233 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5234 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5235 (tested with reference rasterizer). Return Invalid Call. */
5236 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5237 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5238 return WINED3DERR_INVALIDCALL;
5240 /*TODO: stateblocks */
5241 if (This->currentPalette != PaletteNumber) {
5242 This->currentPalette = PaletteNumber;
5243 dirtify_p8_texture_samplers(This);
5245 TRACE("(%p) : returning\n", This);
5249 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5251 if (PaletteNumber == NULL) {
5252 WARN("(%p) : returning Invalid Call\n", This);
5253 return WINED3DERR_INVALIDCALL;
5255 /*TODO: stateblocks */
5256 *PaletteNumber = This->currentPalette;
5257 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5261 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5266 FIXME("(%p) : stub\n", This);
5270 This->softwareVertexProcessing = bSoftware;
5275 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5280 FIXME("(%p) : stub\n", This);
5283 return This->softwareVertexProcessing;
5287 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5289 IWineD3DSwapChain *swapChain;
5292 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5294 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5295 if(hr == WINED3D_OK){
5296 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5297 IWineD3DSwapChain_Release(swapChain);
5299 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5305 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5308 if(nSegments != 0.0f) {
5311 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5318 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5323 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5329 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5331 /** TODO: remove casts to IWineD3DSurfaceImpl
5332 * NOTE: move code to surface to accomplish this
5333 ****************************************/
5334 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5335 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5336 int srcWidth, srcHeight;
5337 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5338 WINED3DFORMAT destFormat, srcFormat;
5340 int srcLeft, destLeft, destTop;
5341 WINED3DPOOL srcPool, destPool;
5343 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5344 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5348 CONVERT_TYPES convert = NO_CONVERSION;
5350 WINED3DSURFACE_DESC winedesc;
5352 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5354 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5355 srcSurfaceWidth = winedesc.width;
5356 srcSurfaceHeight = winedesc.height;
5357 srcPool = winedesc.pool;
5358 srcFormat = winedesc.format;
5360 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5361 destSurfaceWidth = winedesc.width;
5362 destSurfaceHeight = winedesc.height;
5363 destPool = winedesc.pool;
5364 destFormat = winedesc.format;
5365 destSize = winedesc.size;
5367 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5368 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5369 return WINED3DERR_INVALIDCALL;
5372 /* This call loads the opengl surface directly, instead of copying the surface to the
5373 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5374 * copy in sysmem and use regular surface loading.
5376 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5377 if(convert != NO_CONVERSION) {
5378 return IWineD3DSurface_BltFast(pDestinationSurface,
5379 pDestPoint ? pDestPoint->x : 0,
5380 pDestPoint ? pDestPoint->y : 0,
5381 pSourceSurface, pSourceRect, 0);
5384 if (destFormat == WINED3DFMT_UNKNOWN) {
5385 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5386 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5388 /* Get the update surface description */
5389 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5392 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
5395 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5396 checkGLcall("glActiveTextureARB");
5399 /* Make sure the surface is loaded and up to date */
5400 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5401 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5403 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5404 dst_format_desc = dst_impl->resource.format_desc;
5406 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5407 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5408 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5409 srcLeft = pSourceRect ? pSourceRect->left : 0;
5410 destLeft = pDestPoint ? pDestPoint->x : 0;
5411 destTop = pDestPoint ? pDestPoint->y : 0;
5414 /* This function doesn't support compressed textures
5415 the pitch is just bytesPerPixel * width */
5416 if(srcWidth != srcSurfaceWidth || srcLeft ){
5417 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5418 offset += srcLeft * src_format_desc->byte_count;
5419 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5421 /* TODO DXT formats */
5423 if(pSourceRect != NULL && pSourceRect->top != 0){
5424 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5426 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5427 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5428 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5431 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5433 /* need to lock the surface to get the data */
5434 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5439 /* TODO: Cube and volume support */
5441 /* not a whole row so we have to do it a line at a time */
5444 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5445 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5447 for (j = destTop; j < (srcHeight + destTop); ++j)
5449 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5450 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5454 } else { /* Full width, so just write out the whole texture */
5455 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5457 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5459 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5461 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5462 FIXME("Updating part of a compressed texture is not supported.\n");
5464 if (destFormat != srcFormat)
5466 FIXME("Updating mixed format compressed textures is not supported.\n");
5470 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5471 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5476 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5477 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5480 checkGLcall("glTexSubImage2D");
5484 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5485 sampler = This->rev_tex_unit_map[0];
5486 if (sampler != WINED3D_UNMAPPED_STAGE)
5488 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5494 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5496 struct WineD3DRectPatch *patch;
5497 GLenum old_primitive_type;
5501 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5503 if(!(Handle || pRectPatchInfo)) {
5504 /* TODO: Write a test for the return value, thus the FIXME */
5505 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5506 return WINED3DERR_INVALIDCALL;
5510 i = PATCHMAP_HASHFUNC(Handle);
5512 LIST_FOR_EACH(e, &This->patches[i]) {
5513 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5514 if(patch->Handle == Handle) {
5521 TRACE("Patch does not exist. Creating a new one\n");
5522 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5523 patch->Handle = Handle;
5524 list_add_head(&This->patches[i], &patch->entry);
5526 TRACE("Found existing patch %p\n", patch);
5529 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5530 * attributes we have to tesselate, read back, and draw. This needs a patch
5531 * management structure instance. Create one.
5533 * A possible improvement is to check if a vertex shader is used, and if not directly
5536 FIXME("Drawing an uncached patch. This is slow\n");
5537 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5540 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5541 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5542 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5544 TRACE("Tesselation density or patch info changed, retesselating\n");
5546 if(pRectPatchInfo) {
5547 patch->RectPatchInfo = *pRectPatchInfo;
5549 patch->numSegs[0] = pNumSegs[0];
5550 patch->numSegs[1] = pNumSegs[1];
5551 patch->numSegs[2] = pNumSegs[2];
5552 patch->numSegs[3] = pNumSegs[3];
5554 hr = tesselate_rectpatch(This, patch);
5556 WARN("Patch tesselation failed\n");
5558 /* Do not release the handle to store the params of the patch */
5560 HeapFree(GetProcessHeap(), 0, patch);
5566 This->currentPatch = patch;
5567 old_primitive_type = This->stateBlock->gl_primitive_type;
5568 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5569 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5570 This->stateBlock->gl_primitive_type = old_primitive_type;
5571 This->currentPatch = NULL;
5573 /* Destroy uncached patches */
5575 HeapFree(GetProcessHeap(), 0, patch->mem);
5576 HeapFree(GetProcessHeap(), 0, patch);
5581 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5583 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5584 FIXME("(%p) : Stub\n", This);
5588 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5591 struct WineD3DRectPatch *patch;
5593 TRACE("(%p) Handle(%d)\n", This, Handle);
5595 i = PATCHMAP_HASHFUNC(Handle);
5596 LIST_FOR_EACH(e, &This->patches[i]) {
5597 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5598 if(patch->Handle == Handle) {
5599 TRACE("Deleting patch %p\n", patch);
5600 list_remove(&patch->entry);
5601 HeapFree(GetProcessHeap(), 0, patch->mem);
5602 HeapFree(GetProcessHeap(), 0, patch);
5607 /* TODO: Write a test for the return value */
5608 FIXME("Attempt to destroy nonexistent patch\n");
5609 return WINED3DERR_INVALIDCALL;
5612 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5614 IWineD3DSwapChain *swapchain;
5616 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5617 if (SUCCEEDED(hr)) {
5618 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5625 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5626 const WINED3DRECT *rect, const float color[4])
5628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5629 struct wined3d_context *context;
5630 IWineD3DSwapChain *swapchain;
5632 swapchain = get_swapchain(surface);
5636 TRACE("Surface %p is onscreen\n", surface);
5638 context = ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
5640 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5641 buffer = surface_get_gl_buffer(surface, swapchain);
5642 glDrawBuffer(buffer);
5643 checkGLcall("glDrawBuffer()");
5645 TRACE("Surface %p is offscreen\n", surface);
5647 context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
5649 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5650 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5651 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5655 glEnable(GL_SCISSOR_TEST);
5657 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5659 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5660 rect->x2 - rect->x1, rect->y2 - rect->y1);
5662 checkGLcall("glScissor");
5663 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5665 glDisable(GL_SCISSOR_TEST);
5667 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5669 glDisable(GL_BLEND);
5670 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5672 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5673 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5675 glClearColor(color[0], color[1], color[2], color[3]);
5676 glClear(GL_COLOR_BUFFER_BIT);
5677 checkGLcall("glClear");
5679 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5680 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5681 glDrawBuffer(GL_BACK);
5682 checkGLcall("glDrawBuffer()");
5688 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5689 unsigned int r, g, b, a;
5692 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5693 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5694 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5697 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5699 a = (color & 0xff000000) >> 24;
5700 r = (color & 0x00ff0000) >> 16;
5701 g = (color & 0x0000ff00) >> 8;
5702 b = (color & 0x000000ff) >> 0;
5706 case WINED3DFMT_B5G6R5_UNORM:
5707 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5714 TRACE("Returning %08x\n", ret);
5717 case WINED3DFMT_B5G5R5X1_UNORM:
5718 case WINED3DFMT_B5G5R5A1_UNORM:
5727 TRACE("Returning %08x\n", ret);
5730 case WINED3DFMT_A8_UNORM:
5731 TRACE("Returning %08x\n", a);
5734 case WINED3DFMT_B4G4R4X4_UNORM:
5735 case WINED3DFMT_B4G4R4A4_UNORM:
5744 TRACE("Returning %08x\n", ret);
5747 case WINED3DFMT_B2G3R3_UNORM:
5754 TRACE("Returning %08x\n", ret);
5757 case WINED3DFMT_R8G8B8X8_UNORM:
5758 case WINED3DFMT_R8G8B8A8_UNORM:
5763 TRACE("Returning %08x\n", ret);
5766 case WINED3DFMT_B10G10R10A2_UNORM:
5768 r = (r * 1024) / 256;
5769 g = (g * 1024) / 256;
5770 b = (b * 1024) / 256;
5775 TRACE("Returning %08x\n", ret);
5778 case WINED3DFMT_R10G10B10A2_UNORM:
5780 r = (r * 1024) / 256;
5781 g = (g * 1024) / 256;
5782 b = (b * 1024) / 256;
5787 TRACE("Returning %08x\n", ret);
5791 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5796 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5798 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5800 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5802 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5803 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5804 return WINED3DERR_INVALIDCALL;
5807 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5808 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5809 color_fill_fbo(iface, pSurface, pRect, c);
5812 /* Just forward this to the DirectDraw blitting engine */
5813 memset(&BltFx, 0, sizeof(BltFx));
5814 BltFx.dwSize = sizeof(BltFx);
5815 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5816 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5817 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5821 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5822 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5824 IWineD3DResource *resource;
5825 IWineD3DSurface *surface;
5828 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5831 ERR("Failed to get resource, hr %#x\n", hr);
5835 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5837 FIXME("Only supported on surface resources\n");
5838 IWineD3DResource_Release(resource);
5842 surface = (IWineD3DSurface *)resource;
5844 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5846 color_fill_fbo(iface, surface, NULL, color);
5853 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5855 c = ((DWORD)(color[2] * 255.0f));
5856 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5857 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5858 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5860 /* Just forward this to the DirectDraw blitting engine */
5861 memset(&BltFx, 0, sizeof(BltFx));
5862 BltFx.dwSize = sizeof(BltFx);
5863 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5864 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5867 ERR("Blt failed, hr %#x\n", hr);
5871 IWineD3DResource_Release(resource);
5874 /* rendertarget and depth stencil functions */
5875 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5878 if (RenderTargetIndex >= This->adapter->gl_info.max_buffers)
5880 ERR("(%p) : Only %d render targets are supported.\n",
5881 This, This->adapter->gl_info.max_buffers);
5882 return WINED3DERR_INVALIDCALL;
5885 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5886 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5887 /* Note inc ref on returned surface */
5888 if(*ppRenderTarget != NULL)
5889 IWineD3DSurface_AddRef(*ppRenderTarget);
5893 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5895 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5896 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5897 IWineD3DSwapChainImpl *Swapchain;
5900 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5902 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5903 if(hr != WINED3D_OK) {
5904 ERR("Can't get the swapchain\n");
5908 /* Make sure to release the swapchain */
5909 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5911 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5912 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5913 return WINED3DERR_INVALIDCALL;
5915 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5916 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5917 return WINED3DERR_INVALIDCALL;
5920 if(Swapchain->frontBuffer != Front) {
5921 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5923 if(Swapchain->frontBuffer)
5925 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5926 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5928 Swapchain->frontBuffer = Front;
5930 if(Swapchain->frontBuffer) {
5931 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5932 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5936 if(Back && !Swapchain->backBuffer) {
5937 /* We need memory for the back buffer array - only one back buffer this way */
5938 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5939 if(!Swapchain->backBuffer) {
5940 ERR("Out of memory\n");
5941 return E_OUTOFMEMORY;
5945 if(Swapchain->backBuffer[0] != Back) {
5946 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5948 /* What to do about the context here in the case of multithreading? Not sure.
5949 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5951 WARN("No active context?\n");
5954 if(!Swapchain->backBuffer[0]) {
5955 /* GL was told to draw to the front buffer at creation,
5958 glDrawBuffer(GL_BACK);
5959 checkGLcall("glDrawBuffer(GL_BACK)");
5960 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5961 Swapchain->presentParms.BackBufferCount = 1;
5963 /* That makes problems - disable for now */
5964 /* glDrawBuffer(GL_FRONT); */
5965 checkGLcall("glDrawBuffer(GL_FRONT)");
5966 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5967 Swapchain->presentParms.BackBufferCount = 0;
5971 if(Swapchain->backBuffer[0])
5973 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5974 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5976 Swapchain->backBuffer[0] = Back;
5978 if(Swapchain->backBuffer[0]) {
5979 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5980 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
5982 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5983 Swapchain->backBuffer = NULL;
5991 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5992 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5993 *ppZStencilSurface = This->stencilBufferTarget;
5994 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5996 if(*ppZStencilSurface != NULL) {
5997 /* Note inc ref on returned surface */
5998 IWineD3DSurface_AddRef(*ppZStencilSurface);
6001 return WINED3DERR_NOTFOUND;
6005 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6006 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6009 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6010 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6011 const struct wined3d_gl_info *gl_info;
6012 struct wined3d_context *context;
6014 POINT offset = {0, 0};
6016 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6017 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6018 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6019 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6022 case WINED3DTEXF_LINEAR:
6023 gl_filter = GL_LINEAR;
6027 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6028 case WINED3DTEXF_NONE:
6029 case WINED3DTEXF_POINT:
6030 gl_filter = GL_NEAREST;
6034 /* Attach src surface to src fbo */
6035 src_swapchain = get_swapchain(src_surface);
6036 dst_swapchain = get_swapchain(dst_surface);
6038 if (src_swapchain) context = ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6039 else if (dst_swapchain) context = ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6040 else context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6042 gl_info = context->gl_info;
6044 if (src_swapchain) {
6045 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6047 TRACE("Source surface %p is onscreen\n", src_surface);
6048 /* Make sure the drawable is up to date. In the offscreen case
6049 * attach_surface_fbo() implicitly takes care of this. */
6050 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6052 if(buffer == GL_FRONT) {
6055 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6056 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6057 h = windowsize.bottom - windowsize.top;
6058 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6059 src_rect->y1 = offset.y + h - src_rect->y1;
6060 src_rect->y2 = offset.y + h - src_rect->y2;
6062 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6063 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6067 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
6068 glReadBuffer(buffer);
6069 checkGLcall("glReadBuffer()");
6071 TRACE("Source surface %p is offscreen\n", src_surface);
6073 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
6074 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
6075 glReadBuffer(GL_COLOR_ATTACHMENT0);
6076 checkGLcall("glReadBuffer()");
6077 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
6081 /* Attach dst surface to dst fbo */
6082 if (dst_swapchain) {
6083 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6085 TRACE("Destination surface %p is onscreen\n", dst_surface);
6086 /* Make sure the drawable is up to date. In the offscreen case
6087 * attach_surface_fbo() implicitly takes care of this. */
6088 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6090 if(buffer == GL_FRONT) {
6093 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6094 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6095 h = windowsize.bottom - windowsize.top;
6096 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6097 dst_rect->y1 = offset.y + h - dst_rect->y1;
6098 dst_rect->y2 = offset.y + h - dst_rect->y2;
6100 /* Screen coords = window coords, surface height = window height */
6101 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6102 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6106 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
6107 glDrawBuffer(buffer);
6108 checkGLcall("glDrawBuffer()");
6110 TRACE("Destination surface %p is offscreen\n", dst_surface);
6113 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
6114 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
6115 glDrawBuffer(GL_COLOR_ATTACHMENT0);
6116 checkGLcall("glDrawBuffer()");
6117 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
6119 glDisable(GL_SCISSOR_TEST);
6120 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6123 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6124 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
6125 checkGLcall("glBlitFramebuffer()");
6127 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6128 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
6129 checkGLcall("glBlitFramebuffer()");
6132 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6134 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6135 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6136 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6137 glDrawBuffer(GL_BACK);
6138 checkGLcall("glDrawBuffer()");
6143 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6145 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
6147 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6149 if (RenderTargetIndex >= This->adapter->gl_info.max_buffers)
6151 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6152 This, RenderTargetIndex, This->adapter->gl_info.max_buffers);
6153 return WINED3DERR_INVALIDCALL;
6156 /* MSDN says that null disables the render target
6157 but a device must always be associated with a render target
6158 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6160 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6161 FIXME("Trying to set render target 0 to NULL\n");
6162 return WINED3DERR_INVALIDCALL;
6164 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6165 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);
6166 return WINED3DERR_INVALIDCALL;
6169 /* If we are trying to set what we already have, don't bother */
6170 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6171 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6174 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6175 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6176 This->render_targets[RenderTargetIndex] = pRenderTarget;
6178 /* Render target 0 is special */
6179 if(RenderTargetIndex == 0 && dxVersion > 7) {
6180 /* Finally, reset the viewport and scissor rect as the MSDN states.
6181 * Tests show that stateblock recording is ignored, the change goes
6182 * directly into the primary stateblock.
6184 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6185 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6186 This->stateBlock->viewport.X = 0;
6187 This->stateBlock->viewport.Y = 0;
6188 This->stateBlock->viewport.MaxZ = 1.0f;
6189 This->stateBlock->viewport.MinZ = 0.0f;
6190 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6192 This->stateBlock->scissorRect.top = 0;
6193 This->stateBlock->scissorRect.left = 0;
6194 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
6195 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
6196 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6201 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6203 HRESULT hr = WINED3D_OK;
6204 IWineD3DSurface *tmp;
6206 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6208 if (pNewZStencil == This->stencilBufferTarget) {
6209 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6211 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6212 * depending on the renter target implementation being used.
6213 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6214 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6215 * stencil buffer and incur an extra memory overhead
6216 ******************************************************/
6218 if (This->stencilBufferTarget) {
6219 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6220 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6221 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6223 struct wined3d_context *context = ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6224 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
6225 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6229 tmp = This->stencilBufferTarget;
6230 This->stencilBufferTarget = pNewZStencil;
6231 /* should we be calling the parent or the wined3d surface? */
6232 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6233 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6236 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6237 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6238 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6239 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6240 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6247 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6248 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6250 /* TODO: the use of Impl is deprecated. */
6251 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6252 WINED3DLOCKED_RECT lockedRect;
6254 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6256 /* some basic validation checks */
6257 if(This->cursorTexture) {
6258 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6260 glDeleteTextures(1, &This->cursorTexture);
6262 This->cursorTexture = 0;
6265 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6266 This->haveHardwareCursor = TRUE;
6268 This->haveHardwareCursor = FALSE;
6271 WINED3DLOCKED_RECT rect;
6273 /* MSDN: Cursor must be A8R8G8B8 */
6274 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6276 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6277 return WINED3DERR_INVALIDCALL;
6280 /* MSDN: Cursor must be smaller than the display mode */
6281 if(pSur->currentDesc.Width > This->ddraw_width ||
6282 pSur->currentDesc.Height > This->ddraw_height) {
6283 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);
6284 return WINED3DERR_INVALIDCALL;
6287 if (!This->haveHardwareCursor) {
6288 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6290 /* Do not store the surface's pointer because the application may
6291 * release it after setting the cursor image. Windows doesn't
6292 * addref the set surface, so we can't do this either without
6293 * creating circular refcount dependencies. Copy out the gl texture
6296 This->cursorWidth = pSur->currentDesc.Width;
6297 This->cursorHeight = pSur->currentDesc.Height;
6298 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6300 const struct GlPixelFormatDesc *glDesc =
6301 getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, &This->adapter->gl_info);
6302 char *mem, *bits = rect.pBits;
6303 GLint intfmt = glDesc->glInternal;
6304 GLint format = glDesc->glFormat;
6305 GLint type = glDesc->glType;
6306 INT height = This->cursorHeight;
6307 INT width = This->cursorWidth;
6308 INT bpp = glDesc->byte_count;
6312 /* Reformat the texture memory (pitch and width can be
6314 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6315 for(i = 0; i < height; i++)
6316 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6317 IWineD3DSurface_UnlockRect(pCursorBitmap);
6319 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6323 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6324 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6325 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6328 /* Make sure that a proper texture unit is selected */
6329 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6330 checkGLcall("glActiveTextureARB");
6331 sampler = This->rev_tex_unit_map[0];
6332 if (sampler != WINED3D_UNMAPPED_STAGE)
6334 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6336 /* Create a new cursor texture */
6337 glGenTextures(1, &This->cursorTexture);
6338 checkGLcall("glGenTextures");
6339 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6340 checkGLcall("glBindTexture");
6341 /* Copy the bitmap memory into the cursor texture */
6342 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6343 HeapFree(GetProcessHeap(), 0, mem);
6344 checkGLcall("glTexImage2D");
6346 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6347 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6348 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6355 FIXME("A cursor texture was not returned.\n");
6356 This->cursorTexture = 0;
6361 /* Draw a hardware cursor */
6362 ICONINFO cursorInfo;
6364 /* Create and clear maskBits because it is not needed for
6365 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6367 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6368 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6369 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6370 WINED3DLOCK_NO_DIRTY_UPDATE |
6371 WINED3DLOCK_READONLY
6373 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6374 pSur->currentDesc.Height);
6376 cursorInfo.fIcon = FALSE;
6377 cursorInfo.xHotspot = XHotSpot;
6378 cursorInfo.yHotspot = YHotSpot;
6379 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6381 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6382 1, 32, lockedRect.pBits);
6383 IWineD3DSurface_UnlockRect(pCursorBitmap);
6384 /* Create our cursor and clean up. */
6385 cursor = CreateIconIndirect(&cursorInfo);
6387 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6388 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6389 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6390 This->hardwareCursor = cursor;
6391 HeapFree(GetProcessHeap(), 0, maskBits);
6395 This->xHotSpot = XHotSpot;
6396 This->yHotSpot = YHotSpot;
6400 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6402 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6404 This->xScreenSpace = XScreenSpace;
6405 This->yScreenSpace = YScreenSpace;
6411 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6413 BOOL oldVisible = This->bCursorVisible;
6416 TRACE("(%p) : visible(%d)\n", This, bShow);
6419 * When ShowCursor is first called it should make the cursor appear at the OS's last
6420 * known cursor position. Because of this, some applications just repetitively call
6421 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6424 This->xScreenSpace = pt.x;
6425 This->yScreenSpace = pt.y;
6427 if (This->haveHardwareCursor) {
6428 This->bCursorVisible = bShow;
6430 SetCursor(This->hardwareCursor);
6436 if (This->cursorTexture)
6437 This->bCursorVisible = bShow;
6443 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6445 IWineD3DResourceImpl *resource;
6446 TRACE("(%p) : state (%u)\n", This, This->state);
6448 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6449 switch (This->state) {
6452 case WINED3DERR_DEVICELOST:
6454 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6455 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6456 return WINED3DERR_DEVICENOTRESET;
6458 return WINED3DERR_DEVICELOST;
6460 case WINED3DERR_DRIVERINTERNALERROR:
6461 return WINED3DERR_DRIVERINTERNALERROR;
6465 return WINED3DERR_DRIVERINTERNALERROR;
6468 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6469 TRACE("checking resource %p for eviction\n", resource);
6470 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6471 TRACE("Evicting %p\n", resource);
6472 IWineD3DResource_UnLoad(resource);
6474 IWineD3DResource_Release(resource);
6478 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6480 TRACE("(%p)\n", This);
6482 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6486 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6488 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6490 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6491 if(surface->Flags & SFLAG_DIBSECTION) {
6492 /* Release the DC */
6493 SelectObject(surface->hDC, surface->dib.holdbitmap);
6494 DeleteDC(surface->hDC);
6495 /* Release the DIB section */
6496 DeleteObject(surface->dib.DIBsection);
6497 surface->dib.bitmap_data = NULL;
6498 surface->resource.allocatedMemory = NULL;
6499 surface->Flags &= ~SFLAG_DIBSECTION;
6501 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6502 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6503 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6504 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6505 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6506 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6508 surface->pow2Width = surface->pow2Height = 1;
6509 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6510 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6512 surface->glRect.left = 0;
6513 surface->glRect.top = 0;
6514 surface->glRect.right = surface->pow2Width;
6515 surface->glRect.bottom = surface->pow2Height;
6517 if (surface->texture_name)
6519 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6521 glDeleteTextures(1, &surface->texture_name);
6523 surface->texture_name = 0;
6524 surface->Flags &= ~SFLAG_CLIENT;
6526 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6527 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6528 surface->Flags |= SFLAG_NONPOW2;
6530 surface->Flags &= ~SFLAG_NONPOW2;
6532 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6533 surface->resource.allocatedMemory = NULL;
6534 surface->resource.heapMemory = NULL;
6535 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6536 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6537 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6538 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6540 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6544 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6545 TRACE("Unloading resource %p\n", resource);
6546 IWineD3DResource_UnLoad(resource);
6547 IWineD3DResource_Release(resource);
6551 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6554 WINED3DDISPLAYMODE m;
6557 /* All Windowed modes are supported, as is leaving the current mode */
6558 if(pp->Windowed) return TRUE;
6559 if(!pp->BackBufferWidth) return TRUE;
6560 if(!pp->BackBufferHeight) return TRUE;
6562 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6563 for(i = 0; i < count; i++) {
6564 memset(&m, 0, sizeof(m));
6565 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6567 ERR("EnumAdapterModes failed\n");
6569 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6570 /* Mode found, it is supported */
6574 /* Mode not found -> not supported */
6578 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6580 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6581 const struct wined3d_context *context;
6582 const struct wined3d_gl_info *gl_info;
6584 IWineD3DBaseShaderImpl *shader;
6586 context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6587 gl_info = context->gl_info;
6589 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6590 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6591 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6595 if(This->depth_blt_texture) {
6596 glDeleteTextures(1, &This->depth_blt_texture);
6597 This->depth_blt_texture = 0;
6599 if (This->depth_blt_rb) {
6600 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6601 This->depth_blt_rb = 0;
6602 This->depth_blt_rb_w = 0;
6603 This->depth_blt_rb_h = 0;
6607 This->blitter->free_private(iface);
6608 This->frag_pipe->free_private(iface);
6609 This->shader_backend->shader_free_private(iface);
6612 for (i = 0; i < This->adapter->gl_info.max_textures; ++i)
6614 /* Textures are recreated below */
6615 glDeleteTextures(1, &This->dummyTextureName[i]);
6616 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6617 This->dummyTextureName[i] = 0;
6621 while(This->numContexts) {
6622 DestroyContext(This, This->contexts[0]);
6624 HeapFree(GetProcessHeap(), 0, swapchain->context);
6625 swapchain->context = NULL;
6626 swapchain->num_contexts = 0;
6629 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6631 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6633 IWineD3DSurfaceImpl *target;
6635 /* Recreate the primary swapchain's context */
6636 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6637 if(swapchain->backBuffer) {
6638 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6640 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6642 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
6643 &swapchain->presentParms);
6644 swapchain->num_contexts = 1;
6646 create_dummy_textures(This);
6648 hr = This->shader_backend->shader_alloc_private(iface);
6650 ERR("Failed to recreate shader private data\n");
6653 hr = This->frag_pipe->alloc_private(iface);
6655 TRACE("Fragment pipeline private data couldn't be allocated\n");
6658 hr = This->blitter->alloc_private(iface);
6660 TRACE("Blitter private data couldn't be allocated\n");
6667 This->blitter->free_private(iface);
6668 This->frag_pipe->free_private(iface);
6669 This->shader_backend->shader_free_private(iface);
6673 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6675 IWineD3DSwapChainImpl *swapchain;
6677 BOOL DisplayModeChanged = FALSE;
6678 WINED3DDISPLAYMODE mode;
6679 TRACE("(%p)\n", This);
6681 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6683 ERR("Failed to get the first implicit swapchain\n");
6687 if(!is_display_mode_supported(This, pPresentationParameters)) {
6688 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6689 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6690 pPresentationParameters->BackBufferHeight);
6691 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6692 return WINED3DERR_INVALIDCALL;
6695 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6696 * on an existing gl context, so there's no real need for recreation.
6698 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6700 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6702 TRACE("New params:\n");
6703 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6704 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6705 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6706 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6707 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6708 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6709 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6710 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6711 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6712 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6713 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6714 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6715 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6717 /* No special treatment of these parameters. Just store them */
6718 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6719 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6720 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6721 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6723 /* What to do about these? */
6724 if(pPresentationParameters->BackBufferCount != 0 &&
6725 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6726 ERR("Cannot change the back buffer count yet\n");
6728 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6729 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6730 ERR("Cannot change the back buffer format yet\n");
6732 if(pPresentationParameters->hDeviceWindow != NULL &&
6733 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6734 ERR("Cannot change the device window yet\n");
6736 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6739 TRACE("Creating the depth stencil buffer\n");
6741 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6743 pPresentationParameters->BackBufferWidth,
6744 pPresentationParameters->BackBufferHeight,
6745 pPresentationParameters->AutoDepthStencilFormat,
6746 pPresentationParameters->MultiSampleType,
6747 pPresentationParameters->MultiSampleQuality,
6749 &This->auto_depth_stencil_buffer);
6752 ERR("Failed to create the depth stencil buffer\n");
6753 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6754 return WINED3DERR_INVALIDCALL;
6758 /* Reset the depth stencil */
6759 if (pPresentationParameters->EnableAutoDepthStencil)
6760 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6762 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6764 TRACE("Resetting stateblock\n");
6765 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6766 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6768 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6770 if(pPresentationParameters->Windowed) {
6771 mode.Width = swapchain->orig_width;
6772 mode.Height = swapchain->orig_height;
6773 mode.RefreshRate = 0;
6774 mode.Format = swapchain->presentParms.BackBufferFormat;
6776 mode.Width = pPresentationParameters->BackBufferWidth;
6777 mode.Height = pPresentationParameters->BackBufferHeight;
6778 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6779 mode.Format = swapchain->presentParms.BackBufferFormat;
6782 /* Should Width == 800 && Height == 0 set 800x600? */
6783 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6784 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6785 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6789 if(!pPresentationParameters->Windowed) {
6790 DisplayModeChanged = TRUE;
6792 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6793 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6795 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6796 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6797 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6799 if(This->auto_depth_stencil_buffer) {
6800 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6804 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6805 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6806 DisplayModeChanged) {
6808 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6810 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
6811 if(swapchain->presentParms.Windowed) {
6812 /* switch from windowed to fs */
6813 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
6814 pPresentationParameters->BackBufferWidth,
6815 pPresentationParameters->BackBufferHeight);
6817 /* Fullscreen -> fullscreen mode change */
6818 MoveWindow(swapchain->win_handle, 0, 0,
6819 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6822 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
6823 /* Fullscreen -> windowed switch */
6824 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
6826 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6827 } else if(!pPresentationParameters->Windowed) {
6828 DWORD style = This->style, exStyle = This->exStyle;
6829 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6830 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6831 * Reset to clear up their mess. Guild Wars also loses the device during that.
6835 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
6836 pPresentationParameters->BackBufferWidth,
6837 pPresentationParameters->BackBufferHeight);
6838 This->style = style;
6839 This->exStyle = exStyle;
6842 /* Note: No parent needed for initial internal stateblock */
6843 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6844 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6845 else TRACE("Created stateblock %p\n", This->stateBlock);
6846 This->updateStateBlock = This->stateBlock;
6847 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6849 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6851 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6854 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6855 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6857 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6863 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6865 /** FIXME: always true at the moment **/
6866 if(!bEnableDialogs) {
6867 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6873 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6875 TRACE("(%p) : pParameters %p\n", This, pParameters);
6877 *pParameters = This->createParms;
6881 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6882 IWineD3DSwapChain *swapchain;
6884 TRACE("Relaying to swapchain\n");
6886 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6887 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6888 IWineD3DSwapChain_Release(swapchain);
6893 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6894 IWineD3DSwapChain *swapchain;
6896 TRACE("Relaying to swapchain\n");
6898 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6899 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6900 IWineD3DSwapChain_Release(swapchain);
6906 /** ********************************************************
6907 * Notification functions
6908 ** ********************************************************/
6909 /** This function must be called in the release of a resource when ref == 0,
6910 * the contents of resource must still be correct,
6911 * any handles to other resource held by the caller must be closed
6912 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6913 *****************************************************/
6914 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6916 TRACE("(%p) : Adding resource %p\n", This, resource);
6918 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6921 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6923 TRACE("(%p) : Removing resource %p\n", This, resource);
6925 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6928 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6930 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6933 TRACE("(%p) : resource %p\n", This, resource);
6935 context_resource_released((IWineD3DDevice *)This, resource, type);
6938 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6939 case WINED3DRTYPE_SURFACE: {
6942 if (This->d3d_initialized)
6944 for (i = 0; i < This->adapter->gl_info.max_buffers; ++i)
6946 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6947 This->render_targets[i] = NULL;
6950 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6951 This->stencilBufferTarget = NULL;
6957 case WINED3DRTYPE_TEXTURE:
6958 case WINED3DRTYPE_CUBETEXTURE:
6959 case WINED3DRTYPE_VOLUMETEXTURE:
6960 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6961 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6962 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6963 This->stateBlock->textures[counter] = NULL;
6965 if (This->updateStateBlock != This->stateBlock ){
6966 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6967 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6968 This->updateStateBlock->textures[counter] = NULL;
6973 case WINED3DRTYPE_VOLUME:
6974 /* TODO: nothing really? */
6976 case WINED3DRTYPE_BUFFER:
6979 TRACE("Cleaning up stream pointers\n");
6981 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6982 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6983 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6985 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6986 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6987 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6988 This->updateStateBlock->streamSource[streamNumber] = 0;
6989 /* Set changed flag? */
6992 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) */
6993 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6994 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6995 This->stateBlock->streamSource[streamNumber] = 0;
7000 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7001 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7002 This->updateStateBlock->pIndexData = NULL;
7005 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7006 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7007 This->stateBlock->pIndexData = NULL;
7014 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7019 /* Remove the resource from the resourceStore */
7020 device_resource_remove(This, resource);
7022 TRACE("Resource released\n");
7026 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7028 IWineD3DResourceImpl *resource, *cursor;
7030 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7032 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7033 TRACE("enumerating resource %p\n", resource);
7034 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7035 ret = pCallback((IWineD3DResource *) resource, pData);
7036 if(ret == S_FALSE) {
7037 TRACE("Canceling enumeration\n");
7044 /**********************************************************
7045 * IWineD3DDevice VTbl follows
7046 **********************************************************/
7048 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7050 /*** IUnknown methods ***/
7051 IWineD3DDeviceImpl_QueryInterface,
7052 IWineD3DDeviceImpl_AddRef,
7053 IWineD3DDeviceImpl_Release,
7054 /*** IWineD3DDevice methods ***/
7055 IWineD3DDeviceImpl_GetParent,
7056 /*** Creation methods**/
7057 IWineD3DDeviceImpl_CreateBuffer,
7058 IWineD3DDeviceImpl_CreateVertexBuffer,
7059 IWineD3DDeviceImpl_CreateIndexBuffer,
7060 IWineD3DDeviceImpl_CreateStateBlock,
7061 IWineD3DDeviceImpl_CreateSurface,
7062 IWineD3DDeviceImpl_CreateRendertargetView,
7063 IWineD3DDeviceImpl_CreateTexture,
7064 IWineD3DDeviceImpl_CreateVolumeTexture,
7065 IWineD3DDeviceImpl_CreateVolume,
7066 IWineD3DDeviceImpl_CreateCubeTexture,
7067 IWineD3DDeviceImpl_CreateQuery,
7068 IWineD3DDeviceImpl_CreateSwapChain,
7069 IWineD3DDeviceImpl_CreateVertexDeclaration,
7070 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7071 IWineD3DDeviceImpl_CreateVertexShader,
7072 IWineD3DDeviceImpl_CreatePixelShader,
7073 IWineD3DDeviceImpl_CreatePalette,
7074 /*** Odd functions **/
7075 IWineD3DDeviceImpl_Init3D,
7076 IWineD3DDeviceImpl_InitGDI,
7077 IWineD3DDeviceImpl_Uninit3D,
7078 IWineD3DDeviceImpl_UninitGDI,
7079 IWineD3DDeviceImpl_SetMultithreaded,
7080 IWineD3DDeviceImpl_EvictManagedResources,
7081 IWineD3DDeviceImpl_GetAvailableTextureMem,
7082 IWineD3DDeviceImpl_GetBackBuffer,
7083 IWineD3DDeviceImpl_GetCreationParameters,
7084 IWineD3DDeviceImpl_GetDeviceCaps,
7085 IWineD3DDeviceImpl_GetDirect3D,
7086 IWineD3DDeviceImpl_GetDisplayMode,
7087 IWineD3DDeviceImpl_SetDisplayMode,
7088 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7089 IWineD3DDeviceImpl_GetRasterStatus,
7090 IWineD3DDeviceImpl_GetSwapChain,
7091 IWineD3DDeviceImpl_Reset,
7092 IWineD3DDeviceImpl_SetDialogBoxMode,
7093 IWineD3DDeviceImpl_SetCursorProperties,
7094 IWineD3DDeviceImpl_SetCursorPosition,
7095 IWineD3DDeviceImpl_ShowCursor,
7096 IWineD3DDeviceImpl_TestCooperativeLevel,
7097 /*** Getters and setters **/
7098 IWineD3DDeviceImpl_SetClipPlane,
7099 IWineD3DDeviceImpl_GetClipPlane,
7100 IWineD3DDeviceImpl_SetClipStatus,
7101 IWineD3DDeviceImpl_GetClipStatus,
7102 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7103 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7104 IWineD3DDeviceImpl_SetDepthStencilSurface,
7105 IWineD3DDeviceImpl_GetDepthStencilSurface,
7106 IWineD3DDeviceImpl_SetGammaRamp,
7107 IWineD3DDeviceImpl_GetGammaRamp,
7108 IWineD3DDeviceImpl_SetIndexBuffer,
7109 IWineD3DDeviceImpl_GetIndexBuffer,
7110 IWineD3DDeviceImpl_SetBaseVertexIndex,
7111 IWineD3DDeviceImpl_GetBaseVertexIndex,
7112 IWineD3DDeviceImpl_SetLight,
7113 IWineD3DDeviceImpl_GetLight,
7114 IWineD3DDeviceImpl_SetLightEnable,
7115 IWineD3DDeviceImpl_GetLightEnable,
7116 IWineD3DDeviceImpl_SetMaterial,
7117 IWineD3DDeviceImpl_GetMaterial,
7118 IWineD3DDeviceImpl_SetNPatchMode,
7119 IWineD3DDeviceImpl_GetNPatchMode,
7120 IWineD3DDeviceImpl_SetPaletteEntries,
7121 IWineD3DDeviceImpl_GetPaletteEntries,
7122 IWineD3DDeviceImpl_SetPixelShader,
7123 IWineD3DDeviceImpl_GetPixelShader,
7124 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7125 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7126 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7127 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7128 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7129 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7130 IWineD3DDeviceImpl_SetRenderState,
7131 IWineD3DDeviceImpl_GetRenderState,
7132 IWineD3DDeviceImpl_SetRenderTarget,
7133 IWineD3DDeviceImpl_GetRenderTarget,
7134 IWineD3DDeviceImpl_SetFrontBackBuffers,
7135 IWineD3DDeviceImpl_SetSamplerState,
7136 IWineD3DDeviceImpl_GetSamplerState,
7137 IWineD3DDeviceImpl_SetScissorRect,
7138 IWineD3DDeviceImpl_GetScissorRect,
7139 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7140 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7141 IWineD3DDeviceImpl_SetStreamSource,
7142 IWineD3DDeviceImpl_GetStreamSource,
7143 IWineD3DDeviceImpl_SetStreamSourceFreq,
7144 IWineD3DDeviceImpl_GetStreamSourceFreq,
7145 IWineD3DDeviceImpl_SetTexture,
7146 IWineD3DDeviceImpl_GetTexture,
7147 IWineD3DDeviceImpl_SetTextureStageState,
7148 IWineD3DDeviceImpl_GetTextureStageState,
7149 IWineD3DDeviceImpl_SetTransform,
7150 IWineD3DDeviceImpl_GetTransform,
7151 IWineD3DDeviceImpl_SetVertexDeclaration,
7152 IWineD3DDeviceImpl_GetVertexDeclaration,
7153 IWineD3DDeviceImpl_SetVertexShader,
7154 IWineD3DDeviceImpl_GetVertexShader,
7155 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7156 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7157 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7158 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7159 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7160 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7161 IWineD3DDeviceImpl_SetViewport,
7162 IWineD3DDeviceImpl_GetViewport,
7163 IWineD3DDeviceImpl_MultiplyTransform,
7164 IWineD3DDeviceImpl_ValidateDevice,
7165 IWineD3DDeviceImpl_ProcessVertices,
7166 /*** State block ***/
7167 IWineD3DDeviceImpl_BeginStateBlock,
7168 IWineD3DDeviceImpl_EndStateBlock,
7169 /*** Scene management ***/
7170 IWineD3DDeviceImpl_BeginScene,
7171 IWineD3DDeviceImpl_EndScene,
7172 IWineD3DDeviceImpl_Present,
7173 IWineD3DDeviceImpl_Clear,
7174 IWineD3DDeviceImpl_ClearRendertargetView,
7176 IWineD3DDeviceImpl_SetPrimitiveType,
7177 IWineD3DDeviceImpl_GetPrimitiveType,
7178 IWineD3DDeviceImpl_DrawPrimitive,
7179 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7180 IWineD3DDeviceImpl_DrawPrimitiveUP,
7181 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7182 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7183 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7184 IWineD3DDeviceImpl_DrawRectPatch,
7185 IWineD3DDeviceImpl_DrawTriPatch,
7186 IWineD3DDeviceImpl_DeletePatch,
7187 IWineD3DDeviceImpl_ColorFill,
7188 IWineD3DDeviceImpl_UpdateTexture,
7189 IWineD3DDeviceImpl_UpdateSurface,
7190 IWineD3DDeviceImpl_GetFrontBufferData,
7191 /*** object tracking ***/
7192 IWineD3DDeviceImpl_EnumResources
7195 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7196 DWORD rep = This->StateTable[state].representative;
7197 struct wined3d_context *context;
7202 for(i = 0; i < This->numContexts; i++) {
7203 context = This->contexts[i];
7204 if(isStateDirty(context, rep)) continue;
7206 context->dirtyArray[context->numDirtyEntries++] = rep;
7209 context->isStateDirty[idx] |= (1 << shift);
7213 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7215 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.wineD3DDevice;
7216 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7217 *width = device->pbufferWidth;
7218 *height = device->pbufferHeight;
7221 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7223 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7224 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7225 *width = surface->pow2Width;
7226 *height = surface->pow2Height;
7229 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7231 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7232 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7233 * current context's drawable, which is the size of the back buffer of the swapchain
7234 * the active context belongs to. The back buffer of the swapchain is stored as the
7235 * surface the context belongs to. */
7236 *width = surface->currentDesc.Width;
7237 *height = surface->currentDesc.Height;