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("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
600 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
601 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
602 ppSurface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
603 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
605 if (Impl == SURFACE_OPENGL && !This->adapter)
607 ERR("OpenGL surfaces are not available without OpenGL.\n");
608 return WINED3DERR_NOTAVAILABLE;
611 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
614 ERR("Failed to allocate surface memory.\n");
615 return WINED3DERR_OUTOFVIDEOMEMORY;
618 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
619 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
622 WARN("Failed to initialize surface, returning %#x.\n", hr);
623 HeapFree(GetProcessHeap(), 0, object);
627 TRACE("(%p) : Created surface %p\n", This, object);
629 *ppSurface = (IWineD3DSurface *)object;
634 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
635 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
637 struct wined3d_rendertarget_view *object;
639 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
642 ERR("Failed to allocate memory\n");
643 return E_OUTOFMEMORY;
646 object->vtbl = &wined3d_rendertarget_view_vtbl;
647 object->refcount = 1;
648 IWineD3DResource_AddRef(resource);
649 object->resource = resource;
650 object->parent = parent;
652 *rendertarget_view = (IWineD3DRendertargetView *)object;
657 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
658 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
659 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
662 IWineD3DTextureImpl *object;
665 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
666 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
667 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
669 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
672 ERR("Out of memory\n");
674 return WINED3DERR_OUTOFVIDEOMEMORY;
677 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
680 WARN("Failed to initialize texture, returning %#x\n", hr);
681 HeapFree(GetProcessHeap(), 0, object);
686 *ppTexture = (IWineD3DTexture *)object;
688 TRACE("(%p) : Created texture %p\n", This, object);
693 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
694 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
695 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
698 IWineD3DVolumeTextureImpl *object;
701 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
702 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
704 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
707 ERR("Out of memory\n");
708 *ppVolumeTexture = NULL;
709 return WINED3DERR_OUTOFVIDEOMEMORY;
712 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
715 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
716 HeapFree(GetProcessHeap(), 0, object);
717 *ppVolumeTexture = NULL;
721 TRACE("(%p) : Created volume texture %p.\n", This, object);
722 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
727 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
728 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
729 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
732 IWineD3DVolumeImpl *object;
735 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
736 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
738 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
741 ERR("Out of memory\n");
743 return WINED3DERR_OUTOFVIDEOMEMORY;
746 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
749 WARN("Failed to initialize volume, returning %#x.\n", hr);
750 HeapFree(GetProcessHeap(), 0, object);
754 TRACE("(%p) : Created volume %p.\n", This, object);
755 *ppVolume = (IWineD3DVolume *)object;
760 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
761 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
762 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
765 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
768 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
771 ERR("Out of memory\n");
772 *ppCubeTexture = NULL;
773 return WINED3DERR_OUTOFVIDEOMEMORY;
776 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
779 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
780 HeapFree(GetProcessHeap(), 0, object);
781 *ppCubeTexture = NULL;
785 TRACE("(%p) : Created Cube Texture %p\n", This, object);
786 *ppCubeTexture = (IWineD3DCubeTexture *)object;
791 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
792 WINED3DQUERYTYPE type, IWineD3DQuery **query, IUnknown *parent)
794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
795 IWineD3DQueryImpl *object;
798 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface, type, query, parent);
800 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
803 ERR("Failed to allocate query memory.\n");
804 return E_OUTOFMEMORY;
807 hr = query_init(object, This, type, parent);
810 WARN("Failed to initialize query, hr %#x.\n", hr);
811 HeapFree(GetProcessHeap(), 0, object);
815 TRACE("Created query %p.\n", object);
816 *query = (IWineD3DQuery *)object;
821 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
822 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
823 IUnknown *parent, WINED3DSURFTYPE surface_type)
825 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
826 IWineD3DSwapChainImpl *object;
829 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
830 iface, present_parameters, swapchain, parent, surface_type);
832 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
835 ERR("Failed to allocate swapchain memory.\n");
836 return E_OUTOFMEMORY;
839 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
842 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
843 HeapFree(GetProcessHeap(), 0, object);
847 TRACE("Created swapchain %p.\n", object);
848 *swapchain = (IWineD3DSwapChain *)object;
853 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
854 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
856 TRACE("(%p)\n", This);
858 return This->NumberOfSwapChains;
861 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
863 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
865 if(iSwapChain < This->NumberOfSwapChains) {
866 *pSwapChain = This->swapchains[iSwapChain];
867 IWineD3DSwapChain_AddRef(*pSwapChain);
868 TRACE("(%p) returning %p\n", This, *pSwapChain);
871 TRACE("Swapchain out of range\n");
873 return WINED3DERR_INVALIDCALL;
877 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
878 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
879 const WINED3DVERTEXELEMENT *elements, UINT element_count)
881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
882 IWineD3DVertexDeclarationImpl *object = NULL;
885 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
886 iface, declaration, parent, elements, element_count);
888 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
891 ERR("Failed to allocate vertex declaration memory.\n");
892 return E_OUTOFMEMORY;
895 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
898 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
899 HeapFree(GetProcessHeap(), 0, object);
903 TRACE("Created vertex declaration %p.\n", object);
904 *declaration = (IWineD3DVertexDeclaration *)object;
909 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
910 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
912 unsigned int idx, idx2;
914 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
915 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
916 BOOL has_blend_idx = has_blend &&
917 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
918 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
919 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
920 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
921 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
922 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
923 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
925 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
926 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
927 WINED3DVERTEXELEMENT *elements = NULL;
930 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
931 if (has_blend_idx) num_blends--;
933 /* Compute declaration size */
934 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
935 has_psize + has_diffuse + has_specular + num_textures;
937 /* convert the declaration */
938 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
939 if (!elements) return ~0U;
943 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
944 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
945 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
947 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
948 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
949 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
952 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
953 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
955 elements[idx].usage_idx = 0;
958 if (has_blend && (num_blends > 0)) {
959 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
960 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
963 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
964 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
965 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
966 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
968 ERR("Unexpected amount of blend values: %u\n", num_blends);
971 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
972 elements[idx].usage_idx = 0;
976 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
977 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
978 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
979 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
980 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
982 elements[idx].format = WINED3DFMT_R32_FLOAT;
983 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
984 elements[idx].usage_idx = 0;
988 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
989 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
990 elements[idx].usage_idx = 0;
994 elements[idx].format = WINED3DFMT_R32_FLOAT;
995 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
996 elements[idx].usage_idx = 0;
1000 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1001 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1002 elements[idx].usage_idx = 0;
1006 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1007 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1008 elements[idx].usage_idx = 1;
1011 for (idx2 = 0; idx2 < num_textures; idx2++) {
1012 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1013 switch (numcoords) {
1014 case WINED3DFVF_TEXTUREFORMAT1:
1015 elements[idx].format = WINED3DFMT_R32_FLOAT;
1017 case WINED3DFVF_TEXTUREFORMAT2:
1018 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1020 case WINED3DFVF_TEXTUREFORMAT3:
1021 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1023 case WINED3DFVF_TEXTUREFORMAT4:
1024 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1027 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1028 elements[idx].usage_idx = idx2;
1032 /* Now compute offsets, and initialize the rest of the fields */
1033 for (idx = 0, offset = 0; idx < size; ++idx)
1035 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1036 elements[idx].input_slot = 0;
1037 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1038 elements[idx].offset = offset;
1039 offset += format_desc->component_count * format_desc->component_size;
1042 *ppVertexElements = elements;
1046 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1047 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1048 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1051 WINED3DVERTEXELEMENT *elements;
1055 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1057 size = ConvertFvfToDeclaration(This, fvf, &elements);
1058 if (size == ~0U) return E_OUTOFMEMORY;
1060 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1061 HeapFree(GetProcessHeap(), 0, elements);
1065 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1066 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1067 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1068 const struct wined3d_parent_ops *parent_ops)
1070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1071 IWineD3DVertexShaderImpl *object;
1074 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1077 ERR("Failed to allocate shader memory.\n");
1078 return E_OUTOFMEMORY;
1081 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1084 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1085 HeapFree(GetProcessHeap(), 0, object);
1089 TRACE("Created vertex shader %p.\n", object);
1090 *ppVertexShader = (IWineD3DVertexShader *)object;
1095 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1096 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1097 IWineD3DGeometryShader **shader, IUnknown *parent,
1098 const struct wined3d_parent_ops *parent_ops)
1100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1101 struct wined3d_geometryshader *object;
1104 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1107 ERR("Failed to allocate shader memory.\n");
1108 return E_OUTOFMEMORY;
1111 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1114 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1115 HeapFree(GetProcessHeap(), 0, object);
1119 TRACE("Created geometry shader %p.\n", object);
1120 *shader = (IWineD3DGeometryShader *)object;
1125 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1126 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1127 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1128 const struct wined3d_parent_ops *parent_ops)
1130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1131 IWineD3DPixelShaderImpl *object;
1134 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1137 ERR("Failed to allocate shader memory.\n");
1138 return E_OUTOFMEMORY;
1141 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1144 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1145 HeapFree(GetProcessHeap(), 0, object);
1149 TRACE("Created pixel shader %p.\n", object);
1150 *ppPixelShader = (IWineD3DPixelShader *)object;
1155 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1156 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1159 IWineD3DPaletteImpl *object;
1161 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1163 /* Create the new object */
1164 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1166 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1167 return E_OUTOFMEMORY;
1170 object->lpVtbl = &IWineD3DPalette_Vtbl;
1172 object->Flags = Flags;
1173 object->parent = Parent;
1174 object->device = This;
1175 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1176 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1179 HeapFree( GetProcessHeap(), 0, object);
1180 return E_OUTOFMEMORY;
1183 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1185 IWineD3DPalette_Release((IWineD3DPalette *) object);
1189 *Palette = (IWineD3DPalette *) object;
1194 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1198 HDC dcb = NULL, dcs = NULL;
1199 WINEDDCOLORKEY colorkey;
1201 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1204 GetObjectA(hbm, sizeof(BITMAP), &bm);
1205 dcb = CreateCompatibleDC(NULL);
1207 SelectObject(dcb, hbm);
1211 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1212 * couldn't be loaded
1214 memset(&bm, 0, sizeof(bm));
1219 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1220 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1221 NULL, &wined3d_null_parent_ops);
1223 ERR("Wine logo requested, but failed to create surface\n");
1228 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1229 if(FAILED(hr)) goto out;
1230 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1231 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1233 colorkey.dwColorSpaceLowValue = 0;
1234 colorkey.dwColorSpaceHighValue = 0;
1235 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1237 /* Fill the surface with a white color to show that wined3d is there */
1238 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1242 if (dcb) DeleteDC(dcb);
1243 if (hbm) DeleteObject(hbm);
1246 /* Context activation is done by the caller. */
1247 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1249 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1251 /* Under DirectX you can have texture stage operations even if no texture is
1252 bound, whereas opengl will only do texture operations when a valid texture is
1253 bound. We emulate this by creating dummy textures and binding them to each
1254 texture stage, but disable all stages by default. Hence if a stage is enabled
1255 then the default texture will kick in until replaced by a SetTexture call */
1258 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1260 /* The dummy texture does not have client storage backing */
1261 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1262 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1265 for (i = 0; i < gl_info->limits.textures; ++i)
1267 GLubyte white = 255;
1269 /* Make appropriate texture active */
1270 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1271 checkGLcall("glActiveTextureARB");
1273 /* Generate an opengl texture name */
1274 glGenTextures(1, &This->dummyTextureName[i]);
1275 checkGLcall("glGenTextures");
1276 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1278 /* Generate a dummy 2d texture (not using 1d because they cause many
1279 * DRI drivers fall back to sw) */
1280 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1281 checkGLcall("glBindTexture");
1283 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1284 checkGLcall("glTexImage2D");
1287 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1289 /* Reenable because if supported it is enabled by default */
1290 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1291 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1297 /* Context activation is done by the caller. */
1298 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1301 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1302 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1305 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1308 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1309 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1312 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1313 IWineD3DSwapChainImpl *swapchain = NULL;
1314 struct wined3d_context *context;
1319 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1321 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1322 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1324 if (!pPresentationParameters->Windowed)
1326 This->focus_window = This->createParms.hFocusWindow;
1327 if (!This->focus_window) This->focus_window = pPresentationParameters->hDeviceWindow;
1328 if (!wined3d_register_window(This->focus_window, This))
1330 ERR("Failed to register window %p.\n", This->focus_window);
1335 TRACE("(%p) : Creating stateblock\n", This);
1336 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1337 hr = IWineD3DDevice_CreateStateBlock(iface,
1339 (IWineD3DStateBlock **)&This->stateBlock,
1341 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1342 WARN("Failed to create stateblock\n");
1345 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1346 This->updateStateBlock = This->stateBlock;
1347 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1349 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1350 sizeof(IWineD3DSurface *) * gl_info->limits.buffers);
1351 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1352 sizeof(GLenum) * gl_info->limits.buffers);
1354 This->NumberOfPalettes = 1;
1355 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1356 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1357 ERR("Out of memory!\n");
1361 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1362 if(!This->palettes[0]) {
1363 ERR("Out of memory!\n");
1367 for (i = 0; i < 256; ++i) {
1368 This->palettes[0][i].peRed = 0xFF;
1369 This->palettes[0][i].peGreen = 0xFF;
1370 This->palettes[0][i].peBlue = 0xFF;
1371 This->palettes[0][i].peFlags = 0xFF;
1373 This->currentPalette = 0;
1375 /* Initialize the texture unit mapping to a 1:1 mapping */
1376 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1378 if (state < gl_info->limits.fragment_samplers)
1380 This->texUnitMap[state] = state;
1381 This->rev_tex_unit_map[state] = state;
1383 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1384 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1388 if (This->focus_window) SetFocus(This->focus_window);
1390 /* Setup the implicit swapchain. This also initializes a context. */
1391 TRACE("Creating implicit swapchain\n");
1392 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1393 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1396 WARN("Failed to create implicit swapchain\n");
1400 This->NumberOfSwapChains = 1;
1401 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1402 if(!This->swapchains) {
1403 ERR("Out of memory!\n");
1406 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1408 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1409 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1410 This->render_targets[0] = swapchain->backBuffer[0];
1413 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1414 This->render_targets[0] = swapchain->frontBuffer;
1416 IWineD3DSurface_AddRef(This->render_targets[0]);
1418 /* Depth Stencil support */
1419 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1420 if (NULL != This->stencilBufferTarget) {
1421 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1424 hr = This->shader_backend->shader_alloc_private(iface);
1426 TRACE("Shader private data couldn't be allocated\n");
1429 hr = This->frag_pipe->alloc_private(iface);
1431 TRACE("Fragment pipeline private data couldn't be allocated\n");
1434 hr = This->blitter->alloc_private(iface);
1436 TRACE("Blitter private data couldn't be allocated\n");
1440 /* Set up some starting GL setup */
1442 /* Setup all the devices defaults */
1443 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1445 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1447 create_dummy_textures(This);
1451 /* Initialize the current view state */
1452 This->view_ident = 1;
1453 This->contexts[0]->last_was_rhw = 0;
1454 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1455 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1457 switch(wined3d_settings.offscreen_rendering_mode) {
1459 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1463 This->offscreenBuffer = GL_BACK;
1466 case ORM_BACKBUFFER:
1468 if (context_get_current()->aux_buffers > 0)
1470 TRACE("Using auxilliary buffer for offscreen rendering\n");
1471 This->offscreenBuffer = GL_AUX0;
1473 TRACE("Using back buffer for offscreen rendering\n");
1474 This->offscreenBuffer = GL_BACK;
1479 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1482 context_release(context);
1484 /* Clear the screen */
1485 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1486 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1489 This->d3d_initialized = TRUE;
1491 if(wined3d_settings.logo) {
1492 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1494 This->highest_dirty_ps_const = 0;
1495 This->highest_dirty_vs_const = 0;
1499 HeapFree(GetProcessHeap(), 0, This->render_targets);
1500 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1501 HeapFree(GetProcessHeap(), 0, This->swapchains);
1502 This->NumberOfSwapChains = 0;
1503 if(This->palettes) {
1504 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1505 HeapFree(GetProcessHeap(), 0, This->palettes);
1507 This->NumberOfPalettes = 0;
1509 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1511 if(This->stateBlock) {
1512 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1513 This->stateBlock = NULL;
1515 if (This->blit_priv) {
1516 This->blitter->free_private(iface);
1518 if (This->fragment_priv) {
1519 This->frag_pipe->free_private(iface);
1521 if (This->shader_priv) {
1522 This->shader_backend->shader_free_private(iface);
1524 if (This->focus_window) wined3d_unregister_window(This->focus_window);
1528 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1529 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1532 IWineD3DSwapChainImpl *swapchain = NULL;
1535 /* Setup the implicit swapchain */
1536 TRACE("Creating implicit swapchain\n");
1537 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1538 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1541 WARN("Failed to create implicit swapchain\n");
1545 This->NumberOfSwapChains = 1;
1546 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1547 if(!This->swapchains) {
1548 ERR("Out of memory!\n");
1551 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1555 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1559 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1561 IWineD3DResource_UnLoad(resource);
1562 IWineD3DResource_Release(resource);
1566 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1567 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1570 const struct wined3d_gl_info *gl_info;
1571 struct wined3d_context *context;
1574 TRACE("(%p)\n", This);
1576 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1578 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1579 * it was created. Thus make sure a context is active for the glDelete* calls
1581 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1582 gl_info = context->gl_info;
1584 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1586 /* Unload resources */
1587 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1589 TRACE("Deleting high order patches\n");
1590 for(i = 0; i < PATCHMAP_SIZE; i++) {
1591 struct list *e1, *e2;
1592 struct WineD3DRectPatch *patch;
1593 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1594 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1595 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1599 /* Delete the palette conversion shader if it is around */
1600 if(This->paletteConversionShader) {
1602 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
1604 This->paletteConversionShader = 0;
1607 /* Delete the pbuffer context if there is any */
1608 if(This->pbufferContext) context_destroy(This, This->pbufferContext);
1610 /* Delete the mouse cursor texture */
1611 if(This->cursorTexture) {
1613 glDeleteTextures(1, &This->cursorTexture);
1615 This->cursorTexture = 0;
1618 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1619 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1621 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1622 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1625 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1626 * private data, it might contain opengl pointers
1628 if(This->depth_blt_texture) {
1630 glDeleteTextures(1, &This->depth_blt_texture);
1632 This->depth_blt_texture = 0;
1634 if (This->depth_blt_rb) {
1636 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1638 This->depth_blt_rb = 0;
1639 This->depth_blt_rb_w = 0;
1640 This->depth_blt_rb_h = 0;
1643 /* Release the update stateblock */
1644 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1645 if(This->updateStateBlock != This->stateBlock)
1646 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1648 This->updateStateBlock = NULL;
1650 { /* because were not doing proper internal refcounts releasing the primary state block
1651 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1652 to set this->stateBlock = NULL; first */
1653 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1654 This->stateBlock = NULL;
1656 /* Release the stateblock */
1657 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1658 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1662 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1663 This->blitter->free_private(iface);
1664 This->frag_pipe->free_private(iface);
1665 This->shader_backend->shader_free_private(iface);
1667 /* Release the buffers (with sanity checks)*/
1668 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1669 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1670 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
1671 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
1673 This->stencilBufferTarget = NULL;
1675 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1676 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1677 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1679 TRACE("Setting rendertarget to NULL\n");
1680 This->render_targets[0] = NULL;
1682 if (This->auto_depth_stencil_buffer) {
1683 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
1685 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1687 This->auto_depth_stencil_buffer = NULL;
1690 context_release(context);
1692 for(i=0; i < This->NumberOfSwapChains; i++) {
1693 TRACE("Releasing the implicit swapchain %d\n", i);
1694 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1695 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1699 HeapFree(GetProcessHeap(), 0, This->swapchains);
1700 This->swapchains = NULL;
1701 This->NumberOfSwapChains = 0;
1703 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1704 HeapFree(GetProcessHeap(), 0, This->palettes);
1705 This->palettes = NULL;
1706 This->NumberOfPalettes = 0;
1708 HeapFree(GetProcessHeap(), 0, This->render_targets);
1709 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1710 This->render_targets = NULL;
1711 This->draw_buffers = NULL;
1713 This->d3d_initialized = FALSE;
1715 if (This->focus_window) wined3d_unregister_window(This->focus_window);
1720 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1724 for(i=0; i < This->NumberOfSwapChains; i++) {
1725 TRACE("Releasing the implicit swapchain %d\n", i);
1726 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1727 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1731 HeapFree(GetProcessHeap(), 0, This->swapchains);
1732 This->swapchains = NULL;
1733 This->NumberOfSwapChains = 0;
1737 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1738 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1739 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1741 * There is no way to deactivate thread safety once it is enabled.
1743 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1746 /*For now just store the flag(needed in case of ddraw) */
1747 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1750 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1751 const WINED3DDISPLAYMODE* pMode) {
1753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1755 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1758 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1760 /* Resize the screen even without a window:
1761 * The app could have unset it with SetCooperativeLevel, but not called
1762 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1763 * but we don't have any hwnd
1766 memset(&devmode, 0, sizeof(devmode));
1767 devmode.dmSize = sizeof(devmode);
1768 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1769 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1770 devmode.dmPelsWidth = pMode->Width;
1771 devmode.dmPelsHeight = pMode->Height;
1773 devmode.dmDisplayFrequency = pMode->RefreshRate;
1774 if (pMode->RefreshRate != 0) {
1775 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1778 /* Only change the mode if necessary */
1779 if( (This->ddraw_width == pMode->Width) &&
1780 (This->ddraw_height == pMode->Height) &&
1781 (This->ddraw_format == pMode->Format) &&
1782 (pMode->RefreshRate == 0) ) {
1786 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1787 if (ret != DISP_CHANGE_SUCCESSFUL) {
1788 if(devmode.dmDisplayFrequency != 0) {
1789 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1790 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1791 devmode.dmDisplayFrequency = 0;
1792 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1794 if(ret != DISP_CHANGE_SUCCESSFUL) {
1795 return WINED3DERR_NOTAVAILABLE;
1799 /* Store the new values */
1800 This->ddraw_width = pMode->Width;
1801 This->ddraw_height = pMode->Height;
1802 This->ddraw_format = pMode->Format;
1804 /* And finally clip mouse to our screen */
1805 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1806 ClipCursor(&clip_rc);
1811 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1813 *ppD3D = This->wined3d;
1814 TRACE("Returning %p.\n", *ppD3D);
1815 IWineD3D_AddRef(*ppD3D);
1819 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1822 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1823 (This->adapter->TextureRam/(1024*1024)),
1824 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
1825 /* return simulated texture memory left */
1826 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
1830 * Get / Set Stream Source
1832 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
1833 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
1835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1836 IWineD3DBuffer *oldSrc;
1838 if (StreamNumber >= MAX_STREAMS) {
1839 WARN("Stream out of range %d\n", StreamNumber);
1840 return WINED3DERR_INVALIDCALL;
1841 } else if(OffsetInBytes & 0x3) {
1842 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
1843 return WINED3DERR_INVALIDCALL;
1846 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
1847 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
1849 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
1851 if(oldSrc == pStreamData &&
1852 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
1853 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
1854 TRACE("Application is setting the old values over, nothing to do\n");
1858 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
1860 This->updateStateBlock->streamStride[StreamNumber] = Stride;
1861 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
1864 /* Handle recording of state blocks */
1865 if (This->isRecordingState) {
1866 TRACE("Recording... not performing anything\n");
1867 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
1868 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
1872 if (pStreamData != NULL) {
1873 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
1874 IWineD3DBuffer_AddRef(pStreamData);
1876 if (oldSrc != NULL) {
1877 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
1878 IWineD3DBuffer_Release(oldSrc);
1881 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
1886 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
1887 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
1889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1891 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
1892 This->stateBlock->streamSource[StreamNumber],
1893 This->stateBlock->streamOffset[StreamNumber],
1894 This->stateBlock->streamStride[StreamNumber]);
1896 if (StreamNumber >= MAX_STREAMS) {
1897 WARN("Stream out of range %d\n", StreamNumber);
1898 return WINED3DERR_INVALIDCALL;
1900 *pStream = This->stateBlock->streamSource[StreamNumber];
1901 *pStride = This->stateBlock->streamStride[StreamNumber];
1903 *pOffset = This->stateBlock->streamOffset[StreamNumber];
1906 if (*pStream != NULL) {
1907 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
1912 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
1913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1914 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
1915 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
1917 /* Verify input at least in d3d9 this is invalid*/
1918 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
1919 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
1920 return WINED3DERR_INVALIDCALL;
1922 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
1923 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
1924 return WINED3DERR_INVALIDCALL;
1927 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
1928 return WINED3DERR_INVALIDCALL;
1931 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
1932 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
1934 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
1935 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
1937 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
1938 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
1939 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
1945 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
1946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1948 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
1949 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
1951 TRACE("(%p) : returning %d\n", This, *Divider);
1957 * Get / Set & Multiply Transform
1959 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
1960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1962 /* Most of this routine, comments included copied from ddraw tree initially: */
1963 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
1965 /* Handle recording of state blocks */
1966 if (This->isRecordingState) {
1967 TRACE("Recording... not performing anything\n");
1968 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
1969 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
1974 * If the new matrix is the same as the current one,
1975 * we cut off any further processing. this seems to be a reasonable
1976 * optimization because as was noticed, some apps (warcraft3 for example)
1977 * tend towards setting the same matrix repeatedly for some reason.
1979 * From here on we assume that the new matrix is different, wherever it matters.
1981 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
1982 TRACE("The app is setting the same matrix over again\n");
1985 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
1989 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
1990 where ViewMat = Camera space, WorldMat = world space.
1992 In OpenGL, camera and world space is combined into GL_MODELVIEW
1993 matrix. The Projection matrix stay projection matrix.
1996 /* Capture the times we can just ignore the change for now */
1997 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
1998 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
1999 /* Handled by the state manager */
2002 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2006 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2008 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2009 *pMatrix = This->stateBlock->transforms[State];
2013 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2014 const WINED3DMATRIX *mat = NULL;
2017 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2018 * below means it will be recorded in a state block change, but it
2019 * works regardless where it is recorded.
2020 * If this is found to be wrong, change to StateBlock.
2022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2023 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2025 if (State <= HIGHEST_TRANSFORMSTATE)
2027 mat = &This->updateStateBlock->transforms[State];
2029 FIXME("Unhandled transform state!!\n");
2032 multiply_matrix(&temp, mat, pMatrix);
2034 /* Apply change via set transform - will reapply to eg. lights this way */
2035 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2041 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2042 you can reference any indexes you want as long as that number max are enabled at any
2043 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2044 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2045 but when recording, just build a chain pretty much of commands to be replayed. */
2047 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2049 struct wined3d_light_info *object = NULL;
2050 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2054 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2056 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2060 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2061 return WINED3DERR_INVALIDCALL;
2064 switch(pLight->Type) {
2065 case WINED3DLIGHT_POINT:
2066 case WINED3DLIGHT_SPOT:
2067 case WINED3DLIGHT_PARALLELPOINT:
2068 case WINED3DLIGHT_GLSPOT:
2069 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2072 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2074 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2075 return WINED3DERR_INVALIDCALL;
2079 case WINED3DLIGHT_DIRECTIONAL:
2080 /* Ignores attenuation */
2084 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2085 return WINED3DERR_INVALIDCALL;
2088 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2090 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2091 if(object->OriginalIndex == Index) break;
2096 TRACE("Adding new light\n");
2097 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2099 ERR("Out of memory error when allocating a light\n");
2100 return E_OUTOFMEMORY;
2102 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2103 object->glIndex = -1;
2104 object->OriginalIndex = Index;
2107 /* Initialize the object */
2108 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,
2109 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2110 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2111 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2112 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2113 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2114 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2116 /* Save away the information */
2117 object->OriginalParms = *pLight;
2119 switch (pLight->Type) {
2120 case WINED3DLIGHT_POINT:
2122 object->lightPosn[0] = pLight->Position.x;
2123 object->lightPosn[1] = pLight->Position.y;
2124 object->lightPosn[2] = pLight->Position.z;
2125 object->lightPosn[3] = 1.0f;
2126 object->cutoff = 180.0f;
2130 case WINED3DLIGHT_DIRECTIONAL:
2132 object->lightPosn[0] = -pLight->Direction.x;
2133 object->lightPosn[1] = -pLight->Direction.y;
2134 object->lightPosn[2] = -pLight->Direction.z;
2135 object->lightPosn[3] = 0.0f;
2136 object->exponent = 0.0f;
2137 object->cutoff = 180.0f;
2140 case WINED3DLIGHT_SPOT:
2142 object->lightPosn[0] = pLight->Position.x;
2143 object->lightPosn[1] = pLight->Position.y;
2144 object->lightPosn[2] = pLight->Position.z;
2145 object->lightPosn[3] = 1.0f;
2148 object->lightDirn[0] = pLight->Direction.x;
2149 object->lightDirn[1] = pLight->Direction.y;
2150 object->lightDirn[2] = pLight->Direction.z;
2151 object->lightDirn[3] = 1.0f;
2154 * opengl-ish and d3d-ish spot lights use too different models for the
2155 * light "intensity" as a function of the angle towards the main light direction,
2156 * so we only can approximate very roughly.
2157 * however spot lights are rather rarely used in games (if ever used at all).
2158 * furthermore if still used, probably nobody pays attention to such details.
2160 if (pLight->Falloff == 0) {
2161 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2162 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2163 * will always be 1.0 for both of them, and we don't have to care for the
2164 * rest of the rather complex calculation
2166 object->exponent = 0.0f;
2168 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2169 if (rho < 0.0001f) rho = 0.0001f;
2170 object->exponent = -0.3f/logf(cosf(rho/2));
2172 if (object->exponent > 128.0f)
2174 object->exponent = 128.0f;
2176 object->cutoff = pLight->Phi*90/M_PI;
2182 FIXME("Unrecognized light type %d\n", pLight->Type);
2185 /* Update the live definitions if the light is currently assigned a glIndex */
2186 if (object->glIndex != -1 && !This->isRecordingState) {
2187 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2192 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2194 struct wined3d_light_info *lightInfo = NULL;
2195 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2196 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2198 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2200 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2202 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2203 if(lightInfo->OriginalIndex == Index) break;
2207 if (lightInfo == NULL) {
2208 TRACE("Light information requested but light not defined\n");
2209 return WINED3DERR_INVALIDCALL;
2212 *pLight = lightInfo->OriginalParms;
2217 * Get / Set Light Enable
2218 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2220 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2222 struct wined3d_light_info *lightInfo = NULL;
2223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2224 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2226 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2228 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2230 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2231 if(lightInfo->OriginalIndex == Index) break;
2234 TRACE("Found light: %p\n", lightInfo);
2236 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2237 if (lightInfo == NULL) {
2239 TRACE("Light enabled requested but light not defined, so defining one!\n");
2240 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2242 /* Search for it again! Should be fairly quick as near head of list */
2243 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2245 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2246 if(lightInfo->OriginalIndex == Index) break;
2249 if (lightInfo == NULL) {
2250 FIXME("Adding default lights has failed dismally\n");
2251 return WINED3DERR_INVALIDCALL;
2256 if(lightInfo->glIndex != -1) {
2257 if(!This->isRecordingState) {
2258 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2261 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2262 lightInfo->glIndex = -1;
2264 TRACE("Light already disabled, nothing to do\n");
2266 lightInfo->enabled = FALSE;
2268 lightInfo->enabled = TRUE;
2269 if (lightInfo->glIndex != -1) {
2271 TRACE("Nothing to do as light was enabled\n");
2274 /* Find a free gl light */
2275 for(i = 0; i < This->maxConcurrentLights; i++) {
2276 if(This->updateStateBlock->activeLights[i] == NULL) {
2277 This->updateStateBlock->activeLights[i] = lightInfo;
2278 lightInfo->glIndex = i;
2282 if(lightInfo->glIndex == -1) {
2283 /* Our tests show that Windows returns D3D_OK in this situation, even with
2284 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2285 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2286 * as well for those lights.
2288 * TODO: Test how this affects rendering
2290 WARN("Too many concurrently active lights\n");
2294 /* i == lightInfo->glIndex */
2295 if(!This->isRecordingState) {
2296 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2304 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2306 struct wined3d_light_info *lightInfo = NULL;
2307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2309 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2310 TRACE("(%p) : for idx(%d)\n", This, Index);
2312 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2314 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2315 if(lightInfo->OriginalIndex == Index) break;
2319 if (lightInfo == NULL) {
2320 TRACE("Light enabled state requested but light not defined\n");
2321 return WINED3DERR_INVALIDCALL;
2323 /* true is 128 according to SetLightEnable */
2324 *pEnable = lightInfo->enabled ? 128 : 0;
2329 * Get / Set Clip Planes
2331 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2333 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2335 /* Validate Index */
2336 if (Index >= This->adapter->gl_info.limits.clipplanes)
2338 TRACE("Application has requested clipplane this device doesn't support\n");
2339 return WINED3DERR_INVALIDCALL;
2342 This->updateStateBlock->changed.clipplane |= 1 << Index;
2344 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2345 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2346 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2347 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2348 TRACE("Application is setting old values over, nothing to do\n");
2352 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2353 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2354 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2355 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2357 /* Handle recording of state blocks */
2358 if (This->isRecordingState) {
2359 TRACE("Recording... not performing anything\n");
2363 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2368 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2370 TRACE("(%p) : for idx %d\n", This, Index);
2372 /* Validate Index */
2373 if (Index >= This->adapter->gl_info.limits.clipplanes)
2375 TRACE("Application has requested clipplane this device doesn't support\n");
2376 return WINED3DERR_INVALIDCALL;
2379 pPlane[0] = This->stateBlock->clipplane[Index][0];
2380 pPlane[1] = This->stateBlock->clipplane[Index][1];
2381 pPlane[2] = This->stateBlock->clipplane[Index][2];
2382 pPlane[3] = This->stateBlock->clipplane[Index][3];
2387 * Get / Set Clip Plane Status
2388 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2390 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2392 FIXME("(%p) : stub\n", This);
2393 if (NULL == pClipStatus) {
2394 return WINED3DERR_INVALIDCALL;
2396 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2397 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2401 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2403 FIXME("(%p) : stub\n", This);
2404 if (NULL == pClipStatus) {
2405 return WINED3DERR_INVALIDCALL;
2407 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2408 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2413 * Get / Set Material
2415 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2418 This->updateStateBlock->changed.material = TRUE;
2419 This->updateStateBlock->material = *pMaterial;
2421 /* Handle recording of state blocks */
2422 if (This->isRecordingState) {
2423 TRACE("Recording... not performing anything\n");
2427 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2431 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2433 *pMaterial = This->updateStateBlock->material;
2434 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2435 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2436 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2437 pMaterial->Ambient.b, pMaterial->Ambient.a);
2438 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2439 pMaterial->Specular.b, pMaterial->Specular.a);
2440 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2441 pMaterial->Emissive.b, pMaterial->Emissive.a);
2442 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2450 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2451 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2454 IWineD3DBuffer *oldIdxs;
2456 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2457 oldIdxs = This->updateStateBlock->pIndexData;
2459 This->updateStateBlock->changed.indices = TRUE;
2460 This->updateStateBlock->pIndexData = pIndexData;
2461 This->updateStateBlock->IndexFmt = fmt;
2463 /* Handle recording of state blocks */
2464 if (This->isRecordingState) {
2465 TRACE("Recording... not performing anything\n");
2466 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2467 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2471 if(oldIdxs != pIndexData) {
2472 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2474 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2475 IWineD3DBuffer_AddRef(pIndexData);
2478 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2479 IWineD3DBuffer_Release(oldIdxs);
2486 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2490 *ppIndexData = This->stateBlock->pIndexData;
2492 /* up ref count on ppindexdata */
2494 IWineD3DBuffer_AddRef(*ppIndexData);
2495 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2497 TRACE("(%p) No index data set\n", This);
2499 TRACE("Returning %p\n", *ppIndexData);
2504 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2505 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2507 TRACE("(%p)->(%d)\n", This, BaseIndex);
2509 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2510 TRACE("Application is setting the old value over, nothing to do\n");
2514 This->updateStateBlock->baseVertexIndex = BaseIndex;
2516 if (This->isRecordingState) {
2517 TRACE("Recording... not performing anything\n");
2520 /* The base vertex index affects the stream sources */
2521 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2525 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2527 TRACE("(%p) : base_index %p\n", This, base_index);
2529 *base_index = This->stateBlock->baseVertexIndex;
2531 TRACE("Returning %u\n", *base_index);
2537 * Get / Set Viewports
2539 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2540 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2542 TRACE("(%p)\n", This);
2543 This->updateStateBlock->changed.viewport = TRUE;
2544 This->updateStateBlock->viewport = *pViewport;
2546 /* Handle recording of state blocks */
2547 if (This->isRecordingState) {
2548 TRACE("Recording... not performing anything\n");
2552 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2553 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2555 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2560 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2562 TRACE("(%p)\n", This);
2563 *pViewport = This->stateBlock->viewport;
2568 * Get / Set Render States
2569 * TODO: Verify against dx9 definitions
2571 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2574 DWORD oldValue = This->stateBlock->renderState[State];
2576 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2578 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2579 This->updateStateBlock->renderState[State] = Value;
2581 /* Handle recording of state blocks */
2582 if (This->isRecordingState) {
2583 TRACE("Recording... not performing anything\n");
2587 /* Compared here and not before the assignment to allow proper stateblock recording */
2588 if(Value == oldValue) {
2589 TRACE("Application is setting the old value over, nothing to do\n");
2591 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2597 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2599 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2600 *pValue = This->stateBlock->renderState[State];
2605 * Get / Set Sampler States
2606 * TODO: Verify against dx9 definitions
2609 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2613 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2614 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2616 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2617 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2620 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2621 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2622 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2625 * SetSampler is designed to allow for more than the standard up to 8 textures
2626 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2627 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2629 * http://developer.nvidia.com/object/General_FAQ.html#t6
2631 * There are two new settings for GForce
2633 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2634 * and the texture one:
2635 * GL_MAX_TEXTURE_COORDS_ARB.
2636 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2639 oldValue = This->stateBlock->samplerState[Sampler][Type];
2640 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2641 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2643 /* Handle recording of state blocks */
2644 if (This->isRecordingState) {
2645 TRACE("Recording... not performing anything\n");
2649 if(oldValue == Value) {
2650 TRACE("Application is setting the old value over, nothing to do\n");
2654 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2659 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2662 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2663 This, Sampler, debug_d3dsamplerstate(Type), Type);
2665 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2666 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2669 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2670 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2671 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2673 *Value = This->stateBlock->samplerState[Sampler][Type];
2674 TRACE("(%p) : Returning %#x\n", This, *Value);
2679 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2682 This->updateStateBlock->changed.scissorRect = TRUE;
2683 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2684 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2687 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2689 if(This->isRecordingState) {
2690 TRACE("Recording... not performing anything\n");
2694 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2699 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2700 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2702 *pRect = This->updateStateBlock->scissorRect;
2703 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2707 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2709 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2711 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2713 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2714 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2716 This->updateStateBlock->vertexDecl = pDecl;
2717 This->updateStateBlock->changed.vertexDecl = TRUE;
2719 if (This->isRecordingState) {
2720 TRACE("Recording... not performing anything\n");
2722 } else if(pDecl == oldDecl) {
2723 /* Checked after the assignment to allow proper stateblock recording */
2724 TRACE("Application is setting the old declaration over, nothing to do\n");
2728 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2732 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2735 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2737 *ppDecl = This->stateBlock->vertexDecl;
2738 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2742 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2744 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2746 This->updateStateBlock->vertexShader = pShader;
2747 This->updateStateBlock->changed.vertexShader = TRUE;
2749 if (This->isRecordingState) {
2750 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2751 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2752 TRACE("Recording... not performing anything\n");
2754 } else if(oldShader == pShader) {
2755 /* Checked here to allow proper stateblock recording */
2756 TRACE("App is setting the old shader over, nothing to do\n");
2760 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2761 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2762 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2764 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2769 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2772 if (NULL == ppShader) {
2773 return WINED3DERR_INVALIDCALL;
2775 *ppShader = This->stateBlock->vertexShader;
2776 if( NULL != *ppShader)
2777 IWineD3DVertexShader_AddRef(*ppShader);
2779 TRACE("(%p) : returning %p\n", This, *ppShader);
2783 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2784 IWineD3DDevice *iface,
2786 CONST BOOL *srcData,
2789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2790 unsigned int i, cnt = min(count, MAX_CONST_B - start);
2792 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2793 iface, srcData, start, count);
2795 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
2797 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2798 for (i = 0; i < cnt; i++)
2799 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2801 for (i = start; i < cnt + start; ++i) {
2802 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
2805 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2810 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2811 IWineD3DDevice *iface,
2816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2817 int cnt = min(count, MAX_CONST_B - start);
2819 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2820 iface, dstData, start, count);
2822 if (dstData == NULL || cnt < 0)
2823 return WINED3DERR_INVALIDCALL;
2825 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2829 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2830 IWineD3DDevice *iface,
2835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2836 unsigned int i, cnt = min(count, MAX_CONST_I - start);
2838 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2839 iface, srcData, start, count);
2841 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
2843 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2844 for (i = 0; i < cnt; i++)
2845 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2846 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2848 for (i = start; i < cnt + start; ++i) {
2849 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
2852 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2857 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2858 IWineD3DDevice *iface,
2863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2864 int cnt = min(count, MAX_CONST_I - start);
2866 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2867 iface, dstData, start, count);
2869 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2870 return WINED3DERR_INVALIDCALL;
2872 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
2876 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
2877 IWineD3DDevice *iface,
2879 CONST float *srcData,
2882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2885 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2886 iface, srcData, start, count);
2888 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
2889 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
2890 return WINED3DERR_INVALIDCALL;
2892 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
2894 for (i = 0; i < count; i++)
2895 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
2896 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2899 if (!This->isRecordingState)
2901 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
2902 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2905 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
2906 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
2911 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
2912 IWineD3DDevice *iface,
2917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2918 int cnt = min(count, This->d3d_vshader_constantF - start);
2920 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2921 iface, dstData, start, count);
2923 if (dstData == NULL || cnt < 0)
2924 return WINED3DERR_INVALIDCALL;
2926 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
2930 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
2932 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
2934 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
2938 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
2940 DWORD i = This->rev_tex_unit_map[unit];
2941 DWORD j = This->texUnitMap[stage];
2943 This->texUnitMap[stage] = unit;
2944 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
2946 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
2949 This->rev_tex_unit_map[unit] = stage;
2950 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
2952 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
2956 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
2959 This->fixed_function_usage_map = 0;
2960 for (i = 0; i < MAX_TEXTURES; ++i) {
2961 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
2962 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
2963 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
2964 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
2965 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
2966 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
2967 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
2968 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
2970 if (color_op == WINED3DTOP_DISABLE) {
2971 /* Not used, and disable higher stages */
2975 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
2976 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
2977 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
2978 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
2979 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
2980 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
2981 This->fixed_function_usage_map |= (1 << i);
2984 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
2985 This->fixed_function_usage_map |= (1 << (i + 1));
2990 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
2991 unsigned int i, tex;
2994 device_update_fixed_function_usage_map(This);
2995 ffu_map = This->fixed_function_usage_map;
2997 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
2998 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
2999 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3001 if (!(ffu_map & 1)) continue;
3003 if (This->texUnitMap[i] != i) {
3004 device_map_stage(This, i, i);
3005 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3006 markTextureStagesDirty(This, i);
3012 /* Now work out the mapping */
3014 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3016 if (!(ffu_map & 1)) continue;
3018 if (This->texUnitMap[i] != tex) {
3019 device_map_stage(This, i, tex);
3020 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3021 markTextureStagesDirty(This, i);
3028 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3029 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3030 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3031 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3034 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3035 if (sampler_type[i] && This->texUnitMap[i] != i)
3037 device_map_stage(This, i, i);
3038 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3039 if (i < gl_info->limits.texture_stages)
3041 markTextureStagesDirty(This, i);
3047 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3048 const DWORD *vshader_sampler_tokens, DWORD unit)
3050 DWORD current_mapping = This->rev_tex_unit_map[unit];
3052 /* Not currently used */
3053 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3055 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3056 /* Used by a fragment sampler */
3058 if (!pshader_sampler_tokens) {
3059 /* No pixel shader, check fixed function */
3060 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3063 /* Pixel shader, check the shader's sampler map */
3064 return !pshader_sampler_tokens[current_mapping];
3067 /* Used by a vertex sampler */
3068 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3071 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3072 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3073 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3074 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3075 int start = min(MAX_COMBINED_SAMPLERS, This->adapter->gl_info.limits.combined_samplers) - 1;
3079 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3081 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3082 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3083 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3086 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3087 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3088 if (vshader_sampler_type[i])
3090 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3092 /* Already mapped somewhere */
3096 while (start >= 0) {
3097 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3099 device_map_stage(This, vsampler_idx, start);
3100 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3112 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3113 BOOL vs = use_vs(This->stateBlock);
3114 BOOL ps = use_ps(This->stateBlock);
3117 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3118 * that would be really messy and require shader recompilation
3119 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3120 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3123 device_map_psamplers(This);
3125 device_map_fixed_function_samplers(This);
3129 device_map_vsamplers(This, ps);
3133 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3135 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3136 This->updateStateBlock->pixelShader = pShader;
3137 This->updateStateBlock->changed.pixelShader = TRUE;
3139 /* Handle recording of state blocks */
3140 if (This->isRecordingState) {
3141 TRACE("Recording... not performing anything\n");
3144 if (This->isRecordingState) {
3145 TRACE("Recording... not performing anything\n");
3146 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3147 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3151 if(pShader == oldShader) {
3152 TRACE("App is setting the old pixel shader over, nothing to do\n");
3156 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3157 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3159 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3160 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3165 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3168 if (NULL == ppShader) {
3169 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3170 return WINED3DERR_INVALIDCALL;
3173 *ppShader = This->stateBlock->pixelShader;
3174 if (NULL != *ppShader) {
3175 IWineD3DPixelShader_AddRef(*ppShader);
3177 TRACE("(%p) : returning %p\n", This, *ppShader);
3181 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3182 IWineD3DDevice *iface,
3184 CONST BOOL *srcData,
3187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3188 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3190 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3191 iface, srcData, start, count);
3193 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3195 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3196 for (i = 0; i < cnt; i++)
3197 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3199 for (i = start; i < cnt + start; ++i) {
3200 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3203 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3208 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3209 IWineD3DDevice *iface,
3214 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3215 int cnt = min(count, MAX_CONST_B - start);
3217 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3218 iface, dstData, start, count);
3220 if (dstData == NULL || cnt < 0)
3221 return WINED3DERR_INVALIDCALL;
3223 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3227 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3228 IWineD3DDevice *iface,
3233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3234 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3236 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3237 iface, srcData, start, count);
3239 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3241 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3242 for (i = 0; i < cnt; i++)
3243 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3244 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3246 for (i = start; i < cnt + start; ++i) {
3247 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3250 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3255 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3256 IWineD3DDevice *iface,
3261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3262 int cnt = min(count, MAX_CONST_I - start);
3264 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3265 iface, dstData, start, count);
3267 if (dstData == NULL || cnt < 0)
3268 return WINED3DERR_INVALIDCALL;
3270 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3274 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3275 IWineD3DDevice *iface,
3277 CONST float *srcData,
3280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3283 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3284 iface, srcData, start, count);
3286 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3287 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3288 return WINED3DERR_INVALIDCALL;
3290 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3292 for (i = 0; i < count; i++)
3293 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3294 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3297 if (!This->isRecordingState)
3299 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3300 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3303 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3304 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3309 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3310 IWineD3DDevice *iface,
3315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3316 int cnt = min(count, This->d3d_pshader_constantF - start);
3318 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3319 iface, dstData, start, count);
3321 if (dstData == NULL || cnt < 0)
3322 return WINED3DERR_INVALIDCALL;
3324 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3328 /* Context activation is done by the caller. */
3329 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3330 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3331 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3334 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3335 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3338 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3342 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3344 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3347 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3349 ERR("Source has no position mask\n");
3350 return WINED3DERR_INVALIDCALL;
3353 /* We might access VBOs from this code, so hold the lock */
3356 if (dest->resource.allocatedMemory == NULL) {
3357 buffer_get_sysmem(dest);
3360 /* Get a pointer into the destination vbo(create one if none exists) and
3361 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3363 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3365 dest->flags |= WINED3D_BUFFER_CREATEBO;
3366 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3369 if (dest->buffer_object)
3371 unsigned char extrabytes = 0;
3372 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3373 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3374 * this may write 4 extra bytes beyond the area that should be written
3376 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3377 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3378 if(!dest_conv_addr) {
3379 ERR("Out of memory\n");
3380 /* Continue without storing converted vertices */
3382 dest_conv = dest_conv_addr;
3386 * a) WINED3DRS_CLIPPING is enabled
3387 * b) WINED3DVOP_CLIP is passed
3389 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3390 static BOOL warned = FALSE;
3392 * The clipping code is not quite correct. Some things need
3393 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3394 * so disable clipping for now.
3395 * (The graphics in Half-Life are broken, and my processvertices
3396 * test crashes with IDirect3DDevice3)
3402 FIXME("Clipping is broken and disabled for now\n");
3404 } else doClip = FALSE;
3405 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3407 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3410 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3411 WINED3DTS_PROJECTION,
3413 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3414 WINED3DTS_WORLDMATRIX(0),
3417 TRACE("View mat:\n");
3418 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);
3419 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);
3420 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);
3421 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);
3423 TRACE("Proj mat:\n");
3424 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);
3425 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);
3426 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);
3427 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);
3429 TRACE("World mat:\n");
3430 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);
3431 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);
3432 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);
3433 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);
3435 /* Get the viewport */
3436 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3437 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3438 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3440 multiply_matrix(&mat,&view_mat,&world_mat);
3441 multiply_matrix(&mat,&proj_mat,&mat);
3443 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3445 for (i = 0; i < dwCount; i+= 1) {
3446 unsigned int tex_index;
3448 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3449 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3450 /* The position first */
3451 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3452 const float *p = (const float *)(element->data + i * element->stride);
3454 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3456 /* Multiplication with world, view and projection matrix */
3457 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);
3458 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);
3459 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);
3460 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);
3462 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3464 /* WARNING: The following things are taken from d3d7 and were not yet checked
3465 * against d3d8 or d3d9!
3468 /* Clipping conditions: From msdn
3470 * A vertex is clipped if it does not match the following requirements
3474 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3476 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3477 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3482 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3483 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3486 /* "Normal" viewport transformation (not clipped)
3487 * 1) The values are divided by rhw
3488 * 2) The y axis is negative, so multiply it with -1
3489 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3490 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3491 * 4) Multiply x with Width/2 and add Width/2
3492 * 5) The same for the height
3493 * 6) Add the viewpoint X and Y to the 2D coordinates and
3494 * The minimum Z value to z
3495 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3497 * Well, basically it's simply a linear transformation into viewport
3509 z *= vp.MaxZ - vp.MinZ;
3511 x += vp.Width / 2 + vp.X;
3512 y += vp.Height / 2 + vp.Y;
3517 /* That vertex got clipped
3518 * Contrary to OpenGL it is not dropped completely, it just
3519 * undergoes a different calculation.
3521 TRACE("Vertex got clipped\n");
3528 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3529 * outside of the main vertex buffer memory. That needs some more
3534 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3537 ( (float *) dest_ptr)[0] = x;
3538 ( (float *) dest_ptr)[1] = y;
3539 ( (float *) dest_ptr)[2] = z;
3540 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3542 dest_ptr += 3 * sizeof(float);
3544 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3545 dest_ptr += sizeof(float);
3550 ( (float *) dest_conv)[0] = x * w;
3551 ( (float *) dest_conv)[1] = y * w;
3552 ( (float *) dest_conv)[2] = z * w;
3553 ( (float *) dest_conv)[3] = w;
3555 dest_conv += 3 * sizeof(float);
3557 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3558 dest_conv += sizeof(float);
3562 if (DestFVF & WINED3DFVF_PSIZE) {
3563 dest_ptr += sizeof(DWORD);
3564 if(dest_conv) dest_conv += sizeof(DWORD);
3566 if (DestFVF & WINED3DFVF_NORMAL) {
3567 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3568 const float *normal = (const float *)(element->data + i * element->stride);
3569 /* AFAIK this should go into the lighting information */
3570 FIXME("Didn't expect the destination to have a normal\n");
3571 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3573 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3577 if (DestFVF & WINED3DFVF_DIFFUSE) {
3578 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3579 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3580 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3582 static BOOL warned = FALSE;
3585 ERR("No diffuse color in source, but destination has one\n");
3589 *( (DWORD *) dest_ptr) = 0xffffffff;
3590 dest_ptr += sizeof(DWORD);
3593 *( (DWORD *) dest_conv) = 0xffffffff;
3594 dest_conv += sizeof(DWORD);
3598 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3600 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3601 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3602 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3603 dest_conv += sizeof(DWORD);
3608 if (DestFVF & WINED3DFVF_SPECULAR)
3610 /* What's the color value in the feedback buffer? */
3611 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3612 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3613 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3615 static BOOL warned = FALSE;
3618 ERR("No specular color in source, but destination has one\n");
3622 *( (DWORD *) dest_ptr) = 0xFF000000;
3623 dest_ptr += sizeof(DWORD);
3626 *( (DWORD *) dest_conv) = 0xFF000000;
3627 dest_conv += sizeof(DWORD);
3631 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3633 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3634 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3635 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3636 dest_conv += sizeof(DWORD);
3641 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3642 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3643 const float *tex_coord = (const float *)(element->data + i * element->stride);
3644 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3646 ERR("No source texture, but destination requests one\n");
3647 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3648 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3651 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3653 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3660 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3661 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3662 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3663 dwCount * get_flexible_vertex_size(DestFVF),
3665 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3666 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3673 #undef copy_and_next
3675 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3676 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3680 struct wined3d_stream_info stream_info;
3681 struct wined3d_context *context;
3682 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3685 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3688 ERR("Output vertex declaration not implemented yet\n");
3691 /* Need any context to write to the vbo. */
3692 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
3694 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3695 * control the streamIsUP flag, thus restore it afterwards.
3697 This->stateBlock->streamIsUP = FALSE;
3698 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3699 This->stateBlock->streamIsUP = streamWasUP;
3701 if(vbo || SrcStartIndex) {
3703 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3704 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3706 * Also get the start index in, but only loop over all elements if there's something to add at all.
3708 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3710 struct wined3d_stream_info_element *e;
3712 if (!(stream_info.use_map & (1 << i))) continue;
3714 e = &stream_info.elements[i];
3715 if (e->buffer_object)
3717 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3718 e->buffer_object = 0;
3719 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3721 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3722 vb->buffer_object = 0;
3725 if (e->data) e->data += e->stride * SrcStartIndex;
3729 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3730 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3732 context_release(context);
3738 * Get / Set Texture Stage States
3739 * TODO: Verify against dx9 definitions
3741 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3743 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3744 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3746 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3748 if (Stage >= gl_info->limits.texture_stages)
3750 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3751 Stage, gl_info->limits.texture_stages - 1);
3755 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3756 This->updateStateBlock->textureState[Stage][Type] = Value;
3758 if (This->isRecordingState) {
3759 TRACE("Recording... not performing anything\n");
3763 /* Checked after the assignments to allow proper stateblock recording */
3764 if(oldValue == Value) {
3765 TRACE("App is setting the old value over, nothing to do\n");
3769 if(Stage > This->stateBlock->lowest_disabled_stage &&
3770 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3771 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3772 * Changes in other states are important on disabled stages too
3777 if(Type == WINED3DTSS_COLOROP) {
3780 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3781 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3782 * they have to be disabled
3784 * The current stage is dirtified below.
3786 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3787 TRACE("Additionally dirtifying stage %u\n", i);
3788 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3790 This->stateBlock->lowest_disabled_stage = Stage;
3791 TRACE("New lowest disabled: %u\n", Stage);
3792 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3793 /* Previously disabled stage enabled. Stages above it may need enabling
3794 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3795 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3797 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3800 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
3802 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3805 TRACE("Additionally dirtifying stage %u due to enable\n", i);
3806 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3808 This->stateBlock->lowest_disabled_stage = i;
3809 TRACE("New lowest disabled: %u\n", i);
3813 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3818 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3820 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3821 *pValue = This->updateStateBlock->textureState[Stage][Type];
3828 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
3829 DWORD stage, IWineD3DBaseTexture *texture)
3831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3832 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3833 IWineD3DBaseTexture *prev;
3835 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
3837 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
3838 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3840 /* Windows accepts overflowing this array... we do not. */
3841 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
3843 WARN("Ignoring invalid stage %u.\n", stage);
3847 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
3848 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
3850 WARN("Rejecting attempt to set scratch texture.\n");
3851 return WINED3DERR_INVALIDCALL;
3854 This->updateStateBlock->changed.textures |= 1 << stage;
3856 prev = This->updateStateBlock->textures[stage];
3857 TRACE("Previous texture %p.\n", prev);
3859 if (texture == prev)
3861 TRACE("App is setting the same texture again, nothing to do.\n");
3865 TRACE("Setting new texture to %p.\n", texture);
3866 This->updateStateBlock->textures[stage] = texture;
3868 if (This->isRecordingState)
3870 TRACE("Recording... not performing anything\n");
3872 if (texture) IWineD3DBaseTexture_AddRef(texture);
3873 if (prev) IWineD3DBaseTexture_Release(prev);
3880 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
3881 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
3882 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
3884 IWineD3DBaseTexture_AddRef(texture);
3886 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
3888 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3891 if (!prev && stage < gl_info->limits.texture_stages)
3893 /* The source arguments for color and alpha ops have different
3894 * meanings when a NULL texture is bound, so the COLOROP and
3895 * ALPHAOP have to be dirtified. */
3896 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
3897 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
3900 if (bind_count == 1) t->baseTexture.sampler = stage;
3905 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
3906 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
3908 IWineD3DBaseTexture_Release(prev);
3910 if (!texture && stage < gl_info->limits.texture_stages)
3912 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
3913 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
3916 if (bind_count && t->baseTexture.sampler == stage)
3920 /* Search for other stages the texture is bound to. Shouldn't
3921 * happen if applications bind textures to a single stage only. */
3922 TRACE("Searching for other stages the texture is bound to.\n");
3923 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
3925 if (This->updateStateBlock->textures[i] == prev)
3927 TRACE("Texture is also bound to stage %u.\n", i);
3928 t->baseTexture.sampler = i;
3935 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
3940 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
3941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3943 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
3945 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
3946 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3949 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
3950 ERR("Current stage overflows textures array (stage %d)\n", Stage);
3951 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3954 *ppTexture=This->stateBlock->textures[Stage];
3956 IWineD3DBaseTexture_AddRef(*ppTexture);
3958 TRACE("(%p) : Returning %p\n", This, *ppTexture);
3966 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
3967 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
3969 IWineD3DSwapChain *swapchain;
3972 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
3973 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
3975 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
3978 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
3982 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
3983 IWineD3DSwapChain_Release(swapchain);
3986 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
3993 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
3994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3995 WARN("(%p) : stub, calling idirect3d for now\n", This);
3996 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
3999 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4001 IWineD3DSwapChain *swapChain;
4004 if(iSwapChain > 0) {
4005 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4006 if (hr == WINED3D_OK) {
4007 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4008 IWineD3DSwapChain_Release(swapChain);
4010 FIXME("(%p) Error getting display mode\n", This);
4013 /* Don't read the real display mode,
4014 but return the stored mode instead. X11 can't change the color
4015 depth, and some apps are pretty angry if they SetDisplayMode from
4016 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4018 Also don't relay to the swapchain because with ddraw it's possible
4019 that there isn't a swapchain at all */
4020 pMode->Width = This->ddraw_width;
4021 pMode->Height = This->ddraw_height;
4022 pMode->Format = This->ddraw_format;
4023 pMode->RefreshRate = 0;
4031 * Stateblock related functions
4034 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4036 IWineD3DStateBlock *stateblock;
4039 TRACE("(%p)\n", This);
4041 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4043 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4044 if (FAILED(hr)) return hr;
4046 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4047 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4048 This->isRecordingState = TRUE;
4050 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4055 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4057 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4059 if (!This->isRecordingState) {
4060 WARN("(%p) not recording! returning error\n", This);
4061 *ppStateBlock = NULL;
4062 return WINED3DERR_INVALIDCALL;
4065 stateblock_init_contained_states(object);
4067 *ppStateBlock = (IWineD3DStateBlock*) object;
4068 This->isRecordingState = FALSE;
4069 This->updateStateBlock = This->stateBlock;
4070 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4071 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4072 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4077 * Scene related functions
4079 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4080 /* At the moment we have no need for any functionality at the beginning
4082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4083 TRACE("(%p)\n", This);
4086 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4087 return WINED3DERR_INVALIDCALL;
4089 This->inScene = TRUE;
4093 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4096 struct wined3d_context *context;
4098 TRACE("(%p)\n", This);
4100 if(!This->inScene) {
4101 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4102 return WINED3DERR_INVALIDCALL;
4105 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4106 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4108 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4110 context_release(context);
4112 This->inScene = FALSE;
4116 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4117 const RECT *pSourceRect, const RECT *pDestRect,
4118 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4120 IWineD3DSwapChain *swapChain = NULL;
4122 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4124 TRACE("iface %p.\n", iface);
4126 for(i = 0 ; i < swapchains ; i ++) {
4128 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4129 TRACE("presentinng chain %d, %p\n", i, swapChain);
4130 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4131 IWineD3DSwapChain_Release(swapChain);
4137 /* Not called from the VTable (internal subroutine) */
4138 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4139 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4140 float Z, DWORD Stencil) {
4141 GLbitfield glMask = 0;
4143 WINED3DRECT curRect;
4145 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4146 UINT drawable_width, drawable_height;
4147 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4148 struct wined3d_context *context;
4150 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4151 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4152 * for the cleared parts, and the untouched parts.
4154 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4155 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4156 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4157 * checking all this if the dest surface is in the drawable anyway.
4159 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4161 if(vp->X != 0 || vp->Y != 0 ||
4162 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4163 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4166 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4167 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4168 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4169 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4170 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4173 if(Count > 0 && pRects && (
4174 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4175 pRects[0].x2 < target->currentDesc.Width ||
4176 pRects[0].y2 < target->currentDesc.Height)) {
4177 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4184 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4186 target->get_drawable_size(context, &drawable_width, &drawable_height);
4190 /* Only set the values up once, as they are not changing */
4191 if (Flags & WINED3DCLEAR_STENCIL) {
4192 glClearStencil(Stencil);
4193 checkGLcall("glClearStencil");
4194 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4195 glStencilMask(0xFFFFFFFF);
4198 if (Flags & WINED3DCLEAR_ZBUFFER) {
4199 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4200 glDepthMask(GL_TRUE);
4202 checkGLcall("glClearDepth");
4203 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4204 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4206 if (vp->X != 0 || vp->Y != 0 ||
4207 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4208 surface_load_ds_location(This->stencilBufferTarget, context, location);
4210 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4211 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4212 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4213 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4214 surface_load_ds_location(This->stencilBufferTarget, context, location);
4216 else if (Count > 0 && pRects && (
4217 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4218 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4219 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4220 surface_load_ds_location(This->stencilBufferTarget, context, location);
4224 if (Flags & WINED3DCLEAR_TARGET) {
4225 TRACE("Clearing screen with glClear to color %x\n", Color);
4226 glClearColor(D3DCOLOR_R(Color),
4230 checkGLcall("glClearColor");
4232 /* Clear ALL colors! */
4233 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4234 glMask = glMask | GL_COLOR_BUFFER_BIT;
4237 vp_rect.left = vp->X;
4238 vp_rect.top = vp->Y;
4239 vp_rect.right = vp->X + vp->Width;
4240 vp_rect.bottom = vp->Y + vp->Height;
4241 if (!(Count > 0 && pRects)) {
4242 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4243 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4245 if (context->render_offscreen)
4247 glScissor(vp_rect.left, vp_rect.top,
4248 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4250 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4251 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4253 checkGLcall("glScissor");
4255 checkGLcall("glClear");
4257 /* Now process each rect in turn */
4258 for (i = 0; i < Count; i++) {
4259 /* Note gl uses lower left, width/height */
4260 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4261 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4262 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4264 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4265 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4266 curRect.x1, (target->currentDesc.Height - curRect.y2),
4267 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4269 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4270 * The rectangle is not cleared, no error is returned, but further rectanlges are
4271 * still cleared if they are valid
4273 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4274 TRACE("Rectangle with negative dimensions, ignoring\n");
4278 if (context->render_offscreen)
4280 glScissor(curRect.x1, curRect.y1,
4281 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4283 glScissor(curRect.x1, drawable_height - curRect.y2,
4284 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4286 checkGLcall("glScissor");
4289 checkGLcall("glClear");
4293 /* Restore the old values (why..?) */
4294 if (Flags & WINED3DCLEAR_STENCIL) {
4295 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4297 if (Flags & WINED3DCLEAR_TARGET) {
4298 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4299 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4300 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4301 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4302 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4304 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4305 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4307 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4309 if (Flags & WINED3DCLEAR_ZBUFFER) {
4310 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4311 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4312 surface_modify_ds_location(This->stencilBufferTarget, location);
4317 wglFlush(); /* Flush to ensure ordering across contexts. */
4319 context_release(context);
4324 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4325 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4327 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4329 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4330 Count, pRects, Flags, Color, Z, Stencil);
4332 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4333 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4334 /* TODO: What about depth stencil buffers without stencil bits? */
4335 return WINED3DERR_INVALIDCALL;
4338 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4345 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4346 WINED3DPRIMITIVETYPE primitive_type)
4348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4350 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4352 This->updateStateBlock->changed.primitive_type = TRUE;
4353 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4356 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4357 WINED3DPRIMITIVETYPE *primitive_type)
4359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4361 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4363 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4365 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4368 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4370 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4372 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4374 if(!This->stateBlock->vertexDecl) {
4375 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4376 return WINED3DERR_INVALIDCALL;
4379 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4380 if(This->stateBlock->streamIsUP) {
4381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4382 This->stateBlock->streamIsUP = FALSE;
4385 if(This->stateBlock->loadBaseVertexIndex != 0) {
4386 This->stateBlock->loadBaseVertexIndex = 0;
4387 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4389 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4390 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4394 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4398 IWineD3DBuffer *pIB;
4401 pIB = This->stateBlock->pIndexData;
4403 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4404 * without an index buffer set. (The first time at least...)
4405 * D3D8 simply dies, but I doubt it can do much harm to return
4406 * D3DERR_INVALIDCALL there as well. */
4407 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4408 return WINED3DERR_INVALIDCALL;
4411 if(!This->stateBlock->vertexDecl) {
4412 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4413 return WINED3DERR_INVALIDCALL;
4416 if(This->stateBlock->streamIsUP) {
4417 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4418 This->stateBlock->streamIsUP = FALSE;
4420 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4422 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4424 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4430 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4431 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4432 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4435 drawPrimitive(iface, index_count, startIndex, idxStride,
4436 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4441 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4442 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4447 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4448 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4450 if(!This->stateBlock->vertexDecl) {
4451 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4452 return WINED3DERR_INVALIDCALL;
4455 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4456 vb = This->stateBlock->streamSource[0];
4457 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4458 if (vb) IWineD3DBuffer_Release(vb);
4459 This->stateBlock->streamOffset[0] = 0;
4460 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4461 This->stateBlock->streamIsUP = TRUE;
4462 This->stateBlock->loadBaseVertexIndex = 0;
4464 /* TODO: Only mark dirty if drawing from a different UP address */
4465 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4467 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4469 /* MSDN specifies stream zero settings must be set to NULL */
4470 This->stateBlock->streamStride[0] = 0;
4471 This->stateBlock->streamSource[0] = NULL;
4473 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4474 * the new stream sources or use UP drawing again
4479 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4480 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4481 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4488 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4489 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4491 if(!This->stateBlock->vertexDecl) {
4492 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4493 return WINED3DERR_INVALIDCALL;
4496 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4502 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4503 vb = This->stateBlock->streamSource[0];
4504 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4505 if (vb) IWineD3DBuffer_Release(vb);
4506 This->stateBlock->streamIsUP = TRUE;
4507 This->stateBlock->streamOffset[0] = 0;
4508 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4510 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4511 This->stateBlock->baseVertexIndex = 0;
4512 This->stateBlock->loadBaseVertexIndex = 0;
4513 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4514 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4515 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4517 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4519 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4520 This->stateBlock->streamSource[0] = NULL;
4521 This->stateBlock->streamStride[0] = 0;
4522 ib = This->stateBlock->pIndexData;
4524 IWineD3DBuffer_Release(ib);
4525 This->stateBlock->pIndexData = NULL;
4527 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4528 * SetStreamSource to specify a vertex buffer
4534 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4535 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4539 /* Mark the state dirty until we have nicer tracking
4540 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4543 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4544 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4545 This->stateBlock->baseVertexIndex = 0;
4546 This->up_strided = DrawPrimStrideData;
4547 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4548 This->up_strided = NULL;
4552 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4553 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4554 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4557 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4559 /* Mark the state dirty until we have nicer tracking
4560 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4563 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4564 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4565 This->stateBlock->streamIsUP = TRUE;
4566 This->stateBlock->baseVertexIndex = 0;
4567 This->up_strided = DrawPrimStrideData;
4568 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4569 This->up_strided = NULL;
4573 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4574 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4575 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4577 WINED3DLOCKED_BOX src;
4578 WINED3DLOCKED_BOX dst;
4581 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4582 iface, pSourceVolume, pDestinationVolume);
4584 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4585 * dirtification to improve loading performance.
4587 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4588 if(FAILED(hr)) return hr;
4589 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4591 IWineD3DVolume_UnlockBox(pSourceVolume);
4595 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4597 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4599 IWineD3DVolume_UnlockBox(pSourceVolume);
4601 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4606 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4607 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4609 unsigned int level_count, i;
4610 WINED3DRESOURCETYPE type;
4613 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4615 /* Verify that the source and destination textures are non-NULL. */
4616 if (!src_texture || !dst_texture)
4618 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4619 return WINED3DERR_INVALIDCALL;
4622 if (src_texture == dst_texture)
4624 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4625 return WINED3DERR_INVALIDCALL;
4628 /* Verify that the source and destination textures are the same type. */
4629 type = IWineD3DBaseTexture_GetType(src_texture);
4630 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4632 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4633 return WINED3DERR_INVALIDCALL;
4636 /* Check that both textures have the identical numbers of levels. */
4637 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4638 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4640 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4641 return WINED3DERR_INVALIDCALL;
4644 /* Make sure that the destination texture is loaded. */
4645 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4647 /* Update every surface level of the texture. */
4650 case WINED3DRTYPE_TEXTURE:
4652 IWineD3DSurface *src_surface;
4653 IWineD3DSurface *dst_surface;
4655 for (i = 0; i < level_count; ++i)
4657 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4658 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4659 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4660 IWineD3DSurface_Release(dst_surface);
4661 IWineD3DSurface_Release(src_surface);
4664 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4671 case WINED3DRTYPE_CUBETEXTURE:
4673 IWineD3DSurface *src_surface;
4674 IWineD3DSurface *dst_surface;
4675 WINED3DCUBEMAP_FACES face;
4677 for (i = 0; i < level_count; ++i)
4679 /* Update each cube face. */
4680 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4682 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4683 face, i, &src_surface);
4684 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4685 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4686 face, i, &dst_surface);
4687 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4688 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4689 IWineD3DSurface_Release(dst_surface);
4690 IWineD3DSurface_Release(src_surface);
4693 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4701 case WINED3DRTYPE_VOLUMETEXTURE:
4703 IWineD3DVolume *src_volume;
4704 IWineD3DVolume *dst_volume;
4706 for (i = 0; i < level_count; ++i)
4708 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4709 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4710 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4711 IWineD3DVolume_Release(dst_volume);
4712 IWineD3DVolume_Release(src_volume);
4715 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4723 FIXME("Unsupported texture type %#x.\n", type);
4724 return WINED3DERR_INVALIDCALL;
4730 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4731 IWineD3DSwapChain *swapChain;
4733 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4734 if(hr == WINED3D_OK) {
4735 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4736 IWineD3DSwapChain_Release(swapChain);
4741 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4743 IWineD3DBaseTextureImpl *texture;
4746 TRACE("(%p) : %p\n", This, pNumPasses);
4748 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4749 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
4750 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4751 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4753 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
4754 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4755 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4758 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
4759 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
4761 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
4762 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4765 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
4766 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4769 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
4770 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
4771 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4776 /* return a sensible default */
4779 TRACE("returning D3D_OK\n");
4783 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
4787 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4789 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
4790 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
4791 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
4793 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
4798 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4802 PALETTEENTRY **palettes;
4804 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4806 if (PaletteNumber >= MAX_PALETTES) {
4807 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4808 return WINED3DERR_INVALIDCALL;
4811 if (PaletteNumber >= This->NumberOfPalettes) {
4812 NewSize = This->NumberOfPalettes;
4815 } while(PaletteNumber >= NewSize);
4816 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
4818 ERR("Out of memory!\n");
4819 return E_OUTOFMEMORY;
4821 This->palettes = palettes;
4822 This->NumberOfPalettes = NewSize;
4825 if (!This->palettes[PaletteNumber]) {
4826 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
4827 if (!This->palettes[PaletteNumber]) {
4828 ERR("Out of memory!\n");
4829 return E_OUTOFMEMORY;
4833 for (j = 0; j < 256; ++j) {
4834 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4835 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4836 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4837 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4839 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
4840 TRACE("(%p) : returning\n", This);
4844 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4847 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4848 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
4849 /* What happens in such situation isn't documented; Native seems to silently abort
4850 on such conditions. Return Invalid Call. */
4851 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
4852 return WINED3DERR_INVALIDCALL;
4854 for (j = 0; j < 256; ++j) {
4855 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4856 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4857 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4858 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4860 TRACE("(%p) : returning\n", This);
4864 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4866 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4867 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
4868 (tested with reference rasterizer). Return Invalid Call. */
4869 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
4870 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
4871 return WINED3DERR_INVALIDCALL;
4873 /*TODO: stateblocks */
4874 if (This->currentPalette != PaletteNumber) {
4875 This->currentPalette = PaletteNumber;
4876 dirtify_p8_texture_samplers(This);
4878 TRACE("(%p) : returning\n", This);
4882 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4884 if (PaletteNumber == NULL) {
4885 WARN("(%p) : returning Invalid Call\n", This);
4886 return WINED3DERR_INVALIDCALL;
4888 /*TODO: stateblocks */
4889 *PaletteNumber = This->currentPalette;
4890 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4894 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4899 FIXME("(%p) : stub\n", This);
4903 This->softwareVertexProcessing = bSoftware;
4908 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4913 FIXME("(%p) : stub\n", This);
4916 return This->softwareVertexProcessing;
4919 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
4920 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
4922 IWineD3DSwapChain *swapchain;
4925 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
4926 iface, swapchain_idx, raster_status);
4928 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4931 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4935 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
4936 IWineD3DSwapChain_Release(swapchain);
4939 WARN("Failed to get raster status, hr %#x.\n", hr);
4946 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
4949 if(nSegments != 0.0f) {
4952 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
4959 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
4964 FIXME("iface %p stub!\n", iface);
4970 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4972 /** TODO: remove casts to IWineD3DSurfaceImpl
4973 * NOTE: move code to surface to accomplish this
4974 ****************************************/
4975 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4976 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
4977 int srcWidth, srcHeight;
4978 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4979 WINED3DFORMAT destFormat, srcFormat;
4981 int srcLeft, destLeft, destTop;
4982 WINED3DPOOL srcPool, destPool;
4984 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4985 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
4989 CONVERT_TYPES convert = NO_CONVERSION;
4990 struct wined3d_context *context;
4992 WINED3DSURFACE_DESC winedesc;
4994 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4996 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4997 srcSurfaceWidth = winedesc.width;
4998 srcSurfaceHeight = winedesc.height;
4999 srcPool = winedesc.pool;
5000 srcFormat = winedesc.format;
5002 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5003 destSurfaceWidth = winedesc.width;
5004 destSurfaceHeight = winedesc.height;
5005 destPool = winedesc.pool;
5006 destFormat = winedesc.format;
5007 destSize = winedesc.size;
5009 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5010 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5011 return WINED3DERR_INVALIDCALL;
5014 /* This call loads the opengl surface directly, instead of copying the surface to the
5015 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5016 * copy in sysmem and use regular surface loading.
5018 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5019 if(convert != NO_CONVERSION) {
5020 return IWineD3DSurface_BltFast(pDestinationSurface,
5021 pDestPoint ? pDestPoint->x : 0,
5022 pDestPoint ? pDestPoint->y : 0,
5023 pSourceSurface, pSourceRect, 0);
5026 if (destFormat == WINED3DFMT_UNKNOWN) {
5027 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5028 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5030 /* Get the update surface description */
5031 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5034 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5037 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5038 checkGLcall("glActiveTextureARB");
5041 /* Make sure the surface is loaded and up to date */
5042 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5043 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5045 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5046 dst_format_desc = dst_impl->resource.format_desc;
5048 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5049 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5050 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5051 srcLeft = pSourceRect ? pSourceRect->left : 0;
5052 destLeft = pDestPoint ? pDestPoint->x : 0;
5053 destTop = pDestPoint ? pDestPoint->y : 0;
5056 /* This function doesn't support compressed textures
5057 the pitch is just bytesPerPixel * width */
5058 if(srcWidth != srcSurfaceWidth || srcLeft ){
5059 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5060 offset += srcLeft * src_format_desc->byte_count;
5061 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5063 /* TODO DXT formats */
5065 if(pSourceRect != NULL && pSourceRect->top != 0){
5066 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5068 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5069 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5070 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5073 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5075 /* need to lock the surface to get the data */
5076 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5081 /* TODO: Cube and volume support */
5083 /* not a whole row so we have to do it a line at a time */
5086 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5087 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5089 for (j = destTop; j < (srcHeight + destTop); ++j)
5091 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5092 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5096 } else { /* Full width, so just write out the whole texture */
5097 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5099 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5101 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5103 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5104 FIXME("Updating part of a compressed texture is not supported.\n");
5106 if (destFormat != srcFormat)
5108 FIXME("Updating mixed format compressed textures is not supported.\n");
5112 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5113 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5118 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5119 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5122 checkGLcall("glTexSubImage2D");
5125 context_release(context);
5127 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5128 sampler = This->rev_tex_unit_map[0];
5129 if (sampler != WINED3D_UNMAPPED_STAGE)
5131 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5137 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5139 struct WineD3DRectPatch *patch;
5140 GLenum old_primitive_type;
5144 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5146 if(!(Handle || pRectPatchInfo)) {
5147 /* TODO: Write a test for the return value, thus the FIXME */
5148 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5149 return WINED3DERR_INVALIDCALL;
5153 i = PATCHMAP_HASHFUNC(Handle);
5155 LIST_FOR_EACH(e, &This->patches[i]) {
5156 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5157 if(patch->Handle == Handle) {
5164 TRACE("Patch does not exist. Creating a new one\n");
5165 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5166 patch->Handle = Handle;
5167 list_add_head(&This->patches[i], &patch->entry);
5169 TRACE("Found existing patch %p\n", patch);
5172 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5173 * attributes we have to tesselate, read back, and draw. This needs a patch
5174 * management structure instance. Create one.
5176 * A possible improvement is to check if a vertex shader is used, and if not directly
5179 FIXME("Drawing an uncached patch. This is slow\n");
5180 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5183 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5184 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5185 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5187 TRACE("Tesselation density or patch info changed, retesselating\n");
5189 if(pRectPatchInfo) {
5190 patch->RectPatchInfo = *pRectPatchInfo;
5192 patch->numSegs[0] = pNumSegs[0];
5193 patch->numSegs[1] = pNumSegs[1];
5194 patch->numSegs[2] = pNumSegs[2];
5195 patch->numSegs[3] = pNumSegs[3];
5197 hr = tesselate_rectpatch(This, patch);
5199 WARN("Patch tesselation failed\n");
5201 /* Do not release the handle to store the params of the patch */
5203 HeapFree(GetProcessHeap(), 0, patch);
5209 This->currentPatch = patch;
5210 old_primitive_type = This->stateBlock->gl_primitive_type;
5211 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5212 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5213 This->stateBlock->gl_primitive_type = old_primitive_type;
5214 This->currentPatch = NULL;
5216 /* Destroy uncached patches */
5218 HeapFree(GetProcessHeap(), 0, patch->mem);
5219 HeapFree(GetProcessHeap(), 0, patch);
5224 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5225 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5227 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5228 iface, handle, segment_count, patch_info);
5233 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5236 struct WineD3DRectPatch *patch;
5238 TRACE("(%p) Handle(%d)\n", This, Handle);
5240 i = PATCHMAP_HASHFUNC(Handle);
5241 LIST_FOR_EACH(e, &This->patches[i]) {
5242 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5243 if(patch->Handle == Handle) {
5244 TRACE("Deleting patch %p\n", patch);
5245 list_remove(&patch->entry);
5246 HeapFree(GetProcessHeap(), 0, patch->mem);
5247 HeapFree(GetProcessHeap(), 0, patch);
5252 /* TODO: Write a test for the return value */
5253 FIXME("Attempt to destroy nonexistent patch\n");
5254 return WINED3DERR_INVALIDCALL;
5257 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5259 IWineD3DSwapChain *swapchain;
5261 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5262 if (SUCCEEDED(hr)) {
5263 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5270 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5271 const WINED3DRECT *rect, const float color[4])
5273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5274 struct wined3d_context *context;
5276 if (!surface_is_offscreen(surface))
5278 TRACE("Surface %p is onscreen\n", surface);
5280 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5282 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5283 context_set_draw_buffer(context, surface_get_gl_buffer(surface));
5287 TRACE("Surface %p is offscreen\n", surface);
5289 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5291 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5292 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5293 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5297 glEnable(GL_SCISSOR_TEST);
5298 if(surface_is_offscreen(surface)) {
5299 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5301 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5302 rect->x2 - rect->x1, rect->y2 - rect->y1);
5304 checkGLcall("glScissor");
5305 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5307 glDisable(GL_SCISSOR_TEST);
5309 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5311 glDisable(GL_BLEND);
5312 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5314 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5315 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5317 glClearColor(color[0], color[1], color[2], color[3]);
5318 glClear(GL_COLOR_BUFFER_BIT);
5319 checkGLcall("glClear");
5323 wglFlush(); /* Flush to ensure ordering across contexts. */
5325 context_release(context);
5328 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5329 unsigned int r, g, b, a;
5332 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5333 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5334 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5337 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5339 a = (color & 0xff000000) >> 24;
5340 r = (color & 0x00ff0000) >> 16;
5341 g = (color & 0x0000ff00) >> 8;
5342 b = (color & 0x000000ff) >> 0;
5346 case WINED3DFMT_B5G6R5_UNORM:
5347 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5354 TRACE("Returning %08x\n", ret);
5357 case WINED3DFMT_B5G5R5X1_UNORM:
5358 case WINED3DFMT_B5G5R5A1_UNORM:
5367 TRACE("Returning %08x\n", ret);
5370 case WINED3DFMT_A8_UNORM:
5371 TRACE("Returning %08x\n", a);
5374 case WINED3DFMT_B4G4R4X4_UNORM:
5375 case WINED3DFMT_B4G4R4A4_UNORM:
5384 TRACE("Returning %08x\n", ret);
5387 case WINED3DFMT_B2G3R3_UNORM:
5394 TRACE("Returning %08x\n", ret);
5397 case WINED3DFMT_R8G8B8X8_UNORM:
5398 case WINED3DFMT_R8G8B8A8_UNORM:
5403 TRACE("Returning %08x\n", ret);
5406 case WINED3DFMT_B10G10R10A2_UNORM:
5408 r = (r * 1024) / 256;
5409 g = (g * 1024) / 256;
5410 b = (b * 1024) / 256;
5415 TRACE("Returning %08x\n", ret);
5418 case WINED3DFMT_R10G10B10A2_UNORM:
5420 r = (r * 1024) / 256;
5421 g = (g * 1024) / 256;
5422 b = (b * 1024) / 256;
5427 TRACE("Returning %08x\n", ret);
5431 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5436 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5437 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5439 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5442 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5444 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5445 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5446 return WINED3DERR_INVALIDCALL;
5449 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5450 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5451 color_fill_fbo(iface, pSurface, pRect, c);
5454 /* Just forward this to the DirectDraw blitting engine */
5455 memset(&BltFx, 0, sizeof(BltFx));
5456 BltFx.dwSize = sizeof(BltFx);
5457 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5458 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5459 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5463 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5464 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5466 IWineD3DResource *resource;
5467 IWineD3DSurface *surface;
5470 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5473 ERR("Failed to get resource, hr %#x\n", hr);
5477 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5479 FIXME("Only supported on surface resources\n");
5480 IWineD3DResource_Release(resource);
5484 surface = (IWineD3DSurface *)resource;
5486 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5488 color_fill_fbo(iface, surface, NULL, color);
5495 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5497 c = ((DWORD)(color[2] * 255.0f));
5498 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5499 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5500 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5502 /* Just forward this to the DirectDraw blitting engine */
5503 memset(&BltFx, 0, sizeof(BltFx));
5504 BltFx.dwSize = sizeof(BltFx);
5505 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5506 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5509 ERR("Blt failed, hr %#x\n", hr);
5513 IWineD3DResource_Release(resource);
5516 /* rendertarget and depth stencil functions */
5517 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5520 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5522 ERR("(%p) : Only %d render targets are supported.\n",
5523 This, This->adapter->gl_info.limits.buffers);
5524 return WINED3DERR_INVALIDCALL;
5527 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5528 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5529 /* Note inc ref on returned surface */
5530 if(*ppRenderTarget != NULL)
5531 IWineD3DSurface_AddRef(*ppRenderTarget);
5535 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5536 IWineD3DSurface *Front, IWineD3DSurface *Back)
5538 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5539 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5540 IWineD3DSwapChainImpl *Swapchain;
5543 TRACE("iface %p, front %p, back %p.\n", iface, Front, Back);
5545 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5546 if(hr != WINED3D_OK) {
5547 ERR("Can't get the swapchain\n");
5551 /* Make sure to release the swapchain */
5552 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5554 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5555 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5556 return WINED3DERR_INVALIDCALL;
5558 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5559 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5560 return WINED3DERR_INVALIDCALL;
5563 if(Swapchain->frontBuffer != Front) {
5564 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5566 if(Swapchain->frontBuffer)
5568 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5569 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5571 Swapchain->frontBuffer = Front;
5573 if(Swapchain->frontBuffer) {
5574 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5575 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5579 if(Back && !Swapchain->backBuffer) {
5580 /* We need memory for the back buffer array - only one back buffer this way */
5581 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5582 if(!Swapchain->backBuffer) {
5583 ERR("Out of memory\n");
5584 return E_OUTOFMEMORY;
5588 if(Swapchain->backBuffer[0] != Back) {
5589 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5591 /* What to do about the context here in the case of multithreading? Not sure.
5592 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5594 WARN("No active context?\n");
5597 if(!Swapchain->backBuffer[0]) {
5598 /* GL was told to draw to the front buffer at creation,
5601 glDrawBuffer(GL_BACK);
5602 checkGLcall("glDrawBuffer(GL_BACK)");
5603 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5604 Swapchain->presentParms.BackBufferCount = 1;
5606 /* That makes problems - disable for now */
5607 /* glDrawBuffer(GL_FRONT); */
5608 checkGLcall("glDrawBuffer(GL_FRONT)");
5609 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5610 Swapchain->presentParms.BackBufferCount = 0;
5614 if(Swapchain->backBuffer[0])
5616 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5617 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5619 Swapchain->backBuffer[0] = Back;
5621 if(Swapchain->backBuffer[0]) {
5622 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5623 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
5624 Swapchain->presentParms.BackBufferWidth = BackImpl->currentDesc.Width;
5625 Swapchain->presentParms.BackBufferHeight = BackImpl->currentDesc.Height;
5626 Swapchain->presentParms.BackBufferFormat = BackImpl->resource.format_desc->format;
5628 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5629 Swapchain->backBuffer = NULL;
5637 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5639 *ppZStencilSurface = This->stencilBufferTarget;
5640 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5642 if(*ppZStencilSurface != NULL) {
5643 /* Note inc ref on returned surface */
5644 IWineD3DSurface_AddRef(*ppZStencilSurface);
5647 return WINED3DERR_NOTFOUND;
5651 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5652 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
5654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5655 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5656 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5657 const struct wined3d_gl_info *gl_info;
5658 struct wined3d_context *context;
5660 POINT offset = {0, 0};
5662 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5663 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5664 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5665 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5668 case WINED3DTEXF_LINEAR:
5669 gl_filter = GL_LINEAR;
5673 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5674 case WINED3DTEXF_NONE:
5675 case WINED3DTEXF_POINT:
5676 gl_filter = GL_NEAREST;
5680 /* Attach src surface to src fbo */
5681 src_swapchain = get_swapchain(src_surface);
5682 dst_swapchain = get_swapchain(dst_surface);
5684 if (src_swapchain) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
5685 else if (dst_swapchain) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5686 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5688 gl_info = context->gl_info;
5690 if (!surface_is_offscreen(src_surface))
5692 GLenum buffer = surface_get_gl_buffer(src_surface);
5694 TRACE("Source surface %p is onscreen\n", src_surface);
5695 /* Make sure the drawable is up to date. In the offscreen case
5696 * attach_surface_fbo() implicitly takes care of this. */
5697 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
5699 if(buffer == GL_FRONT) {
5702 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
5703 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
5704 h = windowsize.bottom - windowsize.top;
5705 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
5706 src_rect->y1 = offset.y + h - src_rect->y1;
5707 src_rect->y2 = offset.y + h - src_rect->y2;
5709 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5710 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5714 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5715 glReadBuffer(buffer);
5716 checkGLcall("glReadBuffer()");
5718 TRACE("Source surface %p is offscreen\n", src_surface);
5720 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5721 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
5722 glReadBuffer(GL_COLOR_ATTACHMENT0);
5723 checkGLcall("glReadBuffer()");
5724 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5728 /* Attach dst surface to dst fbo */
5729 if (!surface_is_offscreen(dst_surface))
5731 GLenum buffer = surface_get_gl_buffer(dst_surface);
5733 TRACE("Destination surface %p is onscreen\n", dst_surface);
5734 /* Make sure the drawable is up to date. In the offscreen case
5735 * attach_surface_fbo() implicitly takes care of this. */
5736 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
5738 if(buffer == GL_FRONT) {
5741 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
5742 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
5743 h = windowsize.bottom - windowsize.top;
5744 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
5745 dst_rect->y1 = offset.y + h - dst_rect->y1;
5746 dst_rect->y2 = offset.y + h - dst_rect->y2;
5748 /* Screen coords = window coords, surface height = window height */
5749 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5750 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5754 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5755 context_set_draw_buffer(context, buffer);
5759 TRACE("Destination surface %p is offscreen\n", dst_surface);
5762 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5763 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
5764 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5765 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5767 glDisable(GL_SCISSOR_TEST);
5768 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5771 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5772 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
5773 checkGLcall("glBlitFramebuffer()");
5775 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5776 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
5777 checkGLcall("glBlitFramebuffer()");
5782 wglFlush(); /* Flush to ensure ordering across contexts. */
5784 context_release(context);
5786 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
5789 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5790 BOOL set_viewport) {
5791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5793 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5795 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5797 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5798 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5799 return WINED3DERR_INVALIDCALL;
5802 /* MSDN says that null disables the render target
5803 but a device must always be associated with a render target
5804 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5806 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5807 FIXME("Trying to set render target 0 to NULL\n");
5808 return WINED3DERR_INVALIDCALL;
5810 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5811 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);
5812 return WINED3DERR_INVALIDCALL;
5815 /* If we are trying to set what we already have, don't bother */
5816 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5817 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5820 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5821 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5822 This->render_targets[RenderTargetIndex] = pRenderTarget;
5824 /* Render target 0 is special */
5825 if(RenderTargetIndex == 0 && set_viewport) {
5826 /* Finally, reset the viewport and scissor rect as the MSDN states.
5827 * Tests show that stateblock recording is ignored, the change goes
5828 * directly into the primary stateblock.
5830 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5831 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5832 This->stateBlock->viewport.X = 0;
5833 This->stateBlock->viewport.Y = 0;
5834 This->stateBlock->viewport.MaxZ = 1.0f;
5835 This->stateBlock->viewport.MinZ = 0.0f;
5836 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5838 This->stateBlock->scissorRect.top = 0;
5839 This->stateBlock->scissorRect.left = 0;
5840 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5841 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5842 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5847 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5849 HRESULT hr = WINED3D_OK;
5850 IWineD3DSurface *tmp;
5852 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
5854 if (pNewZStencil == This->stencilBufferTarget) {
5855 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5857 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
5858 * depending on the renter target implementation being used.
5859 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5860 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5861 * stencil buffer and incur an extra memory overhead
5862 ******************************************************/
5864 if (This->stencilBufferTarget) {
5865 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5866 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
5867 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
5869 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5870 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
5871 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
5872 context_release(context);
5876 tmp = This->stencilBufferTarget;
5877 This->stencilBufferTarget = pNewZStencil;
5878 /* should we be calling the parent or the wined3d surface? */
5879 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5880 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5883 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5884 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5885 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5886 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5887 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5894 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5895 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5897 /* TODO: the use of Impl is deprecated. */
5898 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5899 WINED3DLOCKED_RECT lockedRect;
5901 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5903 /* some basic validation checks */
5904 if(This->cursorTexture) {
5905 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5907 glDeleteTextures(1, &This->cursorTexture);
5909 context_release(context);
5910 This->cursorTexture = 0;
5913 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5914 This->haveHardwareCursor = TRUE;
5916 This->haveHardwareCursor = FALSE;
5919 WINED3DLOCKED_RECT rect;
5921 /* MSDN: Cursor must be A8R8G8B8 */
5922 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
5924 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5925 return WINED3DERR_INVALIDCALL;
5928 /* MSDN: Cursor must be smaller than the display mode */
5929 if(pSur->currentDesc.Width > This->ddraw_width ||
5930 pSur->currentDesc.Height > This->ddraw_height) {
5931 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);
5932 return WINED3DERR_INVALIDCALL;
5935 if (!This->haveHardwareCursor) {
5936 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5938 /* Do not store the surface's pointer because the application may
5939 * release it after setting the cursor image. Windows doesn't
5940 * addref the set surface, so we can't do this either without
5941 * creating circular refcount dependencies. Copy out the gl texture
5944 This->cursorWidth = pSur->currentDesc.Width;
5945 This->cursorHeight = pSur->currentDesc.Height;
5946 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5948 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5949 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
5950 struct wined3d_context *context;
5951 char *mem, *bits = rect.pBits;
5952 GLint intfmt = glDesc->glInternal;
5953 GLint format = glDesc->glFormat;
5954 GLint type = glDesc->glType;
5955 INT height = This->cursorHeight;
5956 INT width = This->cursorWidth;
5957 INT bpp = glDesc->byte_count;
5961 /* Reformat the texture memory (pitch and width can be
5963 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5964 for(i = 0; i < height; i++)
5965 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5966 IWineD3DSurface_UnlockRect(pCursorBitmap);
5968 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5972 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5974 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5975 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5978 /* Make sure that a proper texture unit is selected */
5979 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5980 checkGLcall("glActiveTextureARB");
5981 sampler = This->rev_tex_unit_map[0];
5982 if (sampler != WINED3D_UNMAPPED_STAGE)
5984 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5986 /* Create a new cursor texture */
5987 glGenTextures(1, &This->cursorTexture);
5988 checkGLcall("glGenTextures");
5989 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5990 checkGLcall("glBindTexture");
5991 /* Copy the bitmap memory into the cursor texture */
5992 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5993 HeapFree(GetProcessHeap(), 0, mem);
5994 checkGLcall("glTexImage2D");
5996 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5998 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5999 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6004 context_release(context);
6008 FIXME("A cursor texture was not returned.\n");
6009 This->cursorTexture = 0;
6014 /* Draw a hardware cursor */
6015 ICONINFO cursorInfo;
6017 /* Create and clear maskBits because it is not needed for
6018 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6020 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6021 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6022 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6023 WINED3DLOCK_NO_DIRTY_UPDATE |
6024 WINED3DLOCK_READONLY
6026 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6027 pSur->currentDesc.Height);
6029 cursorInfo.fIcon = FALSE;
6030 cursorInfo.xHotspot = XHotSpot;
6031 cursorInfo.yHotspot = YHotSpot;
6032 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6034 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6035 1, 32, lockedRect.pBits);
6036 IWineD3DSurface_UnlockRect(pCursorBitmap);
6037 /* Create our cursor and clean up. */
6038 cursor = CreateIconIndirect(&cursorInfo);
6040 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6041 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6042 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6043 This->hardwareCursor = cursor;
6044 HeapFree(GetProcessHeap(), 0, maskBits);
6048 This->xHotSpot = XHotSpot;
6049 This->yHotSpot = YHotSpot;
6053 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6055 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6057 This->xScreenSpace = XScreenSpace;
6058 This->yScreenSpace = YScreenSpace;
6064 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6066 BOOL oldVisible = This->bCursorVisible;
6069 TRACE("(%p) : visible(%d)\n", This, bShow);
6072 * When ShowCursor is first called it should make the cursor appear at the OS's last
6073 * known cursor position. Because of this, some applications just repetitively call
6074 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6077 This->xScreenSpace = pt.x;
6078 This->yScreenSpace = pt.y;
6080 if (This->haveHardwareCursor) {
6081 This->bCursorVisible = bShow;
6083 SetCursor(This->hardwareCursor);
6089 if (This->cursorTexture)
6090 This->bCursorVisible = bShow;
6096 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6097 TRACE("checking resource %p for eviction\n", resource);
6098 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6099 TRACE("Evicting %p\n", resource);
6100 IWineD3DResource_UnLoad(resource);
6102 IWineD3DResource_Release(resource);
6106 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6108 TRACE("iface %p.\n", iface);
6110 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6114 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6116 IWineD3DDeviceImpl *device = surface->resource.device;
6117 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6119 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6120 if(surface->Flags & SFLAG_DIBSECTION) {
6121 /* Release the DC */
6122 SelectObject(surface->hDC, surface->dib.holdbitmap);
6123 DeleteDC(surface->hDC);
6124 /* Release the DIB section */
6125 DeleteObject(surface->dib.DIBsection);
6126 surface->dib.bitmap_data = NULL;
6127 surface->resource.allocatedMemory = NULL;
6128 surface->Flags &= ~SFLAG_DIBSECTION;
6130 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6131 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6132 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6133 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6135 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6136 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6138 surface->pow2Width = surface->pow2Height = 1;
6139 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6140 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6142 surface->glRect.left = 0;
6143 surface->glRect.top = 0;
6144 surface->glRect.right = surface->pow2Width;
6145 surface->glRect.bottom = surface->pow2Height;
6147 if (surface->texture_name)
6149 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6151 glDeleteTextures(1, &surface->texture_name);
6153 context_release(context);
6154 surface->texture_name = 0;
6155 surface->Flags &= ~SFLAG_CLIENT;
6157 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6158 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6159 surface->Flags |= SFLAG_NONPOW2;
6161 surface->Flags &= ~SFLAG_NONPOW2;
6163 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6164 surface->resource.allocatedMemory = NULL;
6165 surface->resource.heapMemory = NULL;
6166 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6168 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6170 if(!surface_init_sysmem((IWineD3DSurface *) surface))
6172 return E_OUTOFMEMORY;
6177 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6178 TRACE("Unloading resource %p\n", resource);
6179 IWineD3DResource_UnLoad(resource);
6180 IWineD3DResource_Release(resource);
6184 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6187 WINED3DDISPLAYMODE m;
6190 /* All Windowed modes are supported, as is leaving the current mode */
6191 if(pp->Windowed) return TRUE;
6192 if(!pp->BackBufferWidth) return TRUE;
6193 if(!pp->BackBufferHeight) return TRUE;
6195 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6196 for(i = 0; i < count; i++) {
6197 memset(&m, 0, sizeof(m));
6198 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6200 ERR("EnumAdapterModes failed\n");
6202 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6203 /* Mode found, it is supported */
6207 /* Mode not found -> not supported */
6211 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6212 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6213 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6214 const struct wined3d_gl_info *gl_info;
6215 struct wined3d_context *context;
6216 IWineD3DBaseShaderImpl *shader;
6218 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6219 gl_info = context->gl_info;
6221 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6222 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6223 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6227 if(This->depth_blt_texture) {
6228 glDeleteTextures(1, &This->depth_blt_texture);
6229 This->depth_blt_texture = 0;
6231 if (This->depth_blt_rb) {
6232 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6233 This->depth_blt_rb = 0;
6234 This->depth_blt_rb_w = 0;
6235 This->depth_blt_rb_h = 0;
6239 This->blitter->free_private(iface);
6240 This->frag_pipe->free_private(iface);
6241 This->shader_backend->shader_free_private(iface);
6242 destroy_dummy_textures(This, gl_info);
6244 context_release(context);
6246 while (This->numContexts)
6248 context_destroy(This, This->contexts[0]);
6250 HeapFree(GetProcessHeap(), 0, swapchain->context);
6251 swapchain->context = NULL;
6252 swapchain->num_contexts = 0;
6255 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6257 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6258 struct wined3d_context *context;
6260 IWineD3DSurfaceImpl *target;
6262 /* Recreate the primary swapchain's context */
6263 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6264 if (!swapchain->context)
6266 ERR("Failed to allocate memory for swapchain context array.\n");
6267 return E_OUTOFMEMORY;
6270 target = (IWineD3DSurfaceImpl *)(swapchain->backBuffer ? swapchain->backBuffer[0] : swapchain->frontBuffer);
6271 context = context_create(This, target, swapchain->win_handle, FALSE, &swapchain->presentParms);
6274 WARN("Failed to create context.\n");
6275 HeapFree(GetProcessHeap(), 0, swapchain->context);
6279 swapchain->context[0] = context;
6280 swapchain->num_contexts = 1;
6281 create_dummy_textures(This);
6282 context_release(context);
6284 hr = This->shader_backend->shader_alloc_private(iface);
6287 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6291 hr = This->frag_pipe->alloc_private(iface);
6294 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6295 This->shader_backend->shader_free_private(iface);
6299 hr = This->blitter->alloc_private(iface);
6302 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6303 This->frag_pipe->free_private(iface);
6304 This->shader_backend->shader_free_private(iface);
6311 context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6312 destroy_dummy_textures(This, context->gl_info);
6313 context_release(context);
6314 context_destroy(This, context);
6315 HeapFree(GetProcessHeap(), 0, swapchain->context);
6316 swapchain->num_contexts = 0;
6320 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6322 IWineD3DSwapChainImpl *swapchain;
6324 BOOL DisplayModeChanged = FALSE;
6325 WINED3DDISPLAYMODE mode;
6326 TRACE("(%p)\n", This);
6328 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6330 ERR("Failed to get the first implicit swapchain\n");
6334 if(!is_display_mode_supported(This, pPresentationParameters)) {
6335 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6336 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6337 pPresentationParameters->BackBufferHeight);
6338 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6339 return WINED3DERR_INVALIDCALL;
6342 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6343 * on an existing gl context, so there's no real need for recreation.
6345 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6347 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6349 TRACE("New params:\n");
6350 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6351 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6352 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6353 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6354 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6355 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6356 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6357 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6358 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6359 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6360 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6361 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6362 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6364 /* No special treatment of these parameters. Just store them */
6365 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6366 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6367 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6368 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6370 /* What to do about these? */
6371 if(pPresentationParameters->BackBufferCount != 0 &&
6372 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6373 ERR("Cannot change the back buffer count yet\n");
6375 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6376 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6377 ERR("Cannot change the back buffer format yet\n");
6379 if(pPresentationParameters->hDeviceWindow != NULL &&
6380 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6381 ERR("Cannot change the device window yet\n");
6383 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6386 TRACE("Creating the depth stencil buffer\n");
6388 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6390 pPresentationParameters->BackBufferWidth,
6391 pPresentationParameters->BackBufferHeight,
6392 pPresentationParameters->AutoDepthStencilFormat,
6393 pPresentationParameters->MultiSampleType,
6394 pPresentationParameters->MultiSampleQuality,
6396 &This->auto_depth_stencil_buffer);
6399 ERR("Failed to create the depth stencil buffer\n");
6400 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6401 return WINED3DERR_INVALIDCALL;
6405 /* Reset the depth stencil */
6406 if (pPresentationParameters->EnableAutoDepthStencil)
6407 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6409 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6411 TRACE("Resetting stateblock\n");
6412 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6413 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6415 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6417 if(pPresentationParameters->Windowed) {
6418 mode.Width = swapchain->orig_width;
6419 mode.Height = swapchain->orig_height;
6420 mode.RefreshRate = 0;
6421 mode.Format = swapchain->presentParms.BackBufferFormat;
6423 mode.Width = pPresentationParameters->BackBufferWidth;
6424 mode.Height = pPresentationParameters->BackBufferHeight;
6425 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6426 mode.Format = swapchain->presentParms.BackBufferFormat;
6429 /* Should Width == 800 && Height == 0 set 800x600? */
6430 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6431 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6432 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6436 if(!pPresentationParameters->Windowed) {
6437 DisplayModeChanged = TRUE;
6439 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6440 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6442 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6445 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6449 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6450 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6453 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6457 if(This->auto_depth_stencil_buffer) {
6458 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6461 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6467 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6468 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6469 DisplayModeChanged) {
6471 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6473 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
6474 if(swapchain->presentParms.Windowed) {
6475 /* switch from windowed to fs */
6476 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6477 pPresentationParameters->BackBufferHeight);
6479 /* Fullscreen -> fullscreen mode change */
6480 MoveWindow(swapchain->win_handle, 0, 0,
6481 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6484 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
6485 /* Fullscreen -> windowed switch */
6486 swapchain_restore_fullscreen_window(swapchain);
6488 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6489 } else if(!pPresentationParameters->Windowed) {
6490 DWORD style = This->style, exStyle = This->exStyle;
6491 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6492 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6493 * Reset to clear up their mess. Guild Wars also loses the device during that.
6497 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6498 pPresentationParameters->BackBufferHeight);
6499 This->style = style;
6500 This->exStyle = exStyle;
6503 /* Note: No parent needed for initial internal stateblock */
6504 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6505 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6506 else TRACE("Created stateblock %p\n", This->stateBlock);
6507 This->updateStateBlock = This->stateBlock;
6508 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6510 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6512 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6515 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6518 GetClientRect(swapchain->win_handle, &client_rect);
6520 if(!swapchain->presentParms.BackBufferCount)
6522 TRACE("Single buffered rendering\n");
6523 swapchain->render_to_fbo = FALSE;
6525 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6526 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6528 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6529 swapchain->presentParms.BackBufferWidth,
6530 swapchain->presentParms.BackBufferHeight,
6531 client_rect.right, client_rect.bottom);
6532 swapchain->render_to_fbo = TRUE;
6536 TRACE("Rendering directly to GL_BACK\n");
6537 swapchain->render_to_fbo = FALSE;
6541 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6542 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6544 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6550 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6552 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6554 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6560 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6562 TRACE("(%p) : pParameters %p\n", This, pParameters);
6564 *pParameters = This->createParms;
6568 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6569 IWineD3DSwapChain *swapchain;
6571 TRACE("Relaying to swapchain\n");
6573 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6574 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6575 IWineD3DSwapChain_Release(swapchain);
6579 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6580 IWineD3DSwapChain *swapchain;
6582 TRACE("Relaying to swapchain\n");
6584 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6585 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6586 IWineD3DSwapChain_Release(swapchain);
6591 /** ********************************************************
6592 * Notification functions
6593 ** ********************************************************/
6594 /** This function must be called in the release of a resource when ref == 0,
6595 * the contents of resource must still be correct,
6596 * any handles to other resource held by the caller must be closed
6597 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6598 *****************************************************/
6599 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6601 TRACE("(%p) : Adding resource %p\n", This, resource);
6603 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6606 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6608 TRACE("(%p) : Removing resource %p\n", This, resource);
6610 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6613 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6615 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6618 TRACE("(%p) : resource %p\n", This, resource);
6620 context_resource_released((IWineD3DDevice *)This, resource, type);
6623 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6624 case WINED3DRTYPE_SURFACE: {
6627 if (This->d3d_initialized)
6629 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6631 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6632 This->render_targets[i] = NULL;
6635 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6636 This->stencilBufferTarget = NULL;
6642 case WINED3DRTYPE_TEXTURE:
6643 case WINED3DRTYPE_CUBETEXTURE:
6644 case WINED3DRTYPE_VOLUMETEXTURE:
6645 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6646 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6647 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6648 This->stateBlock->textures[counter] = NULL;
6650 if (This->updateStateBlock != This->stateBlock ){
6651 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6652 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6653 This->updateStateBlock->textures[counter] = NULL;
6658 case WINED3DRTYPE_VOLUME:
6659 /* TODO: nothing really? */
6661 case WINED3DRTYPE_BUFFER:
6664 TRACE("Cleaning up stream pointers\n");
6666 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6667 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6668 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6670 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6671 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6672 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6673 This->updateStateBlock->streamSource[streamNumber] = 0;
6674 /* Set changed flag? */
6677 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) */
6678 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6679 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6680 This->stateBlock->streamSource[streamNumber] = 0;
6685 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6686 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6687 This->updateStateBlock->pIndexData = NULL;
6690 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6691 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6692 This->stateBlock->pIndexData = NULL;
6699 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6704 /* Remove the resource from the resourceStore */
6705 device_resource_remove(This, resource);
6707 TRACE("Resource released\n");
6711 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6713 IWineD3DResourceImpl *resource, *cursor;
6715 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6717 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6718 TRACE("enumerating resource %p\n", resource);
6719 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6720 ret = pCallback((IWineD3DResource *) resource, pData);
6721 if(ret == S_FALSE) {
6722 TRACE("Canceling enumeration\n");
6729 /**********************************************************
6730 * IWineD3DDevice VTbl follows
6731 **********************************************************/
6733 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6735 /*** IUnknown methods ***/
6736 IWineD3DDeviceImpl_QueryInterface,
6737 IWineD3DDeviceImpl_AddRef,
6738 IWineD3DDeviceImpl_Release,
6739 /*** IWineD3DDevice methods ***/
6740 IWineD3DDeviceImpl_GetParent,
6741 /*** Creation methods**/
6742 IWineD3DDeviceImpl_CreateBuffer,
6743 IWineD3DDeviceImpl_CreateVertexBuffer,
6744 IWineD3DDeviceImpl_CreateIndexBuffer,
6745 IWineD3DDeviceImpl_CreateStateBlock,
6746 IWineD3DDeviceImpl_CreateSurface,
6747 IWineD3DDeviceImpl_CreateRendertargetView,
6748 IWineD3DDeviceImpl_CreateTexture,
6749 IWineD3DDeviceImpl_CreateVolumeTexture,
6750 IWineD3DDeviceImpl_CreateVolume,
6751 IWineD3DDeviceImpl_CreateCubeTexture,
6752 IWineD3DDeviceImpl_CreateQuery,
6753 IWineD3DDeviceImpl_CreateSwapChain,
6754 IWineD3DDeviceImpl_CreateVertexDeclaration,
6755 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6756 IWineD3DDeviceImpl_CreateVertexShader,
6757 IWineD3DDeviceImpl_CreateGeometryShader,
6758 IWineD3DDeviceImpl_CreatePixelShader,
6759 IWineD3DDeviceImpl_CreatePalette,
6760 /*** Odd functions **/
6761 IWineD3DDeviceImpl_Init3D,
6762 IWineD3DDeviceImpl_InitGDI,
6763 IWineD3DDeviceImpl_Uninit3D,
6764 IWineD3DDeviceImpl_UninitGDI,
6765 IWineD3DDeviceImpl_SetMultithreaded,
6766 IWineD3DDeviceImpl_EvictManagedResources,
6767 IWineD3DDeviceImpl_GetAvailableTextureMem,
6768 IWineD3DDeviceImpl_GetBackBuffer,
6769 IWineD3DDeviceImpl_GetCreationParameters,
6770 IWineD3DDeviceImpl_GetDeviceCaps,
6771 IWineD3DDeviceImpl_GetDirect3D,
6772 IWineD3DDeviceImpl_GetDisplayMode,
6773 IWineD3DDeviceImpl_SetDisplayMode,
6774 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6775 IWineD3DDeviceImpl_GetRasterStatus,
6776 IWineD3DDeviceImpl_GetSwapChain,
6777 IWineD3DDeviceImpl_Reset,
6778 IWineD3DDeviceImpl_SetDialogBoxMode,
6779 IWineD3DDeviceImpl_SetCursorProperties,
6780 IWineD3DDeviceImpl_SetCursorPosition,
6781 IWineD3DDeviceImpl_ShowCursor,
6782 /*** Getters and setters **/
6783 IWineD3DDeviceImpl_SetClipPlane,
6784 IWineD3DDeviceImpl_GetClipPlane,
6785 IWineD3DDeviceImpl_SetClipStatus,
6786 IWineD3DDeviceImpl_GetClipStatus,
6787 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6788 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6789 IWineD3DDeviceImpl_SetDepthStencilSurface,
6790 IWineD3DDeviceImpl_GetDepthStencilSurface,
6791 IWineD3DDeviceImpl_SetGammaRamp,
6792 IWineD3DDeviceImpl_GetGammaRamp,
6793 IWineD3DDeviceImpl_SetIndexBuffer,
6794 IWineD3DDeviceImpl_GetIndexBuffer,
6795 IWineD3DDeviceImpl_SetBaseVertexIndex,
6796 IWineD3DDeviceImpl_GetBaseVertexIndex,
6797 IWineD3DDeviceImpl_SetLight,
6798 IWineD3DDeviceImpl_GetLight,
6799 IWineD3DDeviceImpl_SetLightEnable,
6800 IWineD3DDeviceImpl_GetLightEnable,
6801 IWineD3DDeviceImpl_SetMaterial,
6802 IWineD3DDeviceImpl_GetMaterial,
6803 IWineD3DDeviceImpl_SetNPatchMode,
6804 IWineD3DDeviceImpl_GetNPatchMode,
6805 IWineD3DDeviceImpl_SetPaletteEntries,
6806 IWineD3DDeviceImpl_GetPaletteEntries,
6807 IWineD3DDeviceImpl_SetPixelShader,
6808 IWineD3DDeviceImpl_GetPixelShader,
6809 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6810 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6811 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6812 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6813 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6814 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6815 IWineD3DDeviceImpl_SetRenderState,
6816 IWineD3DDeviceImpl_GetRenderState,
6817 IWineD3DDeviceImpl_SetRenderTarget,
6818 IWineD3DDeviceImpl_GetRenderTarget,
6819 IWineD3DDeviceImpl_SetFrontBackBuffers,
6820 IWineD3DDeviceImpl_SetSamplerState,
6821 IWineD3DDeviceImpl_GetSamplerState,
6822 IWineD3DDeviceImpl_SetScissorRect,
6823 IWineD3DDeviceImpl_GetScissorRect,
6824 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6825 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6826 IWineD3DDeviceImpl_SetStreamSource,
6827 IWineD3DDeviceImpl_GetStreamSource,
6828 IWineD3DDeviceImpl_SetStreamSourceFreq,
6829 IWineD3DDeviceImpl_GetStreamSourceFreq,
6830 IWineD3DDeviceImpl_SetTexture,
6831 IWineD3DDeviceImpl_GetTexture,
6832 IWineD3DDeviceImpl_SetTextureStageState,
6833 IWineD3DDeviceImpl_GetTextureStageState,
6834 IWineD3DDeviceImpl_SetTransform,
6835 IWineD3DDeviceImpl_GetTransform,
6836 IWineD3DDeviceImpl_SetVertexDeclaration,
6837 IWineD3DDeviceImpl_GetVertexDeclaration,
6838 IWineD3DDeviceImpl_SetVertexShader,
6839 IWineD3DDeviceImpl_GetVertexShader,
6840 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6841 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6842 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6843 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6844 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6845 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6846 IWineD3DDeviceImpl_SetViewport,
6847 IWineD3DDeviceImpl_GetViewport,
6848 IWineD3DDeviceImpl_MultiplyTransform,
6849 IWineD3DDeviceImpl_ValidateDevice,
6850 IWineD3DDeviceImpl_ProcessVertices,
6851 /*** State block ***/
6852 IWineD3DDeviceImpl_BeginStateBlock,
6853 IWineD3DDeviceImpl_EndStateBlock,
6854 /*** Scene management ***/
6855 IWineD3DDeviceImpl_BeginScene,
6856 IWineD3DDeviceImpl_EndScene,
6857 IWineD3DDeviceImpl_Present,
6858 IWineD3DDeviceImpl_Clear,
6859 IWineD3DDeviceImpl_ClearRendertargetView,
6861 IWineD3DDeviceImpl_SetPrimitiveType,
6862 IWineD3DDeviceImpl_GetPrimitiveType,
6863 IWineD3DDeviceImpl_DrawPrimitive,
6864 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6865 IWineD3DDeviceImpl_DrawPrimitiveUP,
6866 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6867 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6868 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6869 IWineD3DDeviceImpl_DrawRectPatch,
6870 IWineD3DDeviceImpl_DrawTriPatch,
6871 IWineD3DDeviceImpl_DeletePatch,
6872 IWineD3DDeviceImpl_ColorFill,
6873 IWineD3DDeviceImpl_UpdateTexture,
6874 IWineD3DDeviceImpl_UpdateSurface,
6875 IWineD3DDeviceImpl_GetFrontBufferData,
6876 /*** object tracking ***/
6877 IWineD3DDeviceImpl_EnumResources
6880 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6881 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6882 IUnknown *parent, IWineD3DDeviceParent *device_parent)
6884 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6885 const struct fragment_pipeline *fragment_pipeline;
6886 struct shader_caps shader_caps;
6887 struct fragment_caps ffp_caps;
6888 WINED3DDISPLAYMODE mode;
6892 device->lpVtbl = &IWineD3DDevice_Vtbl;
6894 device->wined3d = (IWineD3D *)wined3d;
6895 IWineD3D_AddRef(device->wined3d);
6896 device->adapter = wined3d->adapter_count ? adapter : NULL;
6897 device->parent = parent;
6898 device->device_parent = device_parent;
6899 list_init(&device->resources);
6900 list_init(&device->shaders);
6902 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6903 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6905 /* Get the initial screen setup for ddraw. */
6906 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6909 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6910 IWineD3D_Release(device->wined3d);
6913 device->ddraw_width = mode.Width;
6914 device->ddraw_height = mode.Height;
6915 device->ddraw_format = mode.Format;
6917 /* Save the creation parameters. */
6918 device->createParms.AdapterOrdinal = adapter_idx;
6919 device->createParms.DeviceType = device_type;
6920 device->createParms.hFocusWindow = focus_window;
6921 device->createParms.BehaviorFlags = flags;
6923 device->devType = device_type;
6924 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6926 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6927 device->shader_backend = adapter->shader_backend;
6929 memset(&shader_caps, 0, sizeof(shader_caps));
6930 device->shader_backend->shader_get_caps(device_type, &adapter->gl_info, &shader_caps);
6931 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6932 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6933 device->vs_clipping = shader_caps.VSClipping;
6935 memset(&ffp_caps, 0, sizeof(ffp_caps));
6936 fragment_pipeline = adapter->fragment_pipe;
6937 device->frag_pipe = fragment_pipeline;
6938 fragment_pipeline->get_caps(device_type, &adapter->gl_info, &ffp_caps);
6939 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6940 device->max_ffp_texture_stages = ffp_caps.MaxTextureBlendStages;
6942 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6943 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6946 ERR("Failed to compile state table, hr %#x.\n", hr);
6947 IWineD3D_Release(device->wined3d);
6951 device->blitter = adapter->blitter;
6957 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6958 DWORD rep = This->StateTable[state].representative;
6959 struct wined3d_context *context;
6964 for(i = 0; i < This->numContexts; i++) {
6965 context = This->contexts[i];
6966 if(isStateDirty(context, rep)) continue;
6968 context->dirtyArray[context->numDirtyEntries++] = rep;
6969 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6970 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6971 context->isStateDirty[idx] |= (1 << shift);
6975 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6977 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.device;
6978 /* The drawable size of a pbuffer render target is the current pbuffer size. */
6979 *width = device->pbufferWidth;
6980 *height = device->pbufferHeight;
6983 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6985 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
6986 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6987 *width = surface->pow2Width;
6988 *height = surface->pow2Height;
6991 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6993 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
6994 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6995 * current context's drawable, which is the size of the back buffer of the swapchain
6996 * the active context belongs to. The back buffer of the swapchain is stored as the
6997 * surface the context belongs to. */
6998 *width = surface->currentDesc.Width;
6999 *height = surface->currentDesc.Height;
7002 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7003 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7005 if (device->filter_messages)
7007 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7008 window, message, wparam, lparam);
7009 return DefWindowProcW(window, message, wparam, lparam);
7012 if (message == WM_DESTROY)
7014 TRACE("unregister window %p.\n", window);
7015 wined3d_unregister_window(window);
7017 if (device->focus_window == window) device->focus_window = NULL;
7018 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7021 return CallWindowProcW(proc, window, message, wparam, lparam);