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 (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
302 && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
304 stream_info->swizzle_map |= 1 << idx;
306 stream_info->use_map |= 1 << idx;
310 /* Now call PreLoad on all the vertex buffers. In the very rare case
311 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
312 * The vertex buffer can now use the strided structure in the device instead of finding its
315 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
317 for (i = 0; i < stream_count; ++i)
319 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
320 if (vb) IWineD3DBuffer_PreLoad(vb);
324 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
325 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
327 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, gl_info);
328 e->format_desc = format_desc;
329 e->stride = strided->dwStride;
330 e->data = strided->lpData;
332 e->buffer_object = 0;
335 void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
336 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
340 memset(stream_info, 0, sizeof(*stream_info));
342 if (strided->position.lpData)
343 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
344 if (strided->normal.lpData)
345 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
346 if (strided->diffuse.lpData)
347 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
348 if (strided->specular.lpData)
349 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
351 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
353 if (strided->texCoords[i].lpData)
354 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
355 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
358 stream_info->position_transformed = strided->position_transformed;
360 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
362 if (!stream_info->elements[i].format_desc) continue;
364 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
365 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
367 stream_info->swizzle_map |= 1 << i;
369 stream_info->use_map |= 1 << i;
373 /**********************************************************
374 * IUnknown parts follows
375 **********************************************************/
377 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
381 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
382 if (IsEqualGUID(riid, &IID_IUnknown)
383 || IsEqualGUID(riid, &IID_IWineD3DBase)
384 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
385 IUnknown_AddRef(iface);
390 return E_NOINTERFACE;
393 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
395 ULONG refCount = InterlockedIncrement(&This->ref);
397 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
401 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
403 ULONG refCount = InterlockedDecrement(&This->ref);
405 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
410 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
411 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
412 This->multistate_funcs[i] = NULL;
415 /* TODO: Clean up all the surfaces and textures! */
416 /* NOTE: You must release the parent if the object was created via a callback
417 ** ***************************/
419 if (!list_empty(&This->resources)) {
420 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
421 dumpResources(&This->resources);
424 if(This->contexts) ERR("Context array not freed!\n");
425 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
426 This->haveHardwareCursor = FALSE;
428 IWineD3D_Release(This->wined3d);
429 This->wined3d = NULL;
430 HeapFree(GetProcessHeap(), 0, This);
431 TRACE("Freed device %p\n", This);
437 /**********************************************************
438 * IWineD3DDevice implementation follows
439 **********************************************************/
440 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
442 *pParent = This->parent;
443 IUnknown_AddRef(This->parent);
447 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
448 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
451 struct wined3d_buffer *object;
454 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
456 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
459 ERR("Failed to allocate memory\n");
460 return E_OUTOFMEMORY;
463 FIXME("Ignoring access flags (pool)\n");
465 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
466 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
469 WARN("Failed to initialize buffer, hr %#x.\n", hr);
470 HeapFree(GetProcessHeap(), 0, object);
473 object->desc = *desc;
475 TRACE("Created buffer %p.\n", object);
477 *buffer = (IWineD3DBuffer *)object;
482 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
483 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
484 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
487 struct wined3d_buffer *object;
490 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
491 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
493 if (Pool == WINED3DPOOL_SCRATCH)
495 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
496 * anyway, SCRATCH vertex buffers aren't usable anywhere
498 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
499 *ppVertexBuffer = NULL;
500 return WINED3DERR_INVALIDCALL;
503 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
506 ERR("Out of memory\n");
507 *ppVertexBuffer = NULL;
508 return WINED3DERR_OUTOFVIDEOMEMORY;
511 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
512 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
515 WARN("Failed to initialize buffer, hr %#x.\n", hr);
516 HeapFree(GetProcessHeap(), 0, object);
520 TRACE("Created buffer %p.\n", object);
521 *ppVertexBuffer = (IWineD3DBuffer *)object;
526 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
527 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
528 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
531 struct wined3d_buffer *object;
534 TRACE("(%p) Creating index buffer\n", This);
536 /* Allocate the storage for the device */
537 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
540 ERR("Out of memory\n");
541 *ppIndexBuffer = NULL;
542 return WINED3DERR_OUTOFVIDEOMEMORY;
545 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
546 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
550 WARN("Failed to initialize buffer, hr %#x\n", hr);
551 HeapFree(GetProcessHeap(), 0, object);
555 TRACE("Created buffer %p.\n", object);
557 *ppIndexBuffer = (IWineD3DBuffer *) object;
562 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
563 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
566 IWineD3DStateBlockImpl *object;
569 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
572 ERR("Failed to allocate stateblock memory.\n");
573 return E_OUTOFMEMORY;
576 hr = stateblock_init(object, This, type);
579 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
580 HeapFree(GetProcessHeap(), 0, object);
584 TRACE("Created stateblock %p.\n", object);
585 *stateblock = (IWineD3DStateBlock *)object;
590 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
591 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
592 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
593 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
596 IWineD3DSurfaceImpl *object;
599 TRACE("(%p) Create surface\n",This);
601 if (Impl == SURFACE_OPENGL && !This->adapter)
603 ERR("OpenGL surfaces are not available without OpenGL.\n");
604 return WINED3DERR_NOTAVAILABLE;
607 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
610 ERR("Failed to allocate surface memory.\n");
611 return WINED3DERR_OUTOFVIDEOMEMORY;
614 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
615 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
618 WARN("Failed to initialize surface, returning %#x.\n", hr);
619 HeapFree(GetProcessHeap(), 0, object);
623 TRACE("(%p) : Created surface %p\n", This, object);
625 *ppSurface = (IWineD3DSurface *)object;
630 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
631 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
633 struct wined3d_rendertarget_view *object;
635 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
638 ERR("Failed to allocate memory\n");
639 return E_OUTOFMEMORY;
642 object->vtbl = &wined3d_rendertarget_view_vtbl;
643 object->refcount = 1;
644 IWineD3DResource_AddRef(resource);
645 object->resource = resource;
646 object->parent = parent;
648 *rendertarget_view = (IWineD3DRendertargetView *)object;
653 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
654 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
655 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
658 IWineD3DTextureImpl *object;
661 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
662 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
663 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
665 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
668 ERR("Out of memory\n");
670 return WINED3DERR_OUTOFVIDEOMEMORY;
673 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
676 WARN("Failed to initialize texture, returning %#x\n", hr);
677 HeapFree(GetProcessHeap(), 0, object);
682 *ppTexture = (IWineD3DTexture *)object;
684 TRACE("(%p) : Created texture %p\n", This, object);
689 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
690 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
691 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
694 IWineD3DVolumeTextureImpl *object;
697 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
698 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
700 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
703 ERR("Out of memory\n");
704 *ppVolumeTexture = NULL;
705 return WINED3DERR_OUTOFVIDEOMEMORY;
708 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
711 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
712 HeapFree(GetProcessHeap(), 0, object);
713 *ppVolumeTexture = NULL;
717 TRACE("(%p) : Created volume texture %p.\n", This, object);
718 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
723 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
724 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
725 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
728 IWineD3DVolumeImpl *object;
731 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
732 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
734 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
737 ERR("Out of memory\n");
739 return WINED3DERR_OUTOFVIDEOMEMORY;
742 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
745 WARN("Failed to initialize volume, returning %#x.\n", hr);
746 HeapFree(GetProcessHeap(), 0, object);
750 TRACE("(%p) : Created volume %p.\n", This, object);
751 *ppVolume = (IWineD3DVolume *)object;
756 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
757 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
758 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
761 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
764 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
767 ERR("Out of memory\n");
768 *ppCubeTexture = NULL;
769 return WINED3DERR_OUTOFVIDEOMEMORY;
772 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
775 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
776 HeapFree(GetProcessHeap(), 0, object);
777 *ppCubeTexture = NULL;
781 TRACE("(%p) : Created Cube Texture %p\n", This, object);
782 *ppCubeTexture = (IWineD3DCubeTexture *)object;
787 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
788 WINED3DQUERYTYPE type, IWineD3DQuery **query, IUnknown *parent)
790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
791 IWineD3DQueryImpl *object;
794 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface, type, query, parent);
796 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
799 ERR("Failed to allocate query memory.\n");
800 return E_OUTOFMEMORY;
803 hr = query_init(object, This, type, parent);
806 WARN("Failed to initialize query, hr %#x.\n", hr);
807 HeapFree(GetProcessHeap(), 0, object);
811 TRACE("Created query %p.\n", object);
812 *query = (IWineD3DQuery *)object;
817 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
818 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
819 IUnknown *parent, WINED3DSURFTYPE surface_type)
821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
822 IWineD3DSwapChainImpl *object;
825 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
826 iface, present_parameters, swapchain, parent, surface_type);
828 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
831 ERR("Failed to allocate swapchain memory.\n");
832 return E_OUTOFMEMORY;
835 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
838 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
839 HeapFree(GetProcessHeap(), 0, object);
843 TRACE("Created swapchain %p.\n", object);
844 *swapchain = (IWineD3DSwapChain *)object;
849 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
850 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
852 TRACE("(%p)\n", This);
854 return This->NumberOfSwapChains;
857 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
859 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
861 if(iSwapChain < This->NumberOfSwapChains) {
862 *pSwapChain = This->swapchains[iSwapChain];
863 IWineD3DSwapChain_AddRef(*pSwapChain);
864 TRACE("(%p) returning %p\n", This, *pSwapChain);
867 TRACE("Swapchain out of range\n");
869 return WINED3DERR_INVALIDCALL;
873 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
874 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
875 const WINED3DVERTEXELEMENT *elements, UINT element_count)
877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
878 IWineD3DVertexDeclarationImpl *object = NULL;
881 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
882 iface, declaration, parent, elements, element_count);
884 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
887 ERR("Failed to allocate vertex declaration memory.\n");
888 return E_OUTOFMEMORY;
891 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
894 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
895 HeapFree(GetProcessHeap(), 0, object);
899 TRACE("Created vertex declaration %p.\n", object);
900 *declaration = (IWineD3DVertexDeclaration *)object;
905 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
906 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
908 unsigned int idx, idx2;
910 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
911 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
912 BOOL has_blend_idx = has_blend &&
913 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
914 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
915 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
916 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
917 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
918 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
919 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
921 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
922 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
923 WINED3DVERTEXELEMENT *elements = NULL;
926 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
927 if (has_blend_idx) num_blends--;
929 /* Compute declaration size */
930 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
931 has_psize + has_diffuse + has_specular + num_textures;
933 /* convert the declaration */
934 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
935 if (!elements) return ~0U;
939 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
940 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
941 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
943 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
944 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
945 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
948 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
949 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
951 elements[idx].usage_idx = 0;
954 if (has_blend && (num_blends > 0)) {
955 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
956 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
959 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
960 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
961 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
962 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
964 ERR("Unexpected amount of blend values: %u\n", num_blends);
967 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
968 elements[idx].usage_idx = 0;
972 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
973 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
974 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
975 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
976 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
978 elements[idx].format = WINED3DFMT_R32_FLOAT;
979 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
980 elements[idx].usage_idx = 0;
984 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
985 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
986 elements[idx].usage_idx = 0;
990 elements[idx].format = WINED3DFMT_R32_FLOAT;
991 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
992 elements[idx].usage_idx = 0;
996 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
997 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
998 elements[idx].usage_idx = 0;
1002 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1003 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1004 elements[idx].usage_idx = 1;
1007 for (idx2 = 0; idx2 < num_textures; idx2++) {
1008 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1009 switch (numcoords) {
1010 case WINED3DFVF_TEXTUREFORMAT1:
1011 elements[idx].format = WINED3DFMT_R32_FLOAT;
1013 case WINED3DFVF_TEXTUREFORMAT2:
1014 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1016 case WINED3DFVF_TEXTUREFORMAT3:
1017 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1019 case WINED3DFVF_TEXTUREFORMAT4:
1020 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1023 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1024 elements[idx].usage_idx = idx2;
1028 /* Now compute offsets, and initialize the rest of the fields */
1029 for (idx = 0, offset = 0; idx < size; ++idx)
1031 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1032 elements[idx].input_slot = 0;
1033 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1034 elements[idx].offset = offset;
1035 offset += format_desc->component_count * format_desc->component_size;
1038 *ppVertexElements = elements;
1042 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1043 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1044 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1046 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1047 WINED3DVERTEXELEMENT *elements;
1051 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1053 size = ConvertFvfToDeclaration(This, fvf, &elements);
1054 if (size == ~0U) return E_OUTOFMEMORY;
1056 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1057 HeapFree(GetProcessHeap(), 0, elements);
1061 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1062 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1063 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1064 const struct wined3d_parent_ops *parent_ops)
1066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1067 IWineD3DVertexShaderImpl *object;
1070 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1073 ERR("Failed to allocate shader memory.\n");
1074 return E_OUTOFMEMORY;
1077 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1080 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1081 HeapFree(GetProcessHeap(), 0, object);
1085 TRACE("Created vertex shader %p.\n", object);
1086 *ppVertexShader = (IWineD3DVertexShader *)object;
1091 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1092 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1093 IWineD3DGeometryShader **shader, IUnknown *parent,
1094 const struct wined3d_parent_ops *parent_ops)
1096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1097 struct wined3d_geometryshader *object;
1100 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1103 ERR("Failed to allocate shader memory.\n");
1104 return E_OUTOFMEMORY;
1107 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1110 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1111 HeapFree(GetProcessHeap(), 0, object);
1115 TRACE("Created geometry shader %p.\n", object);
1116 *shader = (IWineD3DGeometryShader *)object;
1121 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1122 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1123 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1124 const struct wined3d_parent_ops *parent_ops)
1126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1127 IWineD3DPixelShaderImpl *object;
1130 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1133 ERR("Failed to allocate shader memory.\n");
1134 return E_OUTOFMEMORY;
1137 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1140 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1141 HeapFree(GetProcessHeap(), 0, object);
1145 TRACE("Created pixel shader %p.\n", object);
1146 *ppPixelShader = (IWineD3DPixelShader *)object;
1151 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1152 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1155 IWineD3DPaletteImpl *object;
1157 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1159 /* Create the new object */
1160 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1162 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1163 return E_OUTOFMEMORY;
1166 object->lpVtbl = &IWineD3DPalette_Vtbl;
1168 object->Flags = Flags;
1169 object->parent = Parent;
1170 object->device = This;
1171 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1172 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1175 HeapFree( GetProcessHeap(), 0, object);
1176 return E_OUTOFMEMORY;
1179 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1181 IWineD3DPalette_Release((IWineD3DPalette *) object);
1185 *Palette = (IWineD3DPalette *) object;
1190 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1194 HDC dcb = NULL, dcs = NULL;
1195 WINEDDCOLORKEY colorkey;
1197 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1200 GetObjectA(hbm, sizeof(BITMAP), &bm);
1201 dcb = CreateCompatibleDC(NULL);
1203 SelectObject(dcb, hbm);
1207 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1208 * couldn't be loaded
1210 memset(&bm, 0, sizeof(bm));
1215 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1216 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1217 NULL, &wined3d_null_parent_ops);
1219 ERR("Wine logo requested, but failed to create surface\n");
1224 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1225 if(FAILED(hr)) goto out;
1226 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1227 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1229 colorkey.dwColorSpaceLowValue = 0;
1230 colorkey.dwColorSpaceHighValue = 0;
1231 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1233 /* Fill the surface with a white color to show that wined3d is there */
1234 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1238 if (dcb) DeleteDC(dcb);
1239 if (hbm) DeleteObject(hbm);
1242 /* Context activation is done by the caller. */
1243 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1245 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1247 /* Under DirectX you can have texture stage operations even if no texture is
1248 bound, whereas opengl will only do texture operations when a valid texture is
1249 bound. We emulate this by creating dummy textures and binding them to each
1250 texture stage, but disable all stages by default. Hence if a stage is enabled
1251 then the default texture will kick in until replaced by a SetTexture call */
1254 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1256 /* The dummy texture does not have client storage backing */
1257 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1258 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1261 for (i = 0; i < gl_info->limits.textures; ++i)
1263 GLubyte white = 255;
1265 /* Make appropriate texture active */
1266 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1267 checkGLcall("glActiveTextureARB");
1269 /* Generate an opengl texture name */
1270 glGenTextures(1, &This->dummyTextureName[i]);
1271 checkGLcall("glGenTextures");
1272 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1274 /* Generate a dummy 2d texture (not using 1d because they cause many
1275 * DRI drivers fall back to sw) */
1276 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1277 checkGLcall("glBindTexture");
1279 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1280 checkGLcall("glTexImage2D");
1283 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1285 /* Reenable because if supported it is enabled by default */
1286 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1287 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1293 /* Context activation is done by the caller. */
1294 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1297 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1298 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1301 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1304 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1305 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1308 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1309 IWineD3DSwapChainImpl *swapchain = NULL;
1310 struct wined3d_context *context;
1315 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1317 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1318 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1320 if (!pPresentationParameters->Windowed)
1322 This->focus_window = This->createParms.hFocusWindow;
1323 if (!This->focus_window) This->focus_window = pPresentationParameters->hDeviceWindow;
1324 if (!wined3d_register_window(This->focus_window, This))
1326 ERR("Failed to register window %p.\n", This->focus_window);
1331 TRACE("(%p) : Creating stateblock\n", This);
1332 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1333 hr = IWineD3DDevice_CreateStateBlock(iface,
1335 (IWineD3DStateBlock **)&This->stateBlock,
1337 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1338 WARN("Failed to create stateblock\n");
1341 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1342 This->updateStateBlock = This->stateBlock;
1343 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1345 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1346 sizeof(IWineD3DSurface *) * gl_info->limits.buffers);
1347 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1348 sizeof(GLenum) * gl_info->limits.buffers);
1350 This->NumberOfPalettes = 1;
1351 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1352 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1353 ERR("Out of memory!\n");
1357 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1358 if(!This->palettes[0]) {
1359 ERR("Out of memory!\n");
1363 for (i = 0; i < 256; ++i) {
1364 This->palettes[0][i].peRed = 0xFF;
1365 This->palettes[0][i].peGreen = 0xFF;
1366 This->palettes[0][i].peBlue = 0xFF;
1367 This->palettes[0][i].peFlags = 0xFF;
1369 This->currentPalette = 0;
1371 /* Initialize the texture unit mapping to a 1:1 mapping */
1372 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1374 if (state < gl_info->limits.fragment_samplers)
1376 This->texUnitMap[state] = state;
1377 This->rev_tex_unit_map[state] = state;
1379 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1380 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1384 if (This->focus_window) SetFocus(This->focus_window);
1386 /* Setup the implicit swapchain. This also initializes a context. */
1387 TRACE("Creating implicit swapchain\n");
1388 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1389 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1392 WARN("Failed to create implicit swapchain\n");
1396 This->NumberOfSwapChains = 1;
1397 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1398 if(!This->swapchains) {
1399 ERR("Out of memory!\n");
1402 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1404 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1405 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1406 This->render_targets[0] = swapchain->backBuffer[0];
1409 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1410 This->render_targets[0] = swapchain->frontBuffer;
1412 IWineD3DSurface_AddRef(This->render_targets[0]);
1414 /* Depth Stencil support */
1415 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1416 if (NULL != This->stencilBufferTarget) {
1417 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1420 hr = This->shader_backend->shader_alloc_private(iface);
1422 TRACE("Shader private data couldn't be allocated\n");
1425 hr = This->frag_pipe->alloc_private(iface);
1427 TRACE("Fragment pipeline private data couldn't be allocated\n");
1430 hr = This->blitter->alloc_private(iface);
1432 TRACE("Blitter private data couldn't be allocated\n");
1436 /* Set up some starting GL setup */
1438 /* Setup all the devices defaults */
1439 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1441 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1443 create_dummy_textures(This);
1447 /* Initialize the current view state */
1448 This->view_ident = 1;
1449 This->contexts[0]->last_was_rhw = 0;
1450 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1451 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1453 switch(wined3d_settings.offscreen_rendering_mode) {
1455 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1459 This->offscreenBuffer = GL_BACK;
1462 case ORM_BACKBUFFER:
1464 if (context_get_current()->aux_buffers > 0)
1466 TRACE("Using auxilliary buffer for offscreen rendering\n");
1467 This->offscreenBuffer = GL_AUX0;
1469 TRACE("Using back buffer for offscreen rendering\n");
1470 This->offscreenBuffer = GL_BACK;
1475 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1478 context_release(context);
1480 /* Clear the screen */
1481 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1482 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1485 This->d3d_initialized = TRUE;
1487 if(wined3d_settings.logo) {
1488 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1490 This->highest_dirty_ps_const = 0;
1491 This->highest_dirty_vs_const = 0;
1495 HeapFree(GetProcessHeap(), 0, This->render_targets);
1496 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1497 HeapFree(GetProcessHeap(), 0, This->swapchains);
1498 This->NumberOfSwapChains = 0;
1499 if(This->palettes) {
1500 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1501 HeapFree(GetProcessHeap(), 0, This->palettes);
1503 This->NumberOfPalettes = 0;
1505 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1507 if(This->stateBlock) {
1508 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1509 This->stateBlock = NULL;
1511 if (This->blit_priv) {
1512 This->blitter->free_private(iface);
1514 if (This->fragment_priv) {
1515 This->frag_pipe->free_private(iface);
1517 if (This->shader_priv) {
1518 This->shader_backend->shader_free_private(iface);
1520 if (This->focus_window) wined3d_unregister_window(This->focus_window);
1524 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1525 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1528 IWineD3DSwapChainImpl *swapchain = NULL;
1531 /* Setup the implicit swapchain */
1532 TRACE("Creating implicit swapchain\n");
1533 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1534 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1537 WARN("Failed to create implicit swapchain\n");
1541 This->NumberOfSwapChains = 1;
1542 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1543 if(!This->swapchains) {
1544 ERR("Out of memory!\n");
1547 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1551 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1555 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1557 IWineD3DResource_UnLoad(resource);
1558 IWineD3DResource_Release(resource);
1562 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1563 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1566 const struct wined3d_gl_info *gl_info;
1567 struct wined3d_context *context;
1570 TRACE("(%p)\n", This);
1572 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1574 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1575 * it was created. Thus make sure a context is active for the glDelete* calls
1577 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1578 gl_info = context->gl_info;
1580 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1582 /* Unload resources */
1583 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1585 TRACE("Deleting high order patches\n");
1586 for(i = 0; i < PATCHMAP_SIZE; i++) {
1587 struct list *e1, *e2;
1588 struct WineD3DRectPatch *patch;
1589 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1590 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1591 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1595 /* Delete the palette conversion shader if it is around */
1596 if(This->paletteConversionShader) {
1598 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
1600 This->paletteConversionShader = 0;
1603 /* Delete the pbuffer context if there is any */
1604 if(This->pbufferContext) context_destroy(This, This->pbufferContext);
1606 /* Delete the mouse cursor texture */
1607 if(This->cursorTexture) {
1609 glDeleteTextures(1, &This->cursorTexture);
1611 This->cursorTexture = 0;
1614 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1615 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1617 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1618 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1621 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1622 * private data, it might contain opengl pointers
1624 if(This->depth_blt_texture) {
1626 glDeleteTextures(1, &This->depth_blt_texture);
1628 This->depth_blt_texture = 0;
1630 if (This->depth_blt_rb) {
1632 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1634 This->depth_blt_rb = 0;
1635 This->depth_blt_rb_w = 0;
1636 This->depth_blt_rb_h = 0;
1639 /* Release the update stateblock */
1640 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1641 if(This->updateStateBlock != This->stateBlock)
1642 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1644 This->updateStateBlock = NULL;
1646 { /* because were not doing proper internal refcounts releasing the primary state block
1647 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1648 to set this->stateBlock = NULL; first */
1649 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1650 This->stateBlock = NULL;
1652 /* Release the stateblock */
1653 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1654 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1658 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1659 This->blitter->free_private(iface);
1660 This->frag_pipe->free_private(iface);
1661 This->shader_backend->shader_free_private(iface);
1663 /* Release the buffers (with sanity checks)*/
1664 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1665 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1666 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
1667 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
1669 This->stencilBufferTarget = NULL;
1671 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1672 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1673 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1675 TRACE("Setting rendertarget to NULL\n");
1676 This->render_targets[0] = NULL;
1678 if (This->auto_depth_stencil_buffer) {
1679 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
1681 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1683 This->auto_depth_stencil_buffer = NULL;
1686 context_release(context);
1688 for(i=0; i < This->NumberOfSwapChains; i++) {
1689 TRACE("Releasing the implicit swapchain %d\n", i);
1690 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1691 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1695 HeapFree(GetProcessHeap(), 0, This->swapchains);
1696 This->swapchains = NULL;
1697 This->NumberOfSwapChains = 0;
1699 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1700 HeapFree(GetProcessHeap(), 0, This->palettes);
1701 This->palettes = NULL;
1702 This->NumberOfPalettes = 0;
1704 HeapFree(GetProcessHeap(), 0, This->render_targets);
1705 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1706 This->render_targets = NULL;
1707 This->draw_buffers = NULL;
1709 This->d3d_initialized = FALSE;
1711 if (This->focus_window) wined3d_unregister_window(This->focus_window);
1716 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1720 for(i=0; i < This->NumberOfSwapChains; i++) {
1721 TRACE("Releasing the implicit swapchain %d\n", i);
1722 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1723 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1727 HeapFree(GetProcessHeap(), 0, This->swapchains);
1728 This->swapchains = NULL;
1729 This->NumberOfSwapChains = 0;
1733 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1734 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1735 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1737 * There is no way to deactivate thread safety once it is enabled.
1739 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1742 /*For now just store the flag(needed in case of ddraw) */
1743 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1746 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1747 const WINED3DDISPLAYMODE* pMode) {
1749 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1751 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1754 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1756 /* Resize the screen even without a window:
1757 * The app could have unset it with SetCooperativeLevel, but not called
1758 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1759 * but we don't have any hwnd
1762 memset(&devmode, 0, sizeof(devmode));
1763 devmode.dmSize = sizeof(devmode);
1764 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1765 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1766 devmode.dmPelsWidth = pMode->Width;
1767 devmode.dmPelsHeight = pMode->Height;
1769 devmode.dmDisplayFrequency = pMode->RefreshRate;
1770 if (pMode->RefreshRate != 0) {
1771 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1774 /* Only change the mode if necessary */
1775 if( (This->ddraw_width == pMode->Width) &&
1776 (This->ddraw_height == pMode->Height) &&
1777 (This->ddraw_format == pMode->Format) &&
1778 (pMode->RefreshRate == 0) ) {
1782 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1783 if (ret != DISP_CHANGE_SUCCESSFUL) {
1784 if(devmode.dmDisplayFrequency != 0) {
1785 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1786 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1787 devmode.dmDisplayFrequency = 0;
1788 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1790 if(ret != DISP_CHANGE_SUCCESSFUL) {
1791 return WINED3DERR_NOTAVAILABLE;
1795 /* Store the new values */
1796 This->ddraw_width = pMode->Width;
1797 This->ddraw_height = pMode->Height;
1798 This->ddraw_format = pMode->Format;
1800 /* And finally clip mouse to our screen */
1801 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1802 ClipCursor(&clip_rc);
1807 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1809 *ppD3D = This->wined3d;
1810 TRACE("Returning %p.\n", *ppD3D);
1811 IWineD3D_AddRef(*ppD3D);
1815 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1818 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1819 (This->adapter->TextureRam/(1024*1024)),
1820 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
1821 /* return simulated texture memory left */
1822 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
1826 * Get / Set Stream Source
1828 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
1829 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
1831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1832 IWineD3DBuffer *oldSrc;
1834 if (StreamNumber >= MAX_STREAMS) {
1835 WARN("Stream out of range %d\n", StreamNumber);
1836 return WINED3DERR_INVALIDCALL;
1837 } else if(OffsetInBytes & 0x3) {
1838 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
1839 return WINED3DERR_INVALIDCALL;
1842 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
1843 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
1845 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
1847 if(oldSrc == pStreamData &&
1848 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
1849 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
1850 TRACE("Application is setting the old values over, nothing to do\n");
1854 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
1856 This->updateStateBlock->streamStride[StreamNumber] = Stride;
1857 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
1860 /* Handle recording of state blocks */
1861 if (This->isRecordingState) {
1862 TRACE("Recording... not performing anything\n");
1863 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
1864 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
1868 if (pStreamData != NULL) {
1869 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
1870 IWineD3DBuffer_AddRef(pStreamData);
1872 if (oldSrc != NULL) {
1873 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
1874 IWineD3DBuffer_Release(oldSrc);
1877 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
1882 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
1883 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
1885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1887 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
1888 This->stateBlock->streamSource[StreamNumber],
1889 This->stateBlock->streamOffset[StreamNumber],
1890 This->stateBlock->streamStride[StreamNumber]);
1892 if (StreamNumber >= MAX_STREAMS) {
1893 WARN("Stream out of range %d\n", StreamNumber);
1894 return WINED3DERR_INVALIDCALL;
1896 *pStream = This->stateBlock->streamSource[StreamNumber];
1897 *pStride = This->stateBlock->streamStride[StreamNumber];
1899 *pOffset = This->stateBlock->streamOffset[StreamNumber];
1902 if (*pStream != NULL) {
1903 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
1908 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
1909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1910 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
1911 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
1913 /* Verify input at least in d3d9 this is invalid*/
1914 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
1915 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
1916 return WINED3DERR_INVALIDCALL;
1918 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
1919 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
1920 return WINED3DERR_INVALIDCALL;
1923 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
1924 return WINED3DERR_INVALIDCALL;
1927 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
1928 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
1930 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
1931 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
1933 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
1934 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
1935 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
1941 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
1942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1944 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
1945 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
1947 TRACE("(%p) : returning %d\n", This, *Divider);
1953 * Get / Set & Multiply Transform
1955 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
1956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1958 /* Most of this routine, comments included copied from ddraw tree initially: */
1959 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
1961 /* Handle recording of state blocks */
1962 if (This->isRecordingState) {
1963 TRACE("Recording... not performing anything\n");
1964 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
1965 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
1970 * If the new matrix is the same as the current one,
1971 * we cut off any further processing. this seems to be a reasonable
1972 * optimization because as was noticed, some apps (warcraft3 for example)
1973 * tend towards setting the same matrix repeatedly for some reason.
1975 * From here on we assume that the new matrix is different, wherever it matters.
1977 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
1978 TRACE("The app is setting the same matrix over again\n");
1981 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
1985 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
1986 where ViewMat = Camera space, WorldMat = world space.
1988 In OpenGL, camera and world space is combined into GL_MODELVIEW
1989 matrix. The Projection matrix stay projection matrix.
1992 /* Capture the times we can just ignore the change for now */
1993 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
1994 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
1995 /* Handled by the state manager */
1998 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2002 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2004 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2005 *pMatrix = This->stateBlock->transforms[State];
2009 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2010 const WINED3DMATRIX *mat = NULL;
2013 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2014 * below means it will be recorded in a state block change, but it
2015 * works regardless where it is recorded.
2016 * If this is found to be wrong, change to StateBlock.
2018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2019 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2021 if (State <= HIGHEST_TRANSFORMSTATE)
2023 mat = &This->updateStateBlock->transforms[State];
2025 FIXME("Unhandled transform state!!\n");
2028 multiply_matrix(&temp, mat, pMatrix);
2030 /* Apply change via set transform - will reapply to eg. lights this way */
2031 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2037 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2038 you can reference any indexes you want as long as that number max are enabled at any
2039 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2040 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2041 but when recording, just build a chain pretty much of commands to be replayed. */
2043 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2045 struct wined3d_light_info *object = NULL;
2046 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2050 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2052 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2056 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2057 return WINED3DERR_INVALIDCALL;
2060 switch(pLight->Type) {
2061 case WINED3DLIGHT_POINT:
2062 case WINED3DLIGHT_SPOT:
2063 case WINED3DLIGHT_PARALLELPOINT:
2064 case WINED3DLIGHT_GLSPOT:
2065 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2068 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2070 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2071 return WINED3DERR_INVALIDCALL;
2075 case WINED3DLIGHT_DIRECTIONAL:
2076 /* Ignores attenuation */
2080 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2081 return WINED3DERR_INVALIDCALL;
2084 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2086 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2087 if(object->OriginalIndex == Index) break;
2092 TRACE("Adding new light\n");
2093 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2095 ERR("Out of memory error when allocating a light\n");
2096 return E_OUTOFMEMORY;
2098 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2099 object->glIndex = -1;
2100 object->OriginalIndex = Index;
2103 /* Initialize the object */
2104 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,
2105 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2106 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2107 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2108 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2109 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2110 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2112 /* Save away the information */
2113 object->OriginalParms = *pLight;
2115 switch (pLight->Type) {
2116 case WINED3DLIGHT_POINT:
2118 object->lightPosn[0] = pLight->Position.x;
2119 object->lightPosn[1] = pLight->Position.y;
2120 object->lightPosn[2] = pLight->Position.z;
2121 object->lightPosn[3] = 1.0f;
2122 object->cutoff = 180.0f;
2126 case WINED3DLIGHT_DIRECTIONAL:
2128 object->lightPosn[0] = -pLight->Direction.x;
2129 object->lightPosn[1] = -pLight->Direction.y;
2130 object->lightPosn[2] = -pLight->Direction.z;
2131 object->lightPosn[3] = 0.0f;
2132 object->exponent = 0.0f;
2133 object->cutoff = 180.0f;
2136 case WINED3DLIGHT_SPOT:
2138 object->lightPosn[0] = pLight->Position.x;
2139 object->lightPosn[1] = pLight->Position.y;
2140 object->lightPosn[2] = pLight->Position.z;
2141 object->lightPosn[3] = 1.0f;
2144 object->lightDirn[0] = pLight->Direction.x;
2145 object->lightDirn[1] = pLight->Direction.y;
2146 object->lightDirn[2] = pLight->Direction.z;
2147 object->lightDirn[3] = 1.0f;
2150 * opengl-ish and d3d-ish spot lights use too different models for the
2151 * light "intensity" as a function of the angle towards the main light direction,
2152 * so we only can approximate very roughly.
2153 * however spot lights are rather rarely used in games (if ever used at all).
2154 * furthermore if still used, probably nobody pays attention to such details.
2156 if (pLight->Falloff == 0) {
2157 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2158 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2159 * will always be 1.0 for both of them, and we don't have to care for the
2160 * rest of the rather complex calculation
2162 object->exponent = 0.0f;
2164 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2165 if (rho < 0.0001f) rho = 0.0001f;
2166 object->exponent = -0.3f/logf(cosf(rho/2));
2168 if (object->exponent > 128.0f)
2170 object->exponent = 128.0f;
2172 object->cutoff = pLight->Phi*90/M_PI;
2178 FIXME("Unrecognized light type %d\n", pLight->Type);
2181 /* Update the live definitions if the light is currently assigned a glIndex */
2182 if (object->glIndex != -1 && !This->isRecordingState) {
2183 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2188 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2190 struct wined3d_light_info *lightInfo = NULL;
2191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2192 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2194 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2196 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2198 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2199 if(lightInfo->OriginalIndex == Index) break;
2203 if (lightInfo == NULL) {
2204 TRACE("Light information requested but light not defined\n");
2205 return WINED3DERR_INVALIDCALL;
2208 *pLight = lightInfo->OriginalParms;
2213 * Get / Set Light Enable
2214 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2216 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2218 struct wined3d_light_info *lightInfo = NULL;
2219 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2220 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2222 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2224 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2226 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2227 if(lightInfo->OriginalIndex == Index) break;
2230 TRACE("Found light: %p\n", lightInfo);
2232 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2233 if (lightInfo == NULL) {
2235 TRACE("Light enabled requested but light not defined, so defining one!\n");
2236 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2238 /* Search for it again! Should be fairly quick as near head of list */
2239 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2241 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2242 if(lightInfo->OriginalIndex == Index) break;
2245 if (lightInfo == NULL) {
2246 FIXME("Adding default lights has failed dismally\n");
2247 return WINED3DERR_INVALIDCALL;
2252 if(lightInfo->glIndex != -1) {
2253 if(!This->isRecordingState) {
2254 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2257 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2258 lightInfo->glIndex = -1;
2260 TRACE("Light already disabled, nothing to do\n");
2262 lightInfo->enabled = FALSE;
2264 lightInfo->enabled = TRUE;
2265 if (lightInfo->glIndex != -1) {
2267 TRACE("Nothing to do as light was enabled\n");
2270 /* Find a free gl light */
2271 for(i = 0; i < This->maxConcurrentLights; i++) {
2272 if(This->updateStateBlock->activeLights[i] == NULL) {
2273 This->updateStateBlock->activeLights[i] = lightInfo;
2274 lightInfo->glIndex = i;
2278 if(lightInfo->glIndex == -1) {
2279 /* Our tests show that Windows returns D3D_OK in this situation, even with
2280 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2281 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2282 * as well for those lights.
2284 * TODO: Test how this affects rendering
2286 WARN("Too many concurrently active lights\n");
2290 /* i == lightInfo->glIndex */
2291 if(!This->isRecordingState) {
2292 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2300 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2302 struct wined3d_light_info *lightInfo = NULL;
2303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2305 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2306 TRACE("(%p) : for idx(%d)\n", This, Index);
2308 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2310 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2311 if(lightInfo->OriginalIndex == Index) break;
2315 if (lightInfo == NULL) {
2316 TRACE("Light enabled state requested but light not defined\n");
2317 return WINED3DERR_INVALIDCALL;
2319 /* true is 128 according to SetLightEnable */
2320 *pEnable = lightInfo->enabled ? 128 : 0;
2325 * Get / Set Clip Planes
2327 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2329 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2331 /* Validate Index */
2332 if (Index >= This->adapter->gl_info.limits.clipplanes)
2334 TRACE("Application has requested clipplane this device doesn't support\n");
2335 return WINED3DERR_INVALIDCALL;
2338 This->updateStateBlock->changed.clipplane |= 1 << Index;
2340 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2341 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2342 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2343 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2344 TRACE("Application is setting old values over, nothing to do\n");
2348 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2349 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2350 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2351 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2353 /* Handle recording of state blocks */
2354 if (This->isRecordingState) {
2355 TRACE("Recording... not performing anything\n");
2359 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2364 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2366 TRACE("(%p) : for idx %d\n", This, Index);
2368 /* Validate Index */
2369 if (Index >= This->adapter->gl_info.limits.clipplanes)
2371 TRACE("Application has requested clipplane this device doesn't support\n");
2372 return WINED3DERR_INVALIDCALL;
2375 pPlane[0] = This->stateBlock->clipplane[Index][0];
2376 pPlane[1] = This->stateBlock->clipplane[Index][1];
2377 pPlane[2] = This->stateBlock->clipplane[Index][2];
2378 pPlane[3] = This->stateBlock->clipplane[Index][3];
2383 * Get / Set Clip Plane Status
2384 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2386 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2388 FIXME("(%p) : stub\n", This);
2389 if (NULL == pClipStatus) {
2390 return WINED3DERR_INVALIDCALL;
2392 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2393 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2397 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2399 FIXME("(%p) : stub\n", This);
2400 if (NULL == pClipStatus) {
2401 return WINED3DERR_INVALIDCALL;
2403 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2404 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2409 * Get / Set Material
2411 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2414 This->updateStateBlock->changed.material = TRUE;
2415 This->updateStateBlock->material = *pMaterial;
2417 /* Handle recording of state blocks */
2418 if (This->isRecordingState) {
2419 TRACE("Recording... not performing anything\n");
2423 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2427 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2429 *pMaterial = This->updateStateBlock->material;
2430 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2431 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2432 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2433 pMaterial->Ambient.b, pMaterial->Ambient.a);
2434 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2435 pMaterial->Specular.b, pMaterial->Specular.a);
2436 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2437 pMaterial->Emissive.b, pMaterial->Emissive.a);
2438 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2446 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2447 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2449 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2450 IWineD3DBuffer *oldIdxs;
2452 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2453 oldIdxs = This->updateStateBlock->pIndexData;
2455 This->updateStateBlock->changed.indices = TRUE;
2456 This->updateStateBlock->pIndexData = pIndexData;
2457 This->updateStateBlock->IndexFmt = fmt;
2459 /* Handle recording of state blocks */
2460 if (This->isRecordingState) {
2461 TRACE("Recording... not performing anything\n");
2462 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2463 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2467 if(oldIdxs != pIndexData) {
2468 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2470 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2471 IWineD3DBuffer_AddRef(pIndexData);
2474 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2475 IWineD3DBuffer_Release(oldIdxs);
2482 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2486 *ppIndexData = This->stateBlock->pIndexData;
2488 /* up ref count on ppindexdata */
2490 IWineD3DBuffer_AddRef(*ppIndexData);
2491 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2493 TRACE("(%p) No index data set\n", This);
2495 TRACE("Returning %p\n", *ppIndexData);
2500 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2501 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2503 TRACE("(%p)->(%d)\n", This, BaseIndex);
2505 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2506 TRACE("Application is setting the old value over, nothing to do\n");
2510 This->updateStateBlock->baseVertexIndex = BaseIndex;
2512 if (This->isRecordingState) {
2513 TRACE("Recording... not performing anything\n");
2516 /* The base vertex index affects the stream sources */
2517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2521 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2523 TRACE("(%p) : base_index %p\n", This, base_index);
2525 *base_index = This->stateBlock->baseVertexIndex;
2527 TRACE("Returning %u\n", *base_index);
2533 * Get / Set Viewports
2535 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2538 TRACE("(%p)\n", This);
2539 This->updateStateBlock->changed.viewport = TRUE;
2540 This->updateStateBlock->viewport = *pViewport;
2542 /* Handle recording of state blocks */
2543 if (This->isRecordingState) {
2544 TRACE("Recording... not performing anything\n");
2548 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2549 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2551 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2556 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2558 TRACE("(%p)\n", This);
2559 *pViewport = This->stateBlock->viewport;
2564 * Get / Set Render States
2565 * TODO: Verify against dx9 definitions
2567 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2570 DWORD oldValue = This->stateBlock->renderState[State];
2572 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2574 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2575 This->updateStateBlock->renderState[State] = Value;
2577 /* Handle recording of state blocks */
2578 if (This->isRecordingState) {
2579 TRACE("Recording... not performing anything\n");
2583 /* Compared here and not before the assignment to allow proper stateblock recording */
2584 if(Value == oldValue) {
2585 TRACE("Application is setting the old value over, nothing to do\n");
2587 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2593 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2595 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2596 *pValue = This->stateBlock->renderState[State];
2601 * Get / Set Sampler States
2602 * TODO: Verify against dx9 definitions
2605 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2609 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2610 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2612 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2613 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2616 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2617 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2618 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2621 * SetSampler is designed to allow for more than the standard up to 8 textures
2622 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2623 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2625 * http://developer.nvidia.com/object/General_FAQ.html#t6
2627 * There are two new settings for GForce
2629 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2630 * and the texture one:
2631 * GL_MAX_TEXTURE_COORDS_ARB.
2632 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2635 oldValue = This->stateBlock->samplerState[Sampler][Type];
2636 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2637 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2639 /* Handle recording of state blocks */
2640 if (This->isRecordingState) {
2641 TRACE("Recording... not performing anything\n");
2645 if(oldValue == Value) {
2646 TRACE("Application is setting the old value over, nothing to do\n");
2650 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2655 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2658 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2659 This, Sampler, debug_d3dsamplerstate(Type), Type);
2661 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2662 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2665 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2666 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2667 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2669 *Value = This->stateBlock->samplerState[Sampler][Type];
2670 TRACE("(%p) : Returning %#x\n", This, *Value);
2675 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2678 This->updateStateBlock->changed.scissorRect = TRUE;
2679 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2680 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2683 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2685 if(This->isRecordingState) {
2686 TRACE("Recording... not performing anything\n");
2690 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2695 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2698 *pRect = This->updateStateBlock->scissorRect;
2699 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2703 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2705 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2707 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2709 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2710 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2712 This->updateStateBlock->vertexDecl = pDecl;
2713 This->updateStateBlock->changed.vertexDecl = TRUE;
2715 if (This->isRecordingState) {
2716 TRACE("Recording... not performing anything\n");
2718 } else if(pDecl == oldDecl) {
2719 /* Checked after the assignment to allow proper stateblock recording */
2720 TRACE("Application is setting the old declaration over, nothing to do\n");
2724 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2728 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2731 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2733 *ppDecl = This->stateBlock->vertexDecl;
2734 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2738 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2740 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2742 This->updateStateBlock->vertexShader = pShader;
2743 This->updateStateBlock->changed.vertexShader = TRUE;
2745 if (This->isRecordingState) {
2746 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2747 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2748 TRACE("Recording... not performing anything\n");
2750 } else if(oldShader == pShader) {
2751 /* Checked here to allow proper stateblock recording */
2752 TRACE("App is setting the old shader over, nothing to do\n");
2756 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2757 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2758 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2760 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2765 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2768 if (NULL == ppShader) {
2769 return WINED3DERR_INVALIDCALL;
2771 *ppShader = This->stateBlock->vertexShader;
2772 if( NULL != *ppShader)
2773 IWineD3DVertexShader_AddRef(*ppShader);
2775 TRACE("(%p) : returning %p\n", This, *ppShader);
2779 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2780 IWineD3DDevice *iface,
2782 CONST BOOL *srcData,
2785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2786 unsigned int i, cnt = min(count, MAX_CONST_B - start);
2788 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2789 iface, srcData, start, count);
2791 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
2793 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2794 for (i = 0; i < cnt; i++)
2795 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2797 for (i = start; i < cnt + start; ++i) {
2798 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
2801 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2806 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2807 IWineD3DDevice *iface,
2812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2813 int cnt = min(count, MAX_CONST_B - start);
2815 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2816 iface, dstData, start, count);
2818 if (dstData == NULL || cnt < 0)
2819 return WINED3DERR_INVALIDCALL;
2821 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2825 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2826 IWineD3DDevice *iface,
2831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2832 unsigned int i, cnt = min(count, MAX_CONST_I - start);
2834 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2835 iface, srcData, start, count);
2837 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
2839 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2840 for (i = 0; i < cnt; i++)
2841 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2842 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2844 for (i = start; i < cnt + start; ++i) {
2845 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
2848 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2853 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2854 IWineD3DDevice *iface,
2859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2860 int cnt = min(count, MAX_CONST_I - start);
2862 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2863 iface, dstData, start, count);
2865 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2866 return WINED3DERR_INVALIDCALL;
2868 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
2872 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
2873 IWineD3DDevice *iface,
2875 CONST float *srcData,
2878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2881 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2882 iface, srcData, start, count);
2884 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
2885 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
2886 return WINED3DERR_INVALIDCALL;
2888 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
2890 for (i = 0; i < count; i++)
2891 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
2892 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2895 if (!This->isRecordingState)
2897 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
2898 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2901 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
2902 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
2907 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
2908 IWineD3DDevice *iface,
2913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2914 int cnt = min(count, This->d3d_vshader_constantF - start);
2916 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2917 iface, dstData, start, count);
2919 if (dstData == NULL || cnt < 0)
2920 return WINED3DERR_INVALIDCALL;
2922 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
2926 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
2928 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
2930 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
2934 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
2936 DWORD i = This->rev_tex_unit_map[unit];
2937 DWORD j = This->texUnitMap[stage];
2939 This->texUnitMap[stage] = unit;
2940 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
2942 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
2945 This->rev_tex_unit_map[unit] = stage;
2946 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
2948 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
2952 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
2955 This->fixed_function_usage_map = 0;
2956 for (i = 0; i < MAX_TEXTURES; ++i) {
2957 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
2958 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
2959 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
2960 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
2961 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
2962 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
2963 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
2964 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
2966 if (color_op == WINED3DTOP_DISABLE) {
2967 /* Not used, and disable higher stages */
2971 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
2972 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
2973 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
2974 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
2975 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
2976 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
2977 This->fixed_function_usage_map |= (1 << i);
2980 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
2981 This->fixed_function_usage_map |= (1 << (i + 1));
2986 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
2987 unsigned int i, tex;
2990 device_update_fixed_function_usage_map(This);
2991 ffu_map = This->fixed_function_usage_map;
2993 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
2994 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
2995 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
2997 if (!(ffu_map & 1)) continue;
2999 if (This->texUnitMap[i] != i) {
3000 device_map_stage(This, i, i);
3001 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3002 markTextureStagesDirty(This, i);
3008 /* Now work out the mapping */
3010 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3012 if (!(ffu_map & 1)) continue;
3014 if (This->texUnitMap[i] != tex) {
3015 device_map_stage(This, i, tex);
3016 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3017 markTextureStagesDirty(This, i);
3024 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3025 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3026 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3027 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3030 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3031 if (sampler_type[i] && This->texUnitMap[i] != i)
3033 device_map_stage(This, i, i);
3034 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3035 if (i < gl_info->limits.texture_stages)
3037 markTextureStagesDirty(This, i);
3043 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3044 const DWORD *vshader_sampler_tokens, DWORD unit)
3046 DWORD current_mapping = This->rev_tex_unit_map[unit];
3048 /* Not currently used */
3049 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3051 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3052 /* Used by a fragment sampler */
3054 if (!pshader_sampler_tokens) {
3055 /* No pixel shader, check fixed function */
3056 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3059 /* Pixel shader, check the shader's sampler map */
3060 return !pshader_sampler_tokens[current_mapping];
3063 /* Used by a vertex sampler */
3064 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3067 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3068 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3069 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3070 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3071 int start = min(MAX_COMBINED_SAMPLERS, This->adapter->gl_info.limits.combined_samplers) - 1;
3075 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3077 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3078 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3079 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3082 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3083 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3084 if (vshader_sampler_type[i])
3086 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3088 /* Already mapped somewhere */
3092 while (start >= 0) {
3093 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3095 device_map_stage(This, vsampler_idx, start);
3096 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3108 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3109 BOOL vs = use_vs(This->stateBlock);
3110 BOOL ps = use_ps(This->stateBlock);
3113 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3114 * that would be really messy and require shader recompilation
3115 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3116 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3119 device_map_psamplers(This);
3121 device_map_fixed_function_samplers(This);
3125 device_map_vsamplers(This, ps);
3129 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3131 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3132 This->updateStateBlock->pixelShader = pShader;
3133 This->updateStateBlock->changed.pixelShader = TRUE;
3135 /* Handle recording of state blocks */
3136 if (This->isRecordingState) {
3137 TRACE("Recording... not performing anything\n");
3140 if (This->isRecordingState) {
3141 TRACE("Recording... not performing anything\n");
3142 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3143 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3147 if(pShader == oldShader) {
3148 TRACE("App is setting the old pixel shader over, nothing to do\n");
3152 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3153 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3155 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3156 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3161 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3164 if (NULL == ppShader) {
3165 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3166 return WINED3DERR_INVALIDCALL;
3169 *ppShader = This->stateBlock->pixelShader;
3170 if (NULL != *ppShader) {
3171 IWineD3DPixelShader_AddRef(*ppShader);
3173 TRACE("(%p) : returning %p\n", This, *ppShader);
3177 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3178 IWineD3DDevice *iface,
3180 CONST BOOL *srcData,
3183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3184 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3186 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3187 iface, srcData, start, count);
3189 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3191 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3192 for (i = 0; i < cnt; i++)
3193 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3195 for (i = start; i < cnt + start; ++i) {
3196 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3199 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3204 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3205 IWineD3DDevice *iface,
3210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3211 int cnt = min(count, MAX_CONST_B - start);
3213 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3214 iface, dstData, start, count);
3216 if (dstData == NULL || cnt < 0)
3217 return WINED3DERR_INVALIDCALL;
3219 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3223 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3224 IWineD3DDevice *iface,
3229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3230 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3232 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3233 iface, srcData, start, count);
3235 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3237 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3238 for (i = 0; i < cnt; i++)
3239 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3240 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3242 for (i = start; i < cnt + start; ++i) {
3243 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3246 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3251 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3252 IWineD3DDevice *iface,
3257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3258 int cnt = min(count, MAX_CONST_I - start);
3260 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3261 iface, dstData, start, count);
3263 if (dstData == NULL || cnt < 0)
3264 return WINED3DERR_INVALIDCALL;
3266 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3270 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3271 IWineD3DDevice *iface,
3273 CONST float *srcData,
3276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3279 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3280 iface, srcData, start, count);
3282 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3283 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3284 return WINED3DERR_INVALIDCALL;
3286 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3288 for (i = 0; i < count; i++)
3289 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3290 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3293 if (!This->isRecordingState)
3295 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3296 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3299 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3300 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3305 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3306 IWineD3DDevice *iface,
3311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3312 int cnt = min(count, This->d3d_pshader_constantF - start);
3314 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3315 iface, dstData, start, count);
3317 if (dstData == NULL || cnt < 0)
3318 return WINED3DERR_INVALIDCALL;
3320 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3324 /* Context activation is done by the caller. */
3325 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3326 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3327 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3330 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3331 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3334 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3338 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3340 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3343 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3345 ERR("Source has no position mask\n");
3346 return WINED3DERR_INVALIDCALL;
3349 /* We might access VBOs from this code, so hold the lock */
3352 if (dest->resource.allocatedMemory == NULL) {
3353 buffer_get_sysmem(dest);
3356 /* Get a pointer into the destination vbo(create one if none exists) and
3357 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3359 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3361 dest->flags |= WINED3D_BUFFER_CREATEBO;
3362 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3365 if (dest->buffer_object)
3367 unsigned char extrabytes = 0;
3368 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3369 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3370 * this may write 4 extra bytes beyond the area that should be written
3372 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3373 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3374 if(!dest_conv_addr) {
3375 ERR("Out of memory\n");
3376 /* Continue without storing converted vertices */
3378 dest_conv = dest_conv_addr;
3382 * a) WINED3DRS_CLIPPING is enabled
3383 * b) WINED3DVOP_CLIP is passed
3385 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3386 static BOOL warned = FALSE;
3388 * The clipping code is not quite correct. Some things need
3389 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3390 * so disable clipping for now.
3391 * (The graphics in Half-Life are broken, and my processvertices
3392 * test crashes with IDirect3DDevice3)
3398 FIXME("Clipping is broken and disabled for now\n");
3400 } else doClip = FALSE;
3401 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3403 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3406 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3407 WINED3DTS_PROJECTION,
3409 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3410 WINED3DTS_WORLDMATRIX(0),
3413 TRACE("View mat:\n");
3414 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);
3415 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);
3416 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);
3417 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);
3419 TRACE("Proj mat:\n");
3420 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);
3421 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);
3422 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);
3423 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);
3425 TRACE("World mat:\n");
3426 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);
3427 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);
3428 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);
3429 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);
3431 /* Get the viewport */
3432 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3433 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3434 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3436 multiply_matrix(&mat,&view_mat,&world_mat);
3437 multiply_matrix(&mat,&proj_mat,&mat);
3439 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3441 for (i = 0; i < dwCount; i+= 1) {
3442 unsigned int tex_index;
3444 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3445 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3446 /* The position first */
3447 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3448 const float *p = (const float *)(element->data + i * element->stride);
3450 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3452 /* Multiplication with world, view and projection matrix */
3453 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);
3454 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);
3455 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);
3456 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);
3458 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3460 /* WARNING: The following things are taken from d3d7 and were not yet checked
3461 * against d3d8 or d3d9!
3464 /* Clipping conditions: From msdn
3466 * A vertex is clipped if it does not match the following requirements
3470 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3472 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3473 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3478 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3479 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3482 /* "Normal" viewport transformation (not clipped)
3483 * 1) The values are divided by rhw
3484 * 2) The y axis is negative, so multiply it with -1
3485 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3486 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3487 * 4) Multiply x with Width/2 and add Width/2
3488 * 5) The same for the height
3489 * 6) Add the viewpoint X and Y to the 2D coordinates and
3490 * The minimum Z value to z
3491 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3493 * Well, basically it's simply a linear transformation into viewport
3505 z *= vp.MaxZ - vp.MinZ;
3507 x += vp.Width / 2 + vp.X;
3508 y += vp.Height / 2 + vp.Y;
3513 /* That vertex got clipped
3514 * Contrary to OpenGL it is not dropped completely, it just
3515 * undergoes a different calculation.
3517 TRACE("Vertex got clipped\n");
3524 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3525 * outside of the main vertex buffer memory. That needs some more
3530 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3533 ( (float *) dest_ptr)[0] = x;
3534 ( (float *) dest_ptr)[1] = y;
3535 ( (float *) dest_ptr)[2] = z;
3536 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3538 dest_ptr += 3 * sizeof(float);
3540 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3541 dest_ptr += sizeof(float);
3546 ( (float *) dest_conv)[0] = x * w;
3547 ( (float *) dest_conv)[1] = y * w;
3548 ( (float *) dest_conv)[2] = z * w;
3549 ( (float *) dest_conv)[3] = w;
3551 dest_conv += 3 * sizeof(float);
3553 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3554 dest_conv += sizeof(float);
3558 if (DestFVF & WINED3DFVF_PSIZE) {
3559 dest_ptr += sizeof(DWORD);
3560 if(dest_conv) dest_conv += sizeof(DWORD);
3562 if (DestFVF & WINED3DFVF_NORMAL) {
3563 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3564 const float *normal = (const float *)(element->data + i * element->stride);
3565 /* AFAIK this should go into the lighting information */
3566 FIXME("Didn't expect the destination to have a normal\n");
3567 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3569 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3573 if (DestFVF & WINED3DFVF_DIFFUSE) {
3574 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3575 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3576 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3578 static BOOL warned = FALSE;
3581 ERR("No diffuse color in source, but destination has one\n");
3585 *( (DWORD *) dest_ptr) = 0xffffffff;
3586 dest_ptr += sizeof(DWORD);
3589 *( (DWORD *) dest_conv) = 0xffffffff;
3590 dest_conv += sizeof(DWORD);
3594 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3596 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3597 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3598 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3599 dest_conv += sizeof(DWORD);
3604 if (DestFVF & WINED3DFVF_SPECULAR)
3606 /* What's the color value in the feedback buffer? */
3607 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3608 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3609 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3611 static BOOL warned = FALSE;
3614 ERR("No specular color in source, but destination has one\n");
3618 *( (DWORD *) dest_ptr) = 0xFF000000;
3619 dest_ptr += sizeof(DWORD);
3622 *( (DWORD *) dest_conv) = 0xFF000000;
3623 dest_conv += sizeof(DWORD);
3627 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3629 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3630 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3631 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3632 dest_conv += sizeof(DWORD);
3637 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3638 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3639 const float *tex_coord = (const float *)(element->data + i * element->stride);
3640 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3642 ERR("No source texture, but destination requests one\n");
3643 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3644 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3647 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3649 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3656 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3657 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3658 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3659 dwCount * get_flexible_vertex_size(DestFVF),
3661 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3662 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3669 #undef copy_and_next
3671 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3672 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3676 struct wined3d_stream_info stream_info;
3677 struct wined3d_context *context;
3678 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3681 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3684 ERR("Output vertex declaration not implemented yet\n");
3687 /* Need any context to write to the vbo. */
3688 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
3690 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3691 * control the streamIsUP flag, thus restore it afterwards.
3693 This->stateBlock->streamIsUP = FALSE;
3694 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3695 This->stateBlock->streamIsUP = streamWasUP;
3697 if(vbo || SrcStartIndex) {
3699 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3700 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3702 * Also get the start index in, but only loop over all elements if there's something to add at all.
3704 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3706 struct wined3d_stream_info_element *e;
3708 if (!(stream_info.use_map & (1 << i))) continue;
3710 e = &stream_info.elements[i];
3711 if (e->buffer_object)
3713 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3714 e->buffer_object = 0;
3715 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3717 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3718 vb->buffer_object = 0;
3721 if (e->data) e->data += e->stride * SrcStartIndex;
3725 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3726 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3728 context_release(context);
3734 * Get / Set Texture Stage States
3735 * TODO: Verify against dx9 definitions
3737 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3739 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3740 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3742 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3744 if (Stage >= gl_info->limits.texture_stages)
3746 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3747 Stage, gl_info->limits.texture_stages - 1);
3751 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3752 This->updateStateBlock->textureState[Stage][Type] = Value;
3754 if (This->isRecordingState) {
3755 TRACE("Recording... not performing anything\n");
3759 /* Checked after the assignments to allow proper stateblock recording */
3760 if(oldValue == Value) {
3761 TRACE("App is setting the old value over, nothing to do\n");
3765 if(Stage > This->stateBlock->lowest_disabled_stage &&
3766 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3767 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3768 * Changes in other states are important on disabled stages too
3773 if(Type == WINED3DTSS_COLOROP) {
3776 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3777 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3778 * they have to be disabled
3780 * The current stage is dirtified below.
3782 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3783 TRACE("Additionally dirtifying stage %u\n", i);
3784 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3786 This->stateBlock->lowest_disabled_stage = Stage;
3787 TRACE("New lowest disabled: %u\n", Stage);
3788 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3789 /* Previously disabled stage enabled. Stages above it may need enabling
3790 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3791 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3793 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3796 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
3798 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3801 TRACE("Additionally dirtifying stage %u due to enable\n", i);
3802 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3804 This->stateBlock->lowest_disabled_stage = i;
3805 TRACE("New lowest disabled: %u\n", i);
3809 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3814 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3816 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3817 *pValue = This->updateStateBlock->textureState[Stage][Type];
3824 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
3825 DWORD stage, IWineD3DBaseTexture *texture)
3827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3828 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3829 IWineD3DBaseTexture *prev;
3831 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
3833 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
3834 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3836 /* Windows accepts overflowing this array... we do not. */
3837 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
3839 WARN("Ignoring invalid stage %u.\n", stage);
3843 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
3844 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
3846 WARN("Rejecting attempt to set scratch texture.\n");
3847 return WINED3DERR_INVALIDCALL;
3850 This->updateStateBlock->changed.textures |= 1 << stage;
3852 prev = This->updateStateBlock->textures[stage];
3853 TRACE("Previous texture %p.\n", prev);
3855 if (texture == prev)
3857 TRACE("App is setting the same texture again, nothing to do.\n");
3861 TRACE("Setting new texture to %p.\n", texture);
3862 This->updateStateBlock->textures[stage] = texture;
3864 if (This->isRecordingState)
3866 TRACE("Recording... not performing anything\n");
3868 if (texture) IWineD3DBaseTexture_AddRef(texture);
3869 if (prev) IWineD3DBaseTexture_Release(prev);
3876 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
3877 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
3878 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
3880 IWineD3DBaseTexture_AddRef(texture);
3882 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
3884 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3887 if (!prev && stage < gl_info->limits.texture_stages)
3889 /* The source arguments for color and alpha ops have different
3890 * meanings when a NULL texture is bound, so the COLOROP and
3891 * ALPHAOP have to be dirtified. */
3892 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
3893 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
3896 if (bind_count == 1) t->baseTexture.sampler = stage;
3901 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
3902 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
3904 IWineD3DBaseTexture_Release(prev);
3906 if (!texture && stage < gl_info->limits.texture_stages)
3908 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
3909 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
3912 if (bind_count && t->baseTexture.sampler == stage)
3916 /* Search for other stages the texture is bound to. Shouldn't
3917 * happen if applications bind textures to a single stage only. */
3918 TRACE("Searching for other stages the texture is bound to.\n");
3919 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
3921 if (This->updateStateBlock->textures[i] == prev)
3923 TRACE("Texture is also bound to stage %u.\n", i);
3924 t->baseTexture.sampler = i;
3931 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
3936 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
3937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3939 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
3941 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
3942 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3945 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
3946 ERR("Current stage overflows textures array (stage %d)\n", Stage);
3947 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3950 *ppTexture=This->stateBlock->textures[Stage];
3952 IWineD3DBaseTexture_AddRef(*ppTexture);
3954 TRACE("(%p) : Returning %p\n", This, *ppTexture);
3962 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
3963 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
3965 IWineD3DSwapChain *swapchain;
3968 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
3969 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
3971 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
3974 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
3978 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
3979 IWineD3DSwapChain_Release(swapchain);
3982 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
3989 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
3990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3991 WARN("(%p) : stub, calling idirect3d for now\n", This);
3992 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
3995 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
3996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3997 IWineD3DSwapChain *swapChain;
4000 if(iSwapChain > 0) {
4001 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4002 if (hr == WINED3D_OK) {
4003 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4004 IWineD3DSwapChain_Release(swapChain);
4006 FIXME("(%p) Error getting display mode\n", This);
4009 /* Don't read the real display mode,
4010 but return the stored mode instead. X11 can't change the color
4011 depth, and some apps are pretty angry if they SetDisplayMode from
4012 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4014 Also don't relay to the swapchain because with ddraw it's possible
4015 that there isn't a swapchain at all */
4016 pMode->Width = This->ddraw_width;
4017 pMode->Height = This->ddraw_height;
4018 pMode->Format = This->ddraw_format;
4019 pMode->RefreshRate = 0;
4027 * Stateblock related functions
4030 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4032 IWineD3DStateBlock *stateblock;
4035 TRACE("(%p)\n", This);
4037 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4039 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4040 if (FAILED(hr)) return hr;
4042 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4043 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4044 This->isRecordingState = TRUE;
4046 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4051 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4053 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4055 if (!This->isRecordingState) {
4056 WARN("(%p) not recording! returning error\n", This);
4057 *ppStateBlock = NULL;
4058 return WINED3DERR_INVALIDCALL;
4061 stateblock_init_contained_states(object);
4063 *ppStateBlock = (IWineD3DStateBlock*) object;
4064 This->isRecordingState = FALSE;
4065 This->updateStateBlock = This->stateBlock;
4066 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4067 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4068 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4073 * Scene related functions
4075 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4076 /* At the moment we have no need for any functionality at the beginning
4078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4079 TRACE("(%p)\n", This);
4082 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4083 return WINED3DERR_INVALIDCALL;
4085 This->inScene = TRUE;
4089 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4092 struct wined3d_context *context;
4094 TRACE("(%p)\n", This);
4096 if(!This->inScene) {
4097 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4098 return WINED3DERR_INVALIDCALL;
4101 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4102 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4104 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4106 context_release(context);
4108 This->inScene = FALSE;
4112 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4113 const RECT *pSourceRect, const RECT *pDestRect,
4114 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4116 IWineD3DSwapChain *swapChain = NULL;
4118 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4120 TRACE("iface %p.\n", iface);
4122 for(i = 0 ; i < swapchains ; i ++) {
4124 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4125 TRACE("presentinng chain %d, %p\n", i, swapChain);
4126 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4127 IWineD3DSwapChain_Release(swapChain);
4133 /* Not called from the VTable (internal subroutine) */
4134 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4135 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4136 float Z, DWORD Stencil) {
4137 GLbitfield glMask = 0;
4139 WINED3DRECT curRect;
4141 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4142 UINT drawable_width, drawable_height;
4143 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4144 struct wined3d_context *context;
4146 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4147 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4148 * for the cleared parts, and the untouched parts.
4150 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4151 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4152 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4153 * checking all this if the dest surface is in the drawable anyway.
4155 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4157 if(vp->X != 0 || vp->Y != 0 ||
4158 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4159 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4162 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4163 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4164 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4165 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4166 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4169 if(Count > 0 && pRects && (
4170 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4171 pRects[0].x2 < target->currentDesc.Width ||
4172 pRects[0].y2 < target->currentDesc.Height)) {
4173 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4180 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4182 target->get_drawable_size(context, &drawable_width, &drawable_height);
4186 /* Only set the values up once, as they are not changing */
4187 if (Flags & WINED3DCLEAR_STENCIL) {
4188 glClearStencil(Stencil);
4189 checkGLcall("glClearStencil");
4190 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4191 glStencilMask(0xFFFFFFFF);
4194 if (Flags & WINED3DCLEAR_ZBUFFER) {
4195 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4196 glDepthMask(GL_TRUE);
4198 checkGLcall("glClearDepth");
4199 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4200 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4202 if (vp->X != 0 || vp->Y != 0 ||
4203 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4204 surface_load_ds_location(This->stencilBufferTarget, context, location);
4206 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4207 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4208 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4209 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4210 surface_load_ds_location(This->stencilBufferTarget, context, location);
4212 else if (Count > 0 && pRects && (
4213 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4214 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4215 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4216 surface_load_ds_location(This->stencilBufferTarget, context, location);
4220 if (Flags & WINED3DCLEAR_TARGET) {
4221 TRACE("Clearing screen with glClear to color %x\n", Color);
4222 glClearColor(D3DCOLOR_R(Color),
4226 checkGLcall("glClearColor");
4228 /* Clear ALL colors! */
4229 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4230 glMask = glMask | GL_COLOR_BUFFER_BIT;
4233 vp_rect.left = vp->X;
4234 vp_rect.top = vp->Y;
4235 vp_rect.right = vp->X + vp->Width;
4236 vp_rect.bottom = vp->Y + vp->Height;
4237 if (!(Count > 0 && pRects)) {
4238 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4239 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4241 if (context->render_offscreen)
4243 glScissor(vp_rect.left, vp_rect.top,
4244 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4246 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4247 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4249 checkGLcall("glScissor");
4251 checkGLcall("glClear");
4253 /* Now process each rect in turn */
4254 for (i = 0; i < Count; i++) {
4255 /* Note gl uses lower left, width/height */
4256 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4257 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4258 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4260 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4261 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4262 curRect.x1, (target->currentDesc.Height - curRect.y2),
4263 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4265 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4266 * The rectangle is not cleared, no error is returned, but further rectanlges are
4267 * still cleared if they are valid
4269 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4270 TRACE("Rectangle with negative dimensions, ignoring\n");
4274 if (context->render_offscreen)
4276 glScissor(curRect.x1, curRect.y1,
4277 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4279 glScissor(curRect.x1, drawable_height - curRect.y2,
4280 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4282 checkGLcall("glScissor");
4285 checkGLcall("glClear");
4289 /* Restore the old values (why..?) */
4290 if (Flags & WINED3DCLEAR_STENCIL) {
4291 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4293 if (Flags & WINED3DCLEAR_TARGET) {
4294 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4295 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4296 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4297 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4298 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4300 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4301 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4303 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4305 if (Flags & WINED3DCLEAR_ZBUFFER) {
4306 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4307 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4308 surface_modify_ds_location(This->stencilBufferTarget, location);
4313 wglFlush(); /* Flush to ensure ordering across contexts. */
4315 context_release(context);
4320 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4321 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4323 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4325 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4326 Count, pRects, Flags, Color, Z, Stencil);
4328 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4329 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4330 /* TODO: What about depth stencil buffers without stencil bits? */
4331 return WINED3DERR_INVALIDCALL;
4334 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4341 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4342 WINED3DPRIMITIVETYPE primitive_type)
4344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4346 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4348 This->updateStateBlock->changed.primitive_type = TRUE;
4349 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4352 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4353 WINED3DPRIMITIVETYPE *primitive_type)
4355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4357 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4359 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4361 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4364 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4368 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4370 if(!This->stateBlock->vertexDecl) {
4371 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4372 return WINED3DERR_INVALIDCALL;
4375 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4376 if(This->stateBlock->streamIsUP) {
4377 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4378 This->stateBlock->streamIsUP = FALSE;
4381 if(This->stateBlock->loadBaseVertexIndex != 0) {
4382 This->stateBlock->loadBaseVertexIndex = 0;
4383 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4385 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4386 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4390 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4394 IWineD3DBuffer *pIB;
4397 pIB = This->stateBlock->pIndexData;
4399 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4400 * without an index buffer set. (The first time at least...)
4401 * D3D8 simply dies, but I doubt it can do much harm to return
4402 * D3DERR_INVALIDCALL there as well. */
4403 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4404 return WINED3DERR_INVALIDCALL;
4407 if(!This->stateBlock->vertexDecl) {
4408 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4409 return WINED3DERR_INVALIDCALL;
4412 if(This->stateBlock->streamIsUP) {
4413 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4414 This->stateBlock->streamIsUP = FALSE;
4416 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4418 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4420 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4426 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4427 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4428 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4431 drawPrimitive(iface, index_count, startIndex, idxStride,
4432 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4437 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4438 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4443 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4444 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4446 if(!This->stateBlock->vertexDecl) {
4447 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4448 return WINED3DERR_INVALIDCALL;
4451 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4452 vb = This->stateBlock->streamSource[0];
4453 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4454 if (vb) IWineD3DBuffer_Release(vb);
4455 This->stateBlock->streamOffset[0] = 0;
4456 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4457 This->stateBlock->streamIsUP = TRUE;
4458 This->stateBlock->loadBaseVertexIndex = 0;
4460 /* TODO: Only mark dirty if drawing from a different UP address */
4461 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4463 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4465 /* MSDN specifies stream zero settings must be set to NULL */
4466 This->stateBlock->streamStride[0] = 0;
4467 This->stateBlock->streamSource[0] = NULL;
4469 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4470 * the new stream sources or use UP drawing again
4475 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4476 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4477 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4484 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4485 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4487 if(!This->stateBlock->vertexDecl) {
4488 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4489 return WINED3DERR_INVALIDCALL;
4492 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4498 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4499 vb = This->stateBlock->streamSource[0];
4500 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4501 if (vb) IWineD3DBuffer_Release(vb);
4502 This->stateBlock->streamIsUP = TRUE;
4503 This->stateBlock->streamOffset[0] = 0;
4504 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4506 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4507 This->stateBlock->baseVertexIndex = 0;
4508 This->stateBlock->loadBaseVertexIndex = 0;
4509 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4510 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4511 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4513 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4515 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4516 This->stateBlock->streamSource[0] = NULL;
4517 This->stateBlock->streamStride[0] = 0;
4518 ib = This->stateBlock->pIndexData;
4520 IWineD3DBuffer_Release(ib);
4521 This->stateBlock->pIndexData = NULL;
4523 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4524 * SetStreamSource to specify a vertex buffer
4530 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4531 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4535 /* Mark the state dirty until we have nicer tracking
4536 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4539 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4540 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4541 This->stateBlock->baseVertexIndex = 0;
4542 This->up_strided = DrawPrimStrideData;
4543 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4544 This->up_strided = NULL;
4548 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4549 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4550 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4553 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4555 /* Mark the state dirty until we have nicer tracking
4556 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4559 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4560 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4561 This->stateBlock->streamIsUP = TRUE;
4562 This->stateBlock->baseVertexIndex = 0;
4563 This->up_strided = DrawPrimStrideData;
4564 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4565 This->up_strided = NULL;
4569 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4570 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4571 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4573 WINED3DLOCKED_BOX src;
4574 WINED3DLOCKED_BOX dst;
4577 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4578 iface, pSourceVolume, pDestinationVolume);
4580 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4581 * dirtification to improve loading performance.
4583 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4584 if(FAILED(hr)) return hr;
4585 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4587 IWineD3DVolume_UnlockBox(pSourceVolume);
4591 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4593 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4595 IWineD3DVolume_UnlockBox(pSourceVolume);
4597 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4602 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4603 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4605 unsigned int level_count, i;
4606 WINED3DRESOURCETYPE type;
4609 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4611 /* Verify that the source and destination textures are non-NULL. */
4612 if (!src_texture || !dst_texture)
4614 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4615 return WINED3DERR_INVALIDCALL;
4618 if (src_texture == dst_texture)
4620 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4621 return WINED3DERR_INVALIDCALL;
4624 /* Verify that the source and destination textures are the same type. */
4625 type = IWineD3DBaseTexture_GetType(src_texture);
4626 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4628 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4629 return WINED3DERR_INVALIDCALL;
4632 /* Check that both textures have the identical numbers of levels. */
4633 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4634 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4636 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4637 return WINED3DERR_INVALIDCALL;
4640 /* Make sure that the destination texture is loaded. */
4641 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4643 /* Update every surface level of the texture. */
4646 case WINED3DRTYPE_TEXTURE:
4648 IWineD3DSurface *src_surface;
4649 IWineD3DSurface *dst_surface;
4651 for (i = 0; i < level_count; ++i)
4653 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4654 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4655 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4656 IWineD3DSurface_Release(dst_surface);
4657 IWineD3DSurface_Release(src_surface);
4660 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4667 case WINED3DRTYPE_CUBETEXTURE:
4669 IWineD3DSurface *src_surface;
4670 IWineD3DSurface *dst_surface;
4671 WINED3DCUBEMAP_FACES face;
4673 for (i = 0; i < level_count; ++i)
4675 /* Update each cube face. */
4676 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4678 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4679 face, i, &src_surface);
4680 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4681 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4682 face, i, &dst_surface);
4683 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4684 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4685 IWineD3DSurface_Release(dst_surface);
4686 IWineD3DSurface_Release(src_surface);
4689 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4697 case WINED3DRTYPE_VOLUMETEXTURE:
4699 IWineD3DVolume *src_volume;
4700 IWineD3DVolume *dst_volume;
4702 for (i = 0; i < level_count; ++i)
4704 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4705 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4706 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4707 IWineD3DVolume_Release(dst_volume);
4708 IWineD3DVolume_Release(src_volume);
4711 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4719 FIXME("Unsupported texture type %#x.\n", type);
4720 return WINED3DERR_INVALIDCALL;
4726 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4727 IWineD3DSwapChain *swapChain;
4729 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4730 if(hr == WINED3D_OK) {
4731 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4732 IWineD3DSwapChain_Release(swapChain);
4737 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4739 IWineD3DBaseTextureImpl *texture;
4742 TRACE("(%p) : %p\n", This, pNumPasses);
4744 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4745 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
4746 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4747 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4749 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
4750 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4751 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4754 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
4755 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
4757 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
4758 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4761 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
4762 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4765 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
4766 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
4767 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4772 /* return a sensible default */
4775 TRACE("returning D3D_OK\n");
4779 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
4783 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4785 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
4786 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
4787 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
4789 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
4794 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4798 PALETTEENTRY **palettes;
4800 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4802 if (PaletteNumber >= MAX_PALETTES) {
4803 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4804 return WINED3DERR_INVALIDCALL;
4807 if (PaletteNumber >= This->NumberOfPalettes) {
4808 NewSize = This->NumberOfPalettes;
4811 } while(PaletteNumber >= NewSize);
4812 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
4814 ERR("Out of memory!\n");
4815 return E_OUTOFMEMORY;
4817 This->palettes = palettes;
4818 This->NumberOfPalettes = NewSize;
4821 if (!This->palettes[PaletteNumber]) {
4822 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
4823 if (!This->palettes[PaletteNumber]) {
4824 ERR("Out of memory!\n");
4825 return E_OUTOFMEMORY;
4829 for (j = 0; j < 256; ++j) {
4830 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4831 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4832 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4833 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4835 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
4836 TRACE("(%p) : returning\n", This);
4840 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4843 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4844 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
4845 /* What happens in such situation isn't documented; Native seems to silently abort
4846 on such conditions. Return Invalid Call. */
4847 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
4848 return WINED3DERR_INVALIDCALL;
4850 for (j = 0; j < 256; ++j) {
4851 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4852 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4853 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4854 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4856 TRACE("(%p) : returning\n", This);
4860 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4862 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4863 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
4864 (tested with reference rasterizer). Return Invalid Call. */
4865 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
4866 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
4867 return WINED3DERR_INVALIDCALL;
4869 /*TODO: stateblocks */
4870 if (This->currentPalette != PaletteNumber) {
4871 This->currentPalette = PaletteNumber;
4872 dirtify_p8_texture_samplers(This);
4874 TRACE("(%p) : returning\n", This);
4878 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4880 if (PaletteNumber == NULL) {
4881 WARN("(%p) : returning Invalid Call\n", This);
4882 return WINED3DERR_INVALIDCALL;
4884 /*TODO: stateblocks */
4885 *PaletteNumber = This->currentPalette;
4886 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4890 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4895 FIXME("(%p) : stub\n", This);
4899 This->softwareVertexProcessing = bSoftware;
4904 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4909 FIXME("(%p) : stub\n", This);
4912 return This->softwareVertexProcessing;
4915 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
4916 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
4918 IWineD3DSwapChain *swapchain;
4921 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
4922 iface, swapchain_idx, raster_status);
4924 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4927 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4931 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
4932 IWineD3DSwapChain_Release(swapchain);
4935 WARN("Failed to get raster status, hr %#x.\n", hr);
4942 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
4945 if(nSegments != 0.0f) {
4948 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
4955 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
4960 FIXME("iface %p stub!\n", iface);
4966 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4968 /** TODO: remove casts to IWineD3DSurfaceImpl
4969 * NOTE: move code to surface to accomplish this
4970 ****************************************/
4971 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4972 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
4973 int srcWidth, srcHeight;
4974 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4975 WINED3DFORMAT destFormat, srcFormat;
4977 int srcLeft, destLeft, destTop;
4978 WINED3DPOOL srcPool, destPool;
4980 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4981 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
4985 CONVERT_TYPES convert = NO_CONVERSION;
4986 struct wined3d_context *context;
4988 WINED3DSURFACE_DESC winedesc;
4990 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4992 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4993 srcSurfaceWidth = winedesc.width;
4994 srcSurfaceHeight = winedesc.height;
4995 srcPool = winedesc.pool;
4996 srcFormat = winedesc.format;
4998 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4999 destSurfaceWidth = winedesc.width;
5000 destSurfaceHeight = winedesc.height;
5001 destPool = winedesc.pool;
5002 destFormat = winedesc.format;
5003 destSize = winedesc.size;
5005 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5006 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5007 return WINED3DERR_INVALIDCALL;
5010 /* This call loads the opengl surface directly, instead of copying the surface to the
5011 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5012 * copy in sysmem and use regular surface loading.
5014 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5015 if(convert != NO_CONVERSION) {
5016 return IWineD3DSurface_BltFast(pDestinationSurface,
5017 pDestPoint ? pDestPoint->x : 0,
5018 pDestPoint ? pDestPoint->y : 0,
5019 pSourceSurface, pSourceRect, 0);
5022 if (destFormat == WINED3DFMT_UNKNOWN) {
5023 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5024 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5026 /* Get the update surface description */
5027 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5030 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5033 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5034 checkGLcall("glActiveTextureARB");
5037 /* Make sure the surface is loaded and up to date */
5038 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5039 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5041 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5042 dst_format_desc = dst_impl->resource.format_desc;
5044 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5045 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5046 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5047 srcLeft = pSourceRect ? pSourceRect->left : 0;
5048 destLeft = pDestPoint ? pDestPoint->x : 0;
5049 destTop = pDestPoint ? pDestPoint->y : 0;
5052 /* This function doesn't support compressed textures
5053 the pitch is just bytesPerPixel * width */
5054 if(srcWidth != srcSurfaceWidth || srcLeft ){
5055 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5056 offset += srcLeft * src_format_desc->byte_count;
5057 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5059 /* TODO DXT formats */
5061 if(pSourceRect != NULL && pSourceRect->top != 0){
5062 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5064 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5065 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5066 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5069 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5071 /* need to lock the surface to get the data */
5072 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5077 /* TODO: Cube and volume support */
5079 /* not a whole row so we have to do it a line at a time */
5082 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5083 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5085 for (j = destTop; j < (srcHeight + destTop); ++j)
5087 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5088 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5092 } else { /* Full width, so just write out the whole texture */
5093 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5095 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5097 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5099 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5100 FIXME("Updating part of a compressed texture is not supported.\n");
5102 if (destFormat != srcFormat)
5104 FIXME("Updating mixed format compressed textures is not supported.\n");
5108 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5109 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5114 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5115 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5118 checkGLcall("glTexSubImage2D");
5121 context_release(context);
5123 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5124 sampler = This->rev_tex_unit_map[0];
5125 if (sampler != WINED3D_UNMAPPED_STAGE)
5127 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5133 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5135 struct WineD3DRectPatch *patch;
5136 GLenum old_primitive_type;
5140 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5142 if(!(Handle || pRectPatchInfo)) {
5143 /* TODO: Write a test for the return value, thus the FIXME */
5144 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5145 return WINED3DERR_INVALIDCALL;
5149 i = PATCHMAP_HASHFUNC(Handle);
5151 LIST_FOR_EACH(e, &This->patches[i]) {
5152 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5153 if(patch->Handle == Handle) {
5160 TRACE("Patch does not exist. Creating a new one\n");
5161 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5162 patch->Handle = Handle;
5163 list_add_head(&This->patches[i], &patch->entry);
5165 TRACE("Found existing patch %p\n", patch);
5168 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5169 * attributes we have to tesselate, read back, and draw. This needs a patch
5170 * management structure instance. Create one.
5172 * A possible improvement is to check if a vertex shader is used, and if not directly
5175 FIXME("Drawing an uncached patch. This is slow\n");
5176 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5179 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5180 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5181 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5183 TRACE("Tesselation density or patch info changed, retesselating\n");
5185 if(pRectPatchInfo) {
5186 patch->RectPatchInfo = *pRectPatchInfo;
5188 patch->numSegs[0] = pNumSegs[0];
5189 patch->numSegs[1] = pNumSegs[1];
5190 patch->numSegs[2] = pNumSegs[2];
5191 patch->numSegs[3] = pNumSegs[3];
5193 hr = tesselate_rectpatch(This, patch);
5195 WARN("Patch tesselation failed\n");
5197 /* Do not release the handle to store the params of the patch */
5199 HeapFree(GetProcessHeap(), 0, patch);
5205 This->currentPatch = patch;
5206 old_primitive_type = This->stateBlock->gl_primitive_type;
5207 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5208 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5209 This->stateBlock->gl_primitive_type = old_primitive_type;
5210 This->currentPatch = NULL;
5212 /* Destroy uncached patches */
5214 HeapFree(GetProcessHeap(), 0, patch->mem);
5215 HeapFree(GetProcessHeap(), 0, patch);
5220 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5221 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5223 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5224 iface, handle, segment_count, patch_info);
5229 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5232 struct WineD3DRectPatch *patch;
5234 TRACE("(%p) Handle(%d)\n", This, Handle);
5236 i = PATCHMAP_HASHFUNC(Handle);
5237 LIST_FOR_EACH(e, &This->patches[i]) {
5238 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5239 if(patch->Handle == Handle) {
5240 TRACE("Deleting patch %p\n", patch);
5241 list_remove(&patch->entry);
5242 HeapFree(GetProcessHeap(), 0, patch->mem);
5243 HeapFree(GetProcessHeap(), 0, patch);
5248 /* TODO: Write a test for the return value */
5249 FIXME("Attempt to destroy nonexistent patch\n");
5250 return WINED3DERR_INVALIDCALL;
5253 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5255 IWineD3DSwapChain *swapchain;
5257 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5258 if (SUCCEEDED(hr)) {
5259 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5266 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5267 const WINED3DRECT *rect, const float color[4])
5269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5270 struct wined3d_context *context;
5272 if (!surface_is_offscreen(surface))
5274 TRACE("Surface %p is onscreen\n", surface);
5276 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5278 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5279 context_set_draw_buffer(context, surface_get_gl_buffer(surface));
5283 TRACE("Surface %p is offscreen\n", surface);
5285 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5287 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5288 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5289 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5293 glEnable(GL_SCISSOR_TEST);
5294 if(surface_is_offscreen(surface)) {
5295 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5297 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5298 rect->x2 - rect->x1, rect->y2 - rect->y1);
5300 checkGLcall("glScissor");
5301 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5303 glDisable(GL_SCISSOR_TEST);
5305 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5307 glDisable(GL_BLEND);
5308 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5310 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5311 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5313 glClearColor(color[0], color[1], color[2], color[3]);
5314 glClear(GL_COLOR_BUFFER_BIT);
5315 checkGLcall("glClear");
5319 wglFlush(); /* Flush to ensure ordering across contexts. */
5321 context_release(context);
5324 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5325 unsigned int r, g, b, a;
5328 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5329 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5330 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5333 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5335 a = (color & 0xff000000) >> 24;
5336 r = (color & 0x00ff0000) >> 16;
5337 g = (color & 0x0000ff00) >> 8;
5338 b = (color & 0x000000ff) >> 0;
5342 case WINED3DFMT_B5G6R5_UNORM:
5343 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5350 TRACE("Returning %08x\n", ret);
5353 case WINED3DFMT_B5G5R5X1_UNORM:
5354 case WINED3DFMT_B5G5R5A1_UNORM:
5363 TRACE("Returning %08x\n", ret);
5366 case WINED3DFMT_A8_UNORM:
5367 TRACE("Returning %08x\n", a);
5370 case WINED3DFMT_B4G4R4X4_UNORM:
5371 case WINED3DFMT_B4G4R4A4_UNORM:
5380 TRACE("Returning %08x\n", ret);
5383 case WINED3DFMT_B2G3R3_UNORM:
5390 TRACE("Returning %08x\n", ret);
5393 case WINED3DFMT_R8G8B8X8_UNORM:
5394 case WINED3DFMT_R8G8B8A8_UNORM:
5399 TRACE("Returning %08x\n", ret);
5402 case WINED3DFMT_B10G10R10A2_UNORM:
5404 r = (r * 1024) / 256;
5405 g = (g * 1024) / 256;
5406 b = (b * 1024) / 256;
5411 TRACE("Returning %08x\n", ret);
5414 case WINED3DFMT_R10G10B10A2_UNORM:
5416 r = (r * 1024) / 256;
5417 g = (g * 1024) / 256;
5418 b = (b * 1024) / 256;
5423 TRACE("Returning %08x\n", ret);
5427 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5432 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5433 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5435 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5438 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5440 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5441 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5442 return WINED3DERR_INVALIDCALL;
5445 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5446 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5447 color_fill_fbo(iface, pSurface, pRect, c);
5450 /* Just forward this to the DirectDraw blitting engine */
5451 memset(&BltFx, 0, sizeof(BltFx));
5452 BltFx.dwSize = sizeof(BltFx);
5453 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5454 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5455 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5459 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5460 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5462 IWineD3DResource *resource;
5463 IWineD3DSurface *surface;
5466 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5469 ERR("Failed to get resource, hr %#x\n", hr);
5473 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5475 FIXME("Only supported on surface resources\n");
5476 IWineD3DResource_Release(resource);
5480 surface = (IWineD3DSurface *)resource;
5482 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5484 color_fill_fbo(iface, surface, NULL, color);
5491 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5493 c = ((DWORD)(color[2] * 255.0f));
5494 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5495 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5496 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5498 /* Just forward this to the DirectDraw blitting engine */
5499 memset(&BltFx, 0, sizeof(BltFx));
5500 BltFx.dwSize = sizeof(BltFx);
5501 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5502 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5505 ERR("Blt failed, hr %#x\n", hr);
5509 IWineD3DResource_Release(resource);
5512 /* rendertarget and depth stencil functions */
5513 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5516 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5518 ERR("(%p) : Only %d render targets are supported.\n",
5519 This, This->adapter->gl_info.limits.buffers);
5520 return WINED3DERR_INVALIDCALL;
5523 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5524 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5525 /* Note inc ref on returned surface */
5526 if(*ppRenderTarget != NULL)
5527 IWineD3DSurface_AddRef(*ppRenderTarget);
5531 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5532 IWineD3DSurface *Front, IWineD3DSurface *Back)
5534 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5535 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5536 IWineD3DSwapChainImpl *Swapchain;
5539 TRACE("iface %p, front %p, back %p.\n", iface, Front, Back);
5541 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5542 if(hr != WINED3D_OK) {
5543 ERR("Can't get the swapchain\n");
5547 /* Make sure to release the swapchain */
5548 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5550 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5551 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5552 return WINED3DERR_INVALIDCALL;
5554 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5555 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5556 return WINED3DERR_INVALIDCALL;
5559 if(Swapchain->frontBuffer != Front) {
5560 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5562 if(Swapchain->frontBuffer)
5564 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5565 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5567 Swapchain->frontBuffer = Front;
5569 if(Swapchain->frontBuffer) {
5570 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5571 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5575 if(Back && !Swapchain->backBuffer) {
5576 /* We need memory for the back buffer array - only one back buffer this way */
5577 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5578 if(!Swapchain->backBuffer) {
5579 ERR("Out of memory\n");
5580 return E_OUTOFMEMORY;
5584 if(Swapchain->backBuffer[0] != Back) {
5585 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5587 /* What to do about the context here in the case of multithreading? Not sure.
5588 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5590 WARN("No active context?\n");
5593 if(!Swapchain->backBuffer[0]) {
5594 /* GL was told to draw to the front buffer at creation,
5597 glDrawBuffer(GL_BACK);
5598 checkGLcall("glDrawBuffer(GL_BACK)");
5599 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5600 Swapchain->presentParms.BackBufferCount = 1;
5602 /* That makes problems - disable for now */
5603 /* glDrawBuffer(GL_FRONT); */
5604 checkGLcall("glDrawBuffer(GL_FRONT)");
5605 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5606 Swapchain->presentParms.BackBufferCount = 0;
5610 if(Swapchain->backBuffer[0])
5612 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5613 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5615 Swapchain->backBuffer[0] = Back;
5617 if(Swapchain->backBuffer[0]) {
5618 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5619 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
5621 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5622 Swapchain->backBuffer = NULL;
5630 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5632 *ppZStencilSurface = This->stencilBufferTarget;
5633 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5635 if(*ppZStencilSurface != NULL) {
5636 /* Note inc ref on returned surface */
5637 IWineD3DSurface_AddRef(*ppZStencilSurface);
5640 return WINED3DERR_NOTFOUND;
5644 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5645 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
5647 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5648 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5649 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5650 const struct wined3d_gl_info *gl_info;
5651 struct wined3d_context *context;
5653 POINT offset = {0, 0};
5655 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5656 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5657 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5658 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5661 case WINED3DTEXF_LINEAR:
5662 gl_filter = GL_LINEAR;
5666 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5667 case WINED3DTEXF_NONE:
5668 case WINED3DTEXF_POINT:
5669 gl_filter = GL_NEAREST;
5673 /* Attach src surface to src fbo */
5674 src_swapchain = get_swapchain(src_surface);
5675 dst_swapchain = get_swapchain(dst_surface);
5677 if (src_swapchain) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
5678 else if (dst_swapchain) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5679 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5681 gl_info = context->gl_info;
5683 if (!surface_is_offscreen(src_surface))
5685 GLenum buffer = surface_get_gl_buffer(src_surface);
5687 TRACE("Source surface %p is onscreen\n", src_surface);
5688 /* Make sure the drawable is up to date. In the offscreen case
5689 * attach_surface_fbo() implicitly takes care of this. */
5690 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
5692 if(buffer == GL_FRONT) {
5695 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
5696 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
5697 h = windowsize.bottom - windowsize.top;
5698 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
5699 src_rect->y1 = offset.y + h - src_rect->y1;
5700 src_rect->y2 = offset.y + h - src_rect->y2;
5702 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5703 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5707 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5708 glReadBuffer(buffer);
5709 checkGLcall("glReadBuffer()");
5711 TRACE("Source surface %p is offscreen\n", src_surface);
5713 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5714 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
5715 glReadBuffer(GL_COLOR_ATTACHMENT0);
5716 checkGLcall("glReadBuffer()");
5717 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5721 /* Attach dst surface to dst fbo */
5722 if (!surface_is_offscreen(dst_surface))
5724 GLenum buffer = surface_get_gl_buffer(dst_surface);
5726 TRACE("Destination surface %p is onscreen\n", dst_surface);
5727 /* Make sure the drawable is up to date. In the offscreen case
5728 * attach_surface_fbo() implicitly takes care of this. */
5729 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
5731 if(buffer == GL_FRONT) {
5734 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
5735 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
5736 h = windowsize.bottom - windowsize.top;
5737 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
5738 dst_rect->y1 = offset.y + h - dst_rect->y1;
5739 dst_rect->y2 = offset.y + h - dst_rect->y2;
5741 /* Screen coords = window coords, surface height = window height */
5742 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5743 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5747 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5748 context_set_draw_buffer(context, buffer);
5752 TRACE("Destination surface %p is offscreen\n", dst_surface);
5755 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5756 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
5757 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5758 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5760 glDisable(GL_SCISSOR_TEST);
5761 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5764 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5765 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
5766 checkGLcall("glBlitFramebuffer()");
5768 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5769 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
5770 checkGLcall("glBlitFramebuffer()");
5775 wglFlush(); /* Flush to ensure ordering across contexts. */
5777 context_release(context);
5779 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
5782 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5783 BOOL set_viewport) {
5784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5786 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5788 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5790 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5791 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5792 return WINED3DERR_INVALIDCALL;
5795 /* MSDN says that null disables the render target
5796 but a device must always be associated with a render target
5797 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5799 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5800 FIXME("Trying to set render target 0 to NULL\n");
5801 return WINED3DERR_INVALIDCALL;
5803 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5804 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);
5805 return WINED3DERR_INVALIDCALL;
5808 /* If we are trying to set what we already have, don't bother */
5809 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5810 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5813 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5814 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5815 This->render_targets[RenderTargetIndex] = pRenderTarget;
5817 /* Render target 0 is special */
5818 if(RenderTargetIndex == 0 && set_viewport) {
5819 /* Finally, reset the viewport and scissor rect as the MSDN states.
5820 * Tests show that stateblock recording is ignored, the change goes
5821 * directly into the primary stateblock.
5823 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5824 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5825 This->stateBlock->viewport.X = 0;
5826 This->stateBlock->viewport.Y = 0;
5827 This->stateBlock->viewport.MaxZ = 1.0f;
5828 This->stateBlock->viewport.MinZ = 0.0f;
5829 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5831 This->stateBlock->scissorRect.top = 0;
5832 This->stateBlock->scissorRect.left = 0;
5833 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5834 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5835 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5840 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5842 HRESULT hr = WINED3D_OK;
5843 IWineD3DSurface *tmp;
5845 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
5847 if (pNewZStencil == This->stencilBufferTarget) {
5848 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5850 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
5851 * depending on the renter target implementation being used.
5852 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5853 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5854 * stencil buffer and incur an extra memory overhead
5855 ******************************************************/
5857 if (This->stencilBufferTarget) {
5858 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5859 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
5860 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
5862 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5863 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
5864 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
5865 context_release(context);
5869 tmp = This->stencilBufferTarget;
5870 This->stencilBufferTarget = pNewZStencil;
5871 /* should we be calling the parent or the wined3d surface? */
5872 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5873 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5876 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5877 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5878 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5879 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5880 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5887 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5888 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5890 /* TODO: the use of Impl is deprecated. */
5891 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5892 WINED3DLOCKED_RECT lockedRect;
5894 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5896 /* some basic validation checks */
5897 if(This->cursorTexture) {
5898 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5900 glDeleteTextures(1, &This->cursorTexture);
5902 context_release(context);
5903 This->cursorTexture = 0;
5906 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5907 This->haveHardwareCursor = TRUE;
5909 This->haveHardwareCursor = FALSE;
5912 WINED3DLOCKED_RECT rect;
5914 /* MSDN: Cursor must be A8R8G8B8 */
5915 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
5917 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5918 return WINED3DERR_INVALIDCALL;
5921 /* MSDN: Cursor must be smaller than the display mode */
5922 if(pSur->currentDesc.Width > This->ddraw_width ||
5923 pSur->currentDesc.Height > This->ddraw_height) {
5924 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);
5925 return WINED3DERR_INVALIDCALL;
5928 if (!This->haveHardwareCursor) {
5929 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5931 /* Do not store the surface's pointer because the application may
5932 * release it after setting the cursor image. Windows doesn't
5933 * addref the set surface, so we can't do this either without
5934 * creating circular refcount dependencies. Copy out the gl texture
5937 This->cursorWidth = pSur->currentDesc.Width;
5938 This->cursorHeight = pSur->currentDesc.Height;
5939 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5941 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5942 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
5943 struct wined3d_context *context;
5944 char *mem, *bits = rect.pBits;
5945 GLint intfmt = glDesc->glInternal;
5946 GLint format = glDesc->glFormat;
5947 GLint type = glDesc->glType;
5948 INT height = This->cursorHeight;
5949 INT width = This->cursorWidth;
5950 INT bpp = glDesc->byte_count;
5954 /* Reformat the texture memory (pitch and width can be
5956 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5957 for(i = 0; i < height; i++)
5958 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5959 IWineD3DSurface_UnlockRect(pCursorBitmap);
5961 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5965 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5967 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5968 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5971 /* Make sure that a proper texture unit is selected */
5972 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5973 checkGLcall("glActiveTextureARB");
5974 sampler = This->rev_tex_unit_map[0];
5975 if (sampler != WINED3D_UNMAPPED_STAGE)
5977 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5979 /* Create a new cursor texture */
5980 glGenTextures(1, &This->cursorTexture);
5981 checkGLcall("glGenTextures");
5982 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5983 checkGLcall("glBindTexture");
5984 /* Copy the bitmap memory into the cursor texture */
5985 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5986 HeapFree(GetProcessHeap(), 0, mem);
5987 checkGLcall("glTexImage2D");
5989 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5991 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5992 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5997 context_release(context);
6001 FIXME("A cursor texture was not returned.\n");
6002 This->cursorTexture = 0;
6007 /* Draw a hardware cursor */
6008 ICONINFO cursorInfo;
6010 /* Create and clear maskBits because it is not needed for
6011 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6013 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6014 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6015 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6016 WINED3DLOCK_NO_DIRTY_UPDATE |
6017 WINED3DLOCK_READONLY
6019 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6020 pSur->currentDesc.Height);
6022 cursorInfo.fIcon = FALSE;
6023 cursorInfo.xHotspot = XHotSpot;
6024 cursorInfo.yHotspot = YHotSpot;
6025 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6027 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6028 1, 32, lockedRect.pBits);
6029 IWineD3DSurface_UnlockRect(pCursorBitmap);
6030 /* Create our cursor and clean up. */
6031 cursor = CreateIconIndirect(&cursorInfo);
6033 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6034 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6035 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6036 This->hardwareCursor = cursor;
6037 HeapFree(GetProcessHeap(), 0, maskBits);
6041 This->xHotSpot = XHotSpot;
6042 This->yHotSpot = YHotSpot;
6046 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6048 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6050 This->xScreenSpace = XScreenSpace;
6051 This->yScreenSpace = YScreenSpace;
6057 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6058 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6059 BOOL oldVisible = This->bCursorVisible;
6062 TRACE("(%p) : visible(%d)\n", This, bShow);
6065 * When ShowCursor is first called it should make the cursor appear at the OS's last
6066 * known cursor position. Because of this, some applications just repetitively call
6067 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6070 This->xScreenSpace = pt.x;
6071 This->yScreenSpace = pt.y;
6073 if (This->haveHardwareCursor) {
6074 This->bCursorVisible = bShow;
6076 SetCursor(This->hardwareCursor);
6082 if (This->cursorTexture)
6083 This->bCursorVisible = bShow;
6089 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6090 TRACE("checking resource %p for eviction\n", resource);
6091 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6092 TRACE("Evicting %p\n", resource);
6093 IWineD3DResource_UnLoad(resource);
6095 IWineD3DResource_Release(resource);
6099 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6101 TRACE("iface %p.\n", iface);
6103 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6107 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6109 IWineD3DDeviceImpl *device = surface->resource.device;
6110 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6112 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6113 if(surface->Flags & SFLAG_DIBSECTION) {
6114 /* Release the DC */
6115 SelectObject(surface->hDC, surface->dib.holdbitmap);
6116 DeleteDC(surface->hDC);
6117 /* Release the DIB section */
6118 DeleteObject(surface->dib.DIBsection);
6119 surface->dib.bitmap_data = NULL;
6120 surface->resource.allocatedMemory = NULL;
6121 surface->Flags &= ~SFLAG_DIBSECTION;
6123 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6124 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6125 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6126 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6128 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6129 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6131 surface->pow2Width = surface->pow2Height = 1;
6132 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6133 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6135 surface->glRect.left = 0;
6136 surface->glRect.top = 0;
6137 surface->glRect.right = surface->pow2Width;
6138 surface->glRect.bottom = surface->pow2Height;
6140 if (surface->texture_name)
6142 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6144 glDeleteTextures(1, &surface->texture_name);
6146 context_release(context);
6147 surface->texture_name = 0;
6148 surface->Flags &= ~SFLAG_CLIENT;
6150 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6151 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6152 surface->Flags |= SFLAG_NONPOW2;
6154 surface->Flags &= ~SFLAG_NONPOW2;
6156 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6157 surface->resource.allocatedMemory = NULL;
6158 surface->resource.heapMemory = NULL;
6159 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6161 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6163 if(!surface_init_sysmem((IWineD3DSurface *) surface))
6165 return E_OUTOFMEMORY;
6170 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6171 TRACE("Unloading resource %p\n", resource);
6172 IWineD3DResource_UnLoad(resource);
6173 IWineD3DResource_Release(resource);
6177 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6180 WINED3DDISPLAYMODE m;
6183 /* All Windowed modes are supported, as is leaving the current mode */
6184 if(pp->Windowed) return TRUE;
6185 if(!pp->BackBufferWidth) return TRUE;
6186 if(!pp->BackBufferHeight) return TRUE;
6188 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6189 for(i = 0; i < count; i++) {
6190 memset(&m, 0, sizeof(m));
6191 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6193 ERR("EnumAdapterModes failed\n");
6195 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6196 /* Mode found, it is supported */
6200 /* Mode not found -> not supported */
6204 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6206 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6207 const struct wined3d_gl_info *gl_info;
6208 struct wined3d_context *context;
6209 IWineD3DBaseShaderImpl *shader;
6211 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6212 gl_info = context->gl_info;
6214 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6215 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6216 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6220 if(This->depth_blt_texture) {
6221 glDeleteTextures(1, &This->depth_blt_texture);
6222 This->depth_blt_texture = 0;
6224 if (This->depth_blt_rb) {
6225 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6226 This->depth_blt_rb = 0;
6227 This->depth_blt_rb_w = 0;
6228 This->depth_blt_rb_h = 0;
6232 This->blitter->free_private(iface);
6233 This->frag_pipe->free_private(iface);
6234 This->shader_backend->shader_free_private(iface);
6235 destroy_dummy_textures(This, gl_info);
6237 context_release(context);
6239 while (This->numContexts)
6241 context_destroy(This, This->contexts[0]);
6243 HeapFree(GetProcessHeap(), 0, swapchain->context);
6244 swapchain->context = NULL;
6245 swapchain->num_contexts = 0;
6248 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6250 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6251 struct wined3d_context *context;
6253 IWineD3DSurfaceImpl *target;
6255 /* Recreate the primary swapchain's context */
6256 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6257 if (!swapchain->context)
6259 ERR("Failed to allocate memory for swapchain context array.\n");
6260 return E_OUTOFMEMORY;
6263 target = (IWineD3DSurfaceImpl *)(swapchain->backBuffer ? swapchain->backBuffer[0] : swapchain->frontBuffer);
6264 context = context_create(This, target, swapchain->win_handle, FALSE, &swapchain->presentParms);
6267 WARN("Failed to create context.\n");
6268 HeapFree(GetProcessHeap(), 0, swapchain->context);
6272 swapchain->context[0] = context;
6273 swapchain->num_contexts = 1;
6274 create_dummy_textures(This);
6275 context_release(context);
6277 hr = This->shader_backend->shader_alloc_private(iface);
6280 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6284 hr = This->frag_pipe->alloc_private(iface);
6287 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6288 This->shader_backend->shader_free_private(iface);
6292 hr = This->blitter->alloc_private(iface);
6295 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6296 This->frag_pipe->free_private(iface);
6297 This->shader_backend->shader_free_private(iface);
6304 context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6305 destroy_dummy_textures(This, context->gl_info);
6306 context_release(context);
6307 context_destroy(This, context);
6308 HeapFree(GetProcessHeap(), 0, swapchain->context);
6309 swapchain->num_contexts = 0;
6313 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6315 IWineD3DSwapChainImpl *swapchain;
6317 BOOL DisplayModeChanged = FALSE;
6318 WINED3DDISPLAYMODE mode;
6319 TRACE("(%p)\n", This);
6321 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6323 ERR("Failed to get the first implicit swapchain\n");
6327 if(!is_display_mode_supported(This, pPresentationParameters)) {
6328 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6329 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6330 pPresentationParameters->BackBufferHeight);
6331 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6332 return WINED3DERR_INVALIDCALL;
6335 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6336 * on an existing gl context, so there's no real need for recreation.
6338 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6340 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6342 TRACE("New params:\n");
6343 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6344 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6345 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6346 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6347 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6348 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6349 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6350 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6351 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6352 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6353 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6354 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6355 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6357 /* No special treatment of these parameters. Just store them */
6358 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6359 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6360 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6361 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6363 /* What to do about these? */
6364 if(pPresentationParameters->BackBufferCount != 0 &&
6365 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6366 ERR("Cannot change the back buffer count yet\n");
6368 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6369 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6370 ERR("Cannot change the back buffer format yet\n");
6372 if(pPresentationParameters->hDeviceWindow != NULL &&
6373 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6374 ERR("Cannot change the device window yet\n");
6376 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6379 TRACE("Creating the depth stencil buffer\n");
6381 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6383 pPresentationParameters->BackBufferWidth,
6384 pPresentationParameters->BackBufferHeight,
6385 pPresentationParameters->AutoDepthStencilFormat,
6386 pPresentationParameters->MultiSampleType,
6387 pPresentationParameters->MultiSampleQuality,
6389 &This->auto_depth_stencil_buffer);
6392 ERR("Failed to create the depth stencil buffer\n");
6393 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6394 return WINED3DERR_INVALIDCALL;
6398 /* Reset the depth stencil */
6399 if (pPresentationParameters->EnableAutoDepthStencil)
6400 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6402 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6404 TRACE("Resetting stateblock\n");
6405 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6406 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6408 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6410 if(pPresentationParameters->Windowed) {
6411 mode.Width = swapchain->orig_width;
6412 mode.Height = swapchain->orig_height;
6413 mode.RefreshRate = 0;
6414 mode.Format = swapchain->presentParms.BackBufferFormat;
6416 mode.Width = pPresentationParameters->BackBufferWidth;
6417 mode.Height = pPresentationParameters->BackBufferHeight;
6418 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6419 mode.Format = swapchain->presentParms.BackBufferFormat;
6422 /* Should Width == 800 && Height == 0 set 800x600? */
6423 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6424 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6425 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6429 if(!pPresentationParameters->Windowed) {
6430 DisplayModeChanged = TRUE;
6432 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6433 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6435 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6438 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6442 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6443 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6446 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6450 if(This->auto_depth_stencil_buffer) {
6451 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6454 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6460 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6461 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6462 DisplayModeChanged) {
6464 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6466 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
6467 if(swapchain->presentParms.Windowed) {
6468 /* switch from windowed to fs */
6469 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6470 pPresentationParameters->BackBufferHeight);
6472 /* Fullscreen -> fullscreen mode change */
6473 MoveWindow(swapchain->win_handle, 0, 0,
6474 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6477 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
6478 /* Fullscreen -> windowed switch */
6479 swapchain_restore_fullscreen_window(swapchain);
6481 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6482 } else if(!pPresentationParameters->Windowed) {
6483 DWORD style = This->style, exStyle = This->exStyle;
6484 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6485 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6486 * Reset to clear up their mess. Guild Wars also loses the device during that.
6490 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6491 pPresentationParameters->BackBufferHeight);
6492 This->style = style;
6493 This->exStyle = exStyle;
6496 /* Note: No parent needed for initial internal stateblock */
6497 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6498 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6499 else TRACE("Created stateblock %p\n", This->stateBlock);
6500 This->updateStateBlock = This->stateBlock;
6501 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6503 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6505 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6508 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6511 GetClientRect(swapchain->win_handle, &client_rect);
6513 if(!swapchain->presentParms.BackBufferCount)
6515 TRACE("Single buffered rendering\n");
6516 swapchain->render_to_fbo = FALSE;
6518 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6519 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6521 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6522 swapchain->presentParms.BackBufferWidth,
6523 swapchain->presentParms.BackBufferHeight,
6524 client_rect.right, client_rect.bottom);
6525 swapchain->render_to_fbo = TRUE;
6529 TRACE("Rendering directly to GL_BACK\n");
6530 swapchain->render_to_fbo = FALSE;
6534 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6535 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6537 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6543 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6545 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6547 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6553 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6555 TRACE("(%p) : pParameters %p\n", This, pParameters);
6557 *pParameters = This->createParms;
6561 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6562 IWineD3DSwapChain *swapchain;
6564 TRACE("Relaying to swapchain\n");
6566 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6567 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6568 IWineD3DSwapChain_Release(swapchain);
6572 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6573 IWineD3DSwapChain *swapchain;
6575 TRACE("Relaying to swapchain\n");
6577 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6578 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6579 IWineD3DSwapChain_Release(swapchain);
6584 /** ********************************************************
6585 * Notification functions
6586 ** ********************************************************/
6587 /** This function must be called in the release of a resource when ref == 0,
6588 * the contents of resource must still be correct,
6589 * any handles to other resource held by the caller must be closed
6590 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6591 *****************************************************/
6592 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6594 TRACE("(%p) : Adding resource %p\n", This, resource);
6596 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6599 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6601 TRACE("(%p) : Removing resource %p\n", This, resource);
6603 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6606 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6608 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6611 TRACE("(%p) : resource %p\n", This, resource);
6613 context_resource_released((IWineD3DDevice *)This, resource, type);
6616 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6617 case WINED3DRTYPE_SURFACE: {
6620 if (This->d3d_initialized)
6622 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6624 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6625 This->render_targets[i] = NULL;
6628 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6629 This->stencilBufferTarget = NULL;
6635 case WINED3DRTYPE_TEXTURE:
6636 case WINED3DRTYPE_CUBETEXTURE:
6637 case WINED3DRTYPE_VOLUMETEXTURE:
6638 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6639 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6640 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6641 This->stateBlock->textures[counter] = NULL;
6643 if (This->updateStateBlock != This->stateBlock ){
6644 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6645 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6646 This->updateStateBlock->textures[counter] = NULL;
6651 case WINED3DRTYPE_VOLUME:
6652 /* TODO: nothing really? */
6654 case WINED3DRTYPE_BUFFER:
6657 TRACE("Cleaning up stream pointers\n");
6659 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6660 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6661 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6663 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6664 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6665 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6666 This->updateStateBlock->streamSource[streamNumber] = 0;
6667 /* Set changed flag? */
6670 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) */
6671 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6672 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6673 This->stateBlock->streamSource[streamNumber] = 0;
6678 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6679 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6680 This->updateStateBlock->pIndexData = NULL;
6683 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6684 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6685 This->stateBlock->pIndexData = NULL;
6692 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6697 /* Remove the resource from the resourceStore */
6698 device_resource_remove(This, resource);
6700 TRACE("Resource released\n");
6704 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6706 IWineD3DResourceImpl *resource, *cursor;
6708 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6710 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6711 TRACE("enumerating resource %p\n", resource);
6712 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6713 ret = pCallback((IWineD3DResource *) resource, pData);
6714 if(ret == S_FALSE) {
6715 TRACE("Canceling enumeration\n");
6722 /**********************************************************
6723 * IWineD3DDevice VTbl follows
6724 **********************************************************/
6726 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6728 /*** IUnknown methods ***/
6729 IWineD3DDeviceImpl_QueryInterface,
6730 IWineD3DDeviceImpl_AddRef,
6731 IWineD3DDeviceImpl_Release,
6732 /*** IWineD3DDevice methods ***/
6733 IWineD3DDeviceImpl_GetParent,
6734 /*** Creation methods**/
6735 IWineD3DDeviceImpl_CreateBuffer,
6736 IWineD3DDeviceImpl_CreateVertexBuffer,
6737 IWineD3DDeviceImpl_CreateIndexBuffer,
6738 IWineD3DDeviceImpl_CreateStateBlock,
6739 IWineD3DDeviceImpl_CreateSurface,
6740 IWineD3DDeviceImpl_CreateRendertargetView,
6741 IWineD3DDeviceImpl_CreateTexture,
6742 IWineD3DDeviceImpl_CreateVolumeTexture,
6743 IWineD3DDeviceImpl_CreateVolume,
6744 IWineD3DDeviceImpl_CreateCubeTexture,
6745 IWineD3DDeviceImpl_CreateQuery,
6746 IWineD3DDeviceImpl_CreateSwapChain,
6747 IWineD3DDeviceImpl_CreateVertexDeclaration,
6748 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6749 IWineD3DDeviceImpl_CreateVertexShader,
6750 IWineD3DDeviceImpl_CreateGeometryShader,
6751 IWineD3DDeviceImpl_CreatePixelShader,
6752 IWineD3DDeviceImpl_CreatePalette,
6753 /*** Odd functions **/
6754 IWineD3DDeviceImpl_Init3D,
6755 IWineD3DDeviceImpl_InitGDI,
6756 IWineD3DDeviceImpl_Uninit3D,
6757 IWineD3DDeviceImpl_UninitGDI,
6758 IWineD3DDeviceImpl_SetMultithreaded,
6759 IWineD3DDeviceImpl_EvictManagedResources,
6760 IWineD3DDeviceImpl_GetAvailableTextureMem,
6761 IWineD3DDeviceImpl_GetBackBuffer,
6762 IWineD3DDeviceImpl_GetCreationParameters,
6763 IWineD3DDeviceImpl_GetDeviceCaps,
6764 IWineD3DDeviceImpl_GetDirect3D,
6765 IWineD3DDeviceImpl_GetDisplayMode,
6766 IWineD3DDeviceImpl_SetDisplayMode,
6767 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6768 IWineD3DDeviceImpl_GetRasterStatus,
6769 IWineD3DDeviceImpl_GetSwapChain,
6770 IWineD3DDeviceImpl_Reset,
6771 IWineD3DDeviceImpl_SetDialogBoxMode,
6772 IWineD3DDeviceImpl_SetCursorProperties,
6773 IWineD3DDeviceImpl_SetCursorPosition,
6774 IWineD3DDeviceImpl_ShowCursor,
6775 /*** Getters and setters **/
6776 IWineD3DDeviceImpl_SetClipPlane,
6777 IWineD3DDeviceImpl_GetClipPlane,
6778 IWineD3DDeviceImpl_SetClipStatus,
6779 IWineD3DDeviceImpl_GetClipStatus,
6780 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6781 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6782 IWineD3DDeviceImpl_SetDepthStencilSurface,
6783 IWineD3DDeviceImpl_GetDepthStencilSurface,
6784 IWineD3DDeviceImpl_SetGammaRamp,
6785 IWineD3DDeviceImpl_GetGammaRamp,
6786 IWineD3DDeviceImpl_SetIndexBuffer,
6787 IWineD3DDeviceImpl_GetIndexBuffer,
6788 IWineD3DDeviceImpl_SetBaseVertexIndex,
6789 IWineD3DDeviceImpl_GetBaseVertexIndex,
6790 IWineD3DDeviceImpl_SetLight,
6791 IWineD3DDeviceImpl_GetLight,
6792 IWineD3DDeviceImpl_SetLightEnable,
6793 IWineD3DDeviceImpl_GetLightEnable,
6794 IWineD3DDeviceImpl_SetMaterial,
6795 IWineD3DDeviceImpl_GetMaterial,
6796 IWineD3DDeviceImpl_SetNPatchMode,
6797 IWineD3DDeviceImpl_GetNPatchMode,
6798 IWineD3DDeviceImpl_SetPaletteEntries,
6799 IWineD3DDeviceImpl_GetPaletteEntries,
6800 IWineD3DDeviceImpl_SetPixelShader,
6801 IWineD3DDeviceImpl_GetPixelShader,
6802 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6803 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6804 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6805 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6806 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6807 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6808 IWineD3DDeviceImpl_SetRenderState,
6809 IWineD3DDeviceImpl_GetRenderState,
6810 IWineD3DDeviceImpl_SetRenderTarget,
6811 IWineD3DDeviceImpl_GetRenderTarget,
6812 IWineD3DDeviceImpl_SetFrontBackBuffers,
6813 IWineD3DDeviceImpl_SetSamplerState,
6814 IWineD3DDeviceImpl_GetSamplerState,
6815 IWineD3DDeviceImpl_SetScissorRect,
6816 IWineD3DDeviceImpl_GetScissorRect,
6817 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6818 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6819 IWineD3DDeviceImpl_SetStreamSource,
6820 IWineD3DDeviceImpl_GetStreamSource,
6821 IWineD3DDeviceImpl_SetStreamSourceFreq,
6822 IWineD3DDeviceImpl_GetStreamSourceFreq,
6823 IWineD3DDeviceImpl_SetTexture,
6824 IWineD3DDeviceImpl_GetTexture,
6825 IWineD3DDeviceImpl_SetTextureStageState,
6826 IWineD3DDeviceImpl_GetTextureStageState,
6827 IWineD3DDeviceImpl_SetTransform,
6828 IWineD3DDeviceImpl_GetTransform,
6829 IWineD3DDeviceImpl_SetVertexDeclaration,
6830 IWineD3DDeviceImpl_GetVertexDeclaration,
6831 IWineD3DDeviceImpl_SetVertexShader,
6832 IWineD3DDeviceImpl_GetVertexShader,
6833 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6834 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6835 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6836 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6837 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6838 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6839 IWineD3DDeviceImpl_SetViewport,
6840 IWineD3DDeviceImpl_GetViewport,
6841 IWineD3DDeviceImpl_MultiplyTransform,
6842 IWineD3DDeviceImpl_ValidateDevice,
6843 IWineD3DDeviceImpl_ProcessVertices,
6844 /*** State block ***/
6845 IWineD3DDeviceImpl_BeginStateBlock,
6846 IWineD3DDeviceImpl_EndStateBlock,
6847 /*** Scene management ***/
6848 IWineD3DDeviceImpl_BeginScene,
6849 IWineD3DDeviceImpl_EndScene,
6850 IWineD3DDeviceImpl_Present,
6851 IWineD3DDeviceImpl_Clear,
6852 IWineD3DDeviceImpl_ClearRendertargetView,
6854 IWineD3DDeviceImpl_SetPrimitiveType,
6855 IWineD3DDeviceImpl_GetPrimitiveType,
6856 IWineD3DDeviceImpl_DrawPrimitive,
6857 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6858 IWineD3DDeviceImpl_DrawPrimitiveUP,
6859 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6860 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6861 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6862 IWineD3DDeviceImpl_DrawRectPatch,
6863 IWineD3DDeviceImpl_DrawTriPatch,
6864 IWineD3DDeviceImpl_DeletePatch,
6865 IWineD3DDeviceImpl_ColorFill,
6866 IWineD3DDeviceImpl_UpdateTexture,
6867 IWineD3DDeviceImpl_UpdateSurface,
6868 IWineD3DDeviceImpl_GetFrontBufferData,
6869 /*** object tracking ***/
6870 IWineD3DDeviceImpl_EnumResources
6873 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6874 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6875 IUnknown *parent, IWineD3DDeviceParent *device_parent)
6877 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6878 const struct fragment_pipeline *fragment_pipeline;
6879 struct shader_caps shader_caps;
6880 struct fragment_caps ffp_caps;
6881 WINED3DDISPLAYMODE mode;
6885 device->lpVtbl = &IWineD3DDevice_Vtbl;
6887 device->wined3d = (IWineD3D *)wined3d;
6888 IWineD3D_AddRef(device->wined3d);
6889 device->adapter = wined3d->adapter_count ? adapter : NULL;
6890 device->parent = parent;
6891 device->device_parent = device_parent;
6892 list_init(&device->resources);
6893 list_init(&device->shaders);
6895 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6896 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6898 /* Get the initial screen setup for ddraw. */
6899 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6902 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6903 IWineD3D_Release(device->wined3d);
6906 device->ddraw_width = mode.Width;
6907 device->ddraw_height = mode.Height;
6908 device->ddraw_format = mode.Format;
6910 /* Save the creation parameters. */
6911 device->createParms.AdapterOrdinal = adapter_idx;
6912 device->createParms.DeviceType = device_type;
6913 device->createParms.hFocusWindow = focus_window;
6914 device->createParms.BehaviorFlags = flags;
6916 device->devType = device_type;
6917 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6919 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6920 device->shader_backend = select_shader_backend(adapter, device_type);
6922 memset(&shader_caps, 0, sizeof(shader_caps));
6923 device->shader_backend->shader_get_caps(device_type, &adapter->gl_info, &shader_caps);
6924 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6925 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6926 device->vs_clipping = shader_caps.VSClipping;
6928 memset(&ffp_caps, 0, sizeof(ffp_caps));
6929 fragment_pipeline = select_fragment_implementation(adapter, device_type);
6930 device->frag_pipe = fragment_pipeline;
6931 fragment_pipeline->get_caps(device_type, &adapter->gl_info, &ffp_caps);
6932 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6933 device->max_ffp_texture_stages = ffp_caps.MaxTextureBlendStages;
6935 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6936 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6939 ERR("Failed to compile state table, hr %#x.\n", hr);
6940 IWineD3D_Release(device->wined3d);
6944 device->blitter = select_blit_implementation(adapter, device_type);
6950 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6951 DWORD rep = This->StateTable[state].representative;
6952 struct wined3d_context *context;
6957 for(i = 0; i < This->numContexts; i++) {
6958 context = This->contexts[i];
6959 if(isStateDirty(context, rep)) continue;
6961 context->dirtyArray[context->numDirtyEntries++] = rep;
6962 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6963 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6964 context->isStateDirty[idx] |= (1 << shift);
6968 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6970 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.device;
6971 /* The drawable size of a pbuffer render target is the current pbuffer size. */
6972 *width = device->pbufferWidth;
6973 *height = device->pbufferHeight;
6976 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6978 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
6979 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6980 *width = surface->pow2Width;
6981 *height = surface->pow2Height;
6984 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6986 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
6987 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6988 * current context's drawable, which is the size of the back buffer of the swapchain
6989 * the active context belongs to. The back buffer of the swapchain is stored as the
6990 * surface the context belongs to. */
6991 *width = surface->currentDesc.Width;
6992 *height = surface->currentDesc.Height;
6995 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
6996 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6998 if (device->filter_messages)
7000 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7001 window, message, wparam, lparam);
7002 return DefWindowProcW(window, message, wparam, lparam);
7005 if (message == WM_DESTROY)
7007 TRACE("unregister window %p.\n", window);
7008 wined3d_unregister_window(window);
7010 if (device->focus_window == window) device->focus_window = NULL;
7011 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7014 return CallWindowProcW(proc, window, message, wparam, lparam);