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[EXT_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[EXT_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, UINT Size,
483 DWORD Usage, DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
484 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
487 struct wined3d_buffer *object;
491 if (Pool == WINED3DPOOL_SCRATCH)
493 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
494 * anyway, SCRATCH vertex buffers aren't usable anywhere
496 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
497 *ppVertexBuffer = NULL;
498 return WINED3DERR_INVALIDCALL;
501 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
504 ERR("Out of memory\n");
505 *ppVertexBuffer = NULL;
506 return WINED3DERR_OUTOFVIDEOMEMORY;
509 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
510 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
513 WARN("Failed to initialize buffer, hr %#x.\n", hr);
514 HeapFree(GetProcessHeap(), 0, object);
518 TRACE("Created buffer %p.\n", object);
519 TRACE("FVF %#x, Pool %#x.\n", FVF, Pool);
520 *ppVertexBuffer = (IWineD3DBuffer *)object;
522 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
523 * drawStridedFast (half-life 2).
525 * Basically converting the vertices in the buffer is quite expensive, and observations
526 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
527 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
529 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
530 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
531 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
532 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
534 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
535 * more. In this call we can convert dx7 buffers too.
537 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
538 if (!This->adapter->gl_info.supported[ARB_VERTEX_BUFFER_OBJECT])
540 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
541 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
542 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
543 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
544 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
545 } else if(!(Usage & WINED3DUSAGE_OPTIMIZE) && conv) {
546 TRACE("Not creating a vbo because the fvf needs conversion, but VB optimization is disabled\n");
548 object->flags |= WINED3D_BUFFER_CREATEBO;
553 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
554 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
555 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
558 struct wined3d_buffer *object;
561 TRACE("(%p) Creating index buffer\n", This);
563 /* Allocate the storage for the device */
564 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
567 ERR("Out of memory\n");
568 *ppIndexBuffer = NULL;
569 return WINED3DERR_OUTOFVIDEOMEMORY;
572 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
573 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
576 WARN("Failed to initialize buffer, hr %#x\n", hr);
577 HeapFree(GetProcessHeap(), 0, object);
581 TRACE("Created buffer %p.\n", object);
583 if (Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC)
584 && This->adapter->gl_info.supported[ARB_VERTEX_BUFFER_OBJECT])
586 object->flags |= WINED3D_BUFFER_CREATEBO;
589 *ppIndexBuffer = (IWineD3DBuffer *) object;
594 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
595 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
598 IWineD3DStateBlockImpl *object;
601 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
604 ERR("Failed to allocate stateblock memory.\n");
605 return E_OUTOFMEMORY;
608 hr = stateblock_init(object, This, type);
611 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
612 HeapFree(GetProcessHeap(), 0, object);
616 TRACE("Created stateblock %p.\n", object);
617 *stateblock = (IWineD3DStateBlock *)object;
622 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
623 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
624 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
625 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
628 IWineD3DSurfaceImpl *object;
631 TRACE("(%p) Create surface\n",This);
633 if (Impl == SURFACE_OPENGL && !This->adapter)
635 ERR("OpenGL surfaces are not available without OpenGL.\n");
636 return WINED3DERR_NOTAVAILABLE;
639 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
642 ERR("Failed to allocate surface memory.\n");
644 return WINED3DERR_OUTOFVIDEOMEMORY;
647 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
648 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
651 WARN("Failed to initialize surface, returning %#x.\n", hr);
652 HeapFree(GetProcessHeap(), 0, object);
657 TRACE("(%p) : Created surface %p\n", This, object);
659 *ppSurface = (IWineD3DSurface *)object;
664 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
665 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
667 struct wined3d_rendertarget_view *object;
669 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
672 ERR("Failed to allocate memory\n");
673 return E_OUTOFMEMORY;
676 object->vtbl = &wined3d_rendertarget_view_vtbl;
677 object->refcount = 1;
678 IWineD3DResource_AddRef(resource);
679 object->resource = resource;
680 object->parent = parent;
682 *rendertarget_view = (IWineD3DRendertargetView *)object;
687 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
688 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
689 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
692 IWineD3DTextureImpl *object;
695 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
696 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
697 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
699 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
702 ERR("Out of memory\n");
704 return WINED3DERR_OUTOFVIDEOMEMORY;
707 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
710 WARN("Failed to initialize texture, returning %#x\n", hr);
711 HeapFree(GetProcessHeap(), 0, object);
716 *ppTexture = (IWineD3DTexture *)object;
718 TRACE("(%p) : Created texture %p\n", This, object);
723 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
724 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
725 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
728 IWineD3DVolumeTextureImpl *object;
731 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
732 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
734 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
737 ERR("Out of memory\n");
738 *ppVolumeTexture = NULL;
739 return WINED3DERR_OUTOFVIDEOMEMORY;
742 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
745 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
746 HeapFree(GetProcessHeap(), 0, object);
747 *ppVolumeTexture = NULL;
751 TRACE("(%p) : Created volume texture %p.\n", This, object);
752 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
757 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
758 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
759 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
762 IWineD3DVolumeImpl *object;
765 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
766 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
768 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
771 ERR("Out of memory\n");
773 return WINED3DERR_OUTOFVIDEOMEMORY;
776 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
779 WARN("Failed to initialize volume, returning %#x.\n", hr);
780 HeapFree(GetProcessHeap(), 0, object);
784 TRACE("(%p) : Created volume %p.\n", This, object);
785 *ppVolume = (IWineD3DVolume *)object;
790 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
791 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
792 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
795 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
798 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
801 ERR("Out of memory\n");
802 *ppCubeTexture = NULL;
803 return WINED3DERR_OUTOFVIDEOMEMORY;
806 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
809 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
810 HeapFree(GetProcessHeap(), 0, object);
811 *ppCubeTexture = NULL;
815 TRACE("(%p) : Created Cube Texture %p\n", This, object);
816 *ppCubeTexture = (IWineD3DCubeTexture *)object;
821 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
823 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
824 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
825 HRESULT hr = WINED3DERR_NOTAVAILABLE;
826 const IWineD3DQueryVtbl *vtable;
828 /* Just a check to see if we support this type of query */
830 case WINED3DQUERYTYPE_OCCLUSION:
831 TRACE("(%p) occlusion query\n", This);
832 if (gl_info->supported[ARB_OCCLUSION_QUERY])
835 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
837 vtable = &IWineD3DOcclusionQuery_Vtbl;
840 case WINED3DQUERYTYPE_EVENT:
841 if (!gl_info->supported[NV_FENCE] && !gl_info->supported[APPLE_FENCE])
843 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
844 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
846 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
848 vtable = &IWineD3DEventQuery_Vtbl;
852 case WINED3DQUERYTYPE_VCACHE:
853 case WINED3DQUERYTYPE_RESOURCEMANAGER:
854 case WINED3DQUERYTYPE_VERTEXSTATS:
855 case WINED3DQUERYTYPE_TIMESTAMP:
856 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
857 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
858 case WINED3DQUERYTYPE_PIPELINETIMINGS:
859 case WINED3DQUERYTYPE_INTERFACETIMINGS:
860 case WINED3DQUERYTYPE_VERTEXTIMINGS:
861 case WINED3DQUERYTYPE_PIXELTIMINGS:
862 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
863 case WINED3DQUERYTYPE_CACHEUTILIZATION:
865 /* Use the base Query vtable until we have a special one for each query */
866 vtable = &IWineD3DQuery_Vtbl;
867 FIXME("(%p) Unhandled query type %d\n", This, Type);
869 if(NULL == ppQuery || hr != WINED3D_OK) {
873 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
876 ERR("Out of memory\n");
878 return WINED3DERR_OUTOFVIDEOMEMORY;
881 object->lpVtbl = vtable;
883 object->state = QUERY_CREATED;
884 object->device = This;
885 object->parent = parent;
888 *ppQuery = (IWineD3DQuery *)object;
890 /* allocated the 'extended' data based on the type of query requested */
892 case WINED3DQUERYTYPE_OCCLUSION:
893 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
894 ((struct wined3d_occlusion_query *)object->extendedData)->context = NULL;
897 case WINED3DQUERYTYPE_EVENT:
898 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query));
899 ((struct wined3d_event_query *)object->extendedData)->context = NULL;
902 case WINED3DQUERYTYPE_VCACHE:
903 case WINED3DQUERYTYPE_RESOURCEMANAGER:
904 case WINED3DQUERYTYPE_VERTEXSTATS:
905 case WINED3DQUERYTYPE_TIMESTAMP:
906 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
907 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
908 case WINED3DQUERYTYPE_PIPELINETIMINGS:
909 case WINED3DQUERYTYPE_INTERFACETIMINGS:
910 case WINED3DQUERYTYPE_VERTEXTIMINGS:
911 case WINED3DQUERYTYPE_PIXELTIMINGS:
912 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
913 case WINED3DQUERYTYPE_CACHEUTILIZATION:
915 object->extendedData = 0;
916 FIXME("(%p) Unhandled query type %d\n",This , Type);
918 TRACE("(%p) : Created Query %p\n", This, object);
922 /*****************************************************************************
923 * IWineD3DDeviceImpl_SetupFullscreenWindow
925 * Helper function that modifies a HWND's Style and ExStyle for proper
929 * iface: Pointer to the IWineD3DDevice interface
930 * window: Window to setup
932 *****************************************************************************/
933 static LONG fullscreen_style(LONG orig_style) {
934 LONG style = orig_style;
935 style &= ~WS_CAPTION;
936 style &= ~WS_THICKFRAME;
938 /* Make sure the window is managed, otherwise we won't get keyboard input */
939 style |= WS_POPUP | WS_SYSMENU;
944 static LONG fullscreen_exStyle(LONG orig_exStyle) {
945 LONG exStyle = orig_exStyle;
947 /* Filter out window decorations */
948 exStyle &= ~WS_EX_WINDOWEDGE;
949 exStyle &= ~WS_EX_CLIENTEDGE;
954 void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDeviceImpl *This, HWND window, UINT w, UINT h)
957 /* Don't do anything if an original style is stored.
958 * That shouldn't happen
960 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
961 if (This->style || This->exStyle) {
962 ERR("(%p): Want to change the window parameters of HWND %p, but "
963 "another style is stored for restoration afterwards\n", This, window);
966 /* Get the parameters and save them */
967 style = GetWindowLongW(window, GWL_STYLE);
968 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
970 This->exStyle = exStyle;
972 style = fullscreen_style(style);
973 exStyle = fullscreen_exStyle(exStyle);
975 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
976 This->style, This->exStyle, style, exStyle);
978 SetWindowLongW(window, GWL_STYLE, style);
979 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
981 /* Inform the window about the update. */
982 SetWindowPos(window, HWND_TOP, 0, 0,
983 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
986 /*****************************************************************************
987 * IWineD3DDeviceImpl_RestoreWindow
989 * Helper function that restores a windows' properties when taking it out
993 * iface: Pointer to the IWineD3DDevice interface
994 * window: Window to setup
996 *****************************************************************************/
997 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1001 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1002 * switch, do nothing
1004 if (!This->style && !This->exStyle) return;
1006 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1007 This, window, This->style, This->exStyle);
1009 style = GetWindowLongW(window, GWL_STYLE);
1010 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1012 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1013 * Some applications change it before calling Reset() when switching between windowed and
1014 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1016 if (style == fullscreen_style(This->style) && exStyle == fullscreen_exStyle(This->exStyle))
1018 SetWindowLongW(window, GWL_STYLE, This->style);
1019 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1022 /* Delete the old values */
1026 /* Inform the window about the update */
1027 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1028 0, 0, 0, 0, /* Pos, Size, ignored */
1029 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1032 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1033 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
1034 IUnknown *parent, WINED3DSURFTYPE surface_type)
1036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1037 IWineD3DSwapChainImpl *object;
1040 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1041 iface, present_parameters, swapchain, parent, surface_type);
1043 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1046 ERR("Failed to allocate swapchain memory.\n");
1047 return E_OUTOFMEMORY;
1050 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1053 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1054 HeapFree(GetProcessHeap(), 0, object);
1058 TRACE("Created swapchain %p.\n", object);
1059 *swapchain = (IWineD3DSwapChain *)object;
1064 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1065 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1067 TRACE("(%p)\n", This);
1069 return This->NumberOfSwapChains;
1072 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1073 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1074 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1076 if(iSwapChain < This->NumberOfSwapChains) {
1077 *pSwapChain = This->swapchains[iSwapChain];
1078 IWineD3DSwapChain_AddRef(*pSwapChain);
1079 TRACE("(%p) returning %p\n", This, *pSwapChain);
1082 TRACE("Swapchain out of range\n");
1084 return WINED3DERR_INVALIDCALL;
1088 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1089 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1090 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1092 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1093 IWineD3DVertexDeclarationImpl *object = NULL;
1096 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1097 iface, declaration, parent, elements, element_count);
1099 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1102 ERR("Failed to allocate vertex declaration memory.\n");
1103 return E_OUTOFMEMORY;
1106 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1109 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1110 HeapFree(GetProcessHeap(), 0, object);
1114 TRACE("Created vertex declaration %p.\n", object);
1115 *declaration = (IWineD3DVertexDeclaration *)object;
1120 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1121 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1123 unsigned int idx, idx2;
1124 unsigned int offset;
1125 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1126 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1127 BOOL has_blend_idx = has_blend &&
1128 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1129 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1130 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1131 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1132 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1133 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1134 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1136 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1137 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1138 WINED3DVERTEXELEMENT *elements = NULL;
1141 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1142 if (has_blend_idx) num_blends--;
1144 /* Compute declaration size */
1145 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1146 has_psize + has_diffuse + has_specular + num_textures;
1148 /* convert the declaration */
1149 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1150 if (!elements) return ~0U;
1154 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1155 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1156 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1158 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1159 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1160 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1163 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1164 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1166 elements[idx].usage_idx = 0;
1169 if (has_blend && (num_blends > 0)) {
1170 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1171 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1173 switch(num_blends) {
1174 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1175 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1176 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1177 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1179 ERR("Unexpected amount of blend values: %u\n", num_blends);
1182 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1183 elements[idx].usage_idx = 0;
1186 if (has_blend_idx) {
1187 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1188 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1189 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1190 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1191 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1193 elements[idx].format = WINED3DFMT_R32_FLOAT;
1194 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1195 elements[idx].usage_idx = 0;
1199 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1200 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1201 elements[idx].usage_idx = 0;
1205 elements[idx].format = WINED3DFMT_R32_FLOAT;
1206 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1207 elements[idx].usage_idx = 0;
1211 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1212 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1213 elements[idx].usage_idx = 0;
1217 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1218 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1219 elements[idx].usage_idx = 1;
1222 for (idx2 = 0; idx2 < num_textures; idx2++) {
1223 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1224 switch (numcoords) {
1225 case WINED3DFVF_TEXTUREFORMAT1:
1226 elements[idx].format = WINED3DFMT_R32_FLOAT;
1228 case WINED3DFVF_TEXTUREFORMAT2:
1229 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1231 case WINED3DFVF_TEXTUREFORMAT3:
1232 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1234 case WINED3DFVF_TEXTUREFORMAT4:
1235 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1238 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1239 elements[idx].usage_idx = idx2;
1243 /* Now compute offsets, and initialize the rest of the fields */
1244 for (idx = 0, offset = 0; idx < size; ++idx)
1246 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1247 elements[idx].input_slot = 0;
1248 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1249 elements[idx].offset = offset;
1250 offset += format_desc->component_count * format_desc->component_size;
1253 *ppVertexElements = elements;
1257 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1258 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1259 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1262 WINED3DVERTEXELEMENT *elements;
1266 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1268 size = ConvertFvfToDeclaration(This, fvf, &elements);
1269 if (size == ~0U) return E_OUTOFMEMORY;
1271 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1272 HeapFree(GetProcessHeap(), 0, elements);
1276 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1277 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1278 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1279 const struct wined3d_parent_ops *parent_ops)
1281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1282 IWineD3DVertexShaderImpl *object;
1285 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1288 ERR("Failed to allocate shader memory.\n");
1289 return E_OUTOFMEMORY;
1292 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1295 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1296 HeapFree(GetProcessHeap(), 0, object);
1300 TRACE("Created vertex shader %p.\n", object);
1301 *ppVertexShader = (IWineD3DVertexShader *)object;
1306 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1307 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1308 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1309 const struct wined3d_parent_ops *parent_ops)
1311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1312 IWineD3DPixelShaderImpl *object;
1315 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1318 ERR("Failed to allocate shader memory.\n");
1319 return E_OUTOFMEMORY;
1322 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1325 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1326 HeapFree(GetProcessHeap(), 0, object);
1330 TRACE("Created pixel shader %p.\n", object);
1331 *ppPixelShader = (IWineD3DPixelShader *)object;
1336 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1337 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1340 IWineD3DPaletteImpl *object;
1342 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1344 /* Create the new object */
1345 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1347 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1348 return E_OUTOFMEMORY;
1351 object->lpVtbl = &IWineD3DPalette_Vtbl;
1353 object->Flags = Flags;
1354 object->parent = Parent;
1355 object->device = This;
1356 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1357 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1360 HeapFree( GetProcessHeap(), 0, object);
1361 return E_OUTOFMEMORY;
1364 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1366 IWineD3DPalette_Release((IWineD3DPalette *) object);
1370 *Palette = (IWineD3DPalette *) object;
1375 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1379 HDC dcb = NULL, dcs = NULL;
1380 WINEDDCOLORKEY colorkey;
1382 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1385 GetObjectA(hbm, sizeof(BITMAP), &bm);
1386 dcb = CreateCompatibleDC(NULL);
1388 SelectObject(dcb, hbm);
1392 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1393 * couldn't be loaded
1395 memset(&bm, 0, sizeof(bm));
1400 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1401 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1402 NULL, &wined3d_null_parent_ops);
1404 ERR("Wine logo requested, but failed to create surface\n");
1409 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1410 if(FAILED(hr)) goto out;
1411 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1412 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1414 colorkey.dwColorSpaceLowValue = 0;
1415 colorkey.dwColorSpaceHighValue = 0;
1416 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1418 /* Fill the surface with a white color to show that wined3d is there */
1419 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1432 /* Context activation is done by the caller. */
1433 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1435 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1437 /* Under DirectX you can have texture stage operations even if no texture is
1438 bound, whereas opengl will only do texture operations when a valid texture is
1439 bound. We emulate this by creating dummy textures and binding them to each
1440 texture stage, but disable all stages by default. Hence if a stage is enabled
1441 then the default texture will kick in until replaced by a SetTexture call */
1444 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1446 /* The dummy texture does not have client storage backing */
1447 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1448 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1451 for (i = 0; i < gl_info->limits.textures; ++i)
1453 GLubyte white = 255;
1455 /* Make appropriate texture active */
1456 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1457 checkGLcall("glActiveTextureARB");
1459 /* Generate an opengl texture name */
1460 glGenTextures(1, &This->dummyTextureName[i]);
1461 checkGLcall("glGenTextures");
1462 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1464 /* Generate a dummy 2d texture (not using 1d because they cause many
1465 * DRI drivers fall back to sw) */
1466 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1467 checkGLcall("glBindTexture");
1469 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1470 checkGLcall("glTexImage2D");
1473 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1475 /* Reenable because if supported it is enabled by default */
1476 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1477 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1483 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1484 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1487 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1488 IWineD3DSwapChainImpl *swapchain = NULL;
1489 struct wined3d_context *context;
1494 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1496 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1497 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1499 /* TODO: Test if OpenGL is compiled in and loaded */
1501 TRACE("(%p) : Creating stateblock\n", This);
1502 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1503 hr = IWineD3DDevice_CreateStateBlock(iface,
1505 (IWineD3DStateBlock **)&This->stateBlock,
1507 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1508 WARN("Failed to create stateblock\n");
1511 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1512 This->updateStateBlock = This->stateBlock;
1513 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1515 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1516 sizeof(IWineD3DSurface *) * gl_info->limits.buffers);
1517 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1518 sizeof(GLenum) * gl_info->limits.buffers);
1520 This->NumberOfPalettes = 1;
1521 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1522 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1523 ERR("Out of memory!\n");
1527 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1528 if(!This->palettes[0]) {
1529 ERR("Out of memory!\n");
1533 for (i = 0; i < 256; ++i) {
1534 This->palettes[0][i].peRed = 0xFF;
1535 This->palettes[0][i].peGreen = 0xFF;
1536 This->palettes[0][i].peBlue = 0xFF;
1537 This->palettes[0][i].peFlags = 0xFF;
1539 This->currentPalette = 0;
1541 /* Initialize the texture unit mapping to a 1:1 mapping */
1542 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1544 if (state < gl_info->limits.fragment_samplers)
1546 This->texUnitMap[state] = state;
1547 This->rev_tex_unit_map[state] = state;
1549 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1550 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1554 /* Setup the implicit swapchain. This also initializes a context. */
1555 TRACE("Creating implicit swapchain\n");
1556 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1557 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1560 WARN("Failed to create implicit swapchain\n");
1564 This->NumberOfSwapChains = 1;
1565 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1566 if(!This->swapchains) {
1567 ERR("Out of memory!\n");
1570 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1572 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1573 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1574 This->render_targets[0] = swapchain->backBuffer[0];
1577 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1578 This->render_targets[0] = swapchain->frontBuffer;
1580 IWineD3DSurface_AddRef(This->render_targets[0]);
1582 /* Depth Stencil support */
1583 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1584 if (NULL != This->stencilBufferTarget) {
1585 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1588 hr = This->shader_backend->shader_alloc_private(iface);
1590 TRACE("Shader private data couldn't be allocated\n");
1593 hr = This->frag_pipe->alloc_private(iface);
1595 TRACE("Fragment pipeline private data couldn't be allocated\n");
1598 hr = This->blitter->alloc_private(iface);
1600 TRACE("Blitter private data couldn't be allocated\n");
1604 /* Set up some starting GL setup */
1606 /* Setup all the devices defaults */
1607 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1609 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1611 create_dummy_textures(This);
1615 /* Initialize the current view state */
1616 This->view_ident = 1;
1617 This->contexts[0]->last_was_rhw = 0;
1618 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1619 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1621 switch(wined3d_settings.offscreen_rendering_mode) {
1623 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1627 This->offscreenBuffer = GL_BACK;
1630 case ORM_BACKBUFFER:
1632 if (context_get_current()->aux_buffers > 0)
1634 TRACE("Using auxilliary buffer for offscreen rendering\n");
1635 This->offscreenBuffer = GL_AUX0;
1637 TRACE("Using back buffer for offscreen rendering\n");
1638 This->offscreenBuffer = GL_BACK;
1643 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1646 context_release(context);
1648 /* Clear the screen */
1649 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1650 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1653 This->d3d_initialized = TRUE;
1655 if(wined3d_settings.logo) {
1656 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1658 This->highest_dirty_ps_const = 0;
1659 This->highest_dirty_vs_const = 0;
1663 HeapFree(GetProcessHeap(), 0, This->render_targets);
1664 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1665 HeapFree(GetProcessHeap(), 0, This->swapchains);
1666 This->NumberOfSwapChains = 0;
1667 if(This->palettes) {
1668 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1669 HeapFree(GetProcessHeap(), 0, This->palettes);
1671 This->NumberOfPalettes = 0;
1673 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1675 if(This->stateBlock) {
1676 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1677 This->stateBlock = NULL;
1679 if (This->blit_priv) {
1680 This->blitter->free_private(iface);
1682 if (This->fragment_priv) {
1683 This->frag_pipe->free_private(iface);
1685 if (This->shader_priv) {
1686 This->shader_backend->shader_free_private(iface);
1691 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1692 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1695 IWineD3DSwapChainImpl *swapchain = NULL;
1698 /* Setup the implicit swapchain */
1699 TRACE("Creating implicit swapchain\n");
1700 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1701 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1704 WARN("Failed to create implicit swapchain\n");
1708 This->NumberOfSwapChains = 1;
1709 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1710 if(!This->swapchains) {
1711 ERR("Out of memory!\n");
1714 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1718 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1722 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1724 IWineD3DResource_UnLoad(resource);
1725 IWineD3DResource_Release(resource);
1729 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1730 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1733 const struct wined3d_gl_info *gl_info;
1734 struct wined3d_context *context;
1737 TRACE("(%p)\n", This);
1739 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1741 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1742 * it was created. Thus make sure a context is active for the glDelete* calls
1744 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1745 gl_info = context->gl_info;
1747 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1749 /* Unload resources */
1750 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1752 TRACE("Deleting high order patches\n");
1753 for(i = 0; i < PATCHMAP_SIZE; i++) {
1754 struct list *e1, *e2;
1755 struct WineD3DRectPatch *patch;
1756 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1757 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1758 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1762 /* Delete the palette conversion shader if it is around */
1763 if(This->paletteConversionShader) {
1765 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
1767 This->paletteConversionShader = 0;
1770 /* Delete the pbuffer context if there is any */
1771 if(This->pbufferContext) context_destroy(This, This->pbufferContext);
1773 /* Delete the mouse cursor texture */
1774 if(This->cursorTexture) {
1776 glDeleteTextures(1, &This->cursorTexture);
1778 This->cursorTexture = 0;
1781 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1782 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1784 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1785 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1788 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1789 * private data, it might contain opengl pointers
1791 if(This->depth_blt_texture) {
1793 glDeleteTextures(1, &This->depth_blt_texture);
1795 This->depth_blt_texture = 0;
1797 if (This->depth_blt_rb) {
1799 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1801 This->depth_blt_rb = 0;
1802 This->depth_blt_rb_w = 0;
1803 This->depth_blt_rb_h = 0;
1806 /* Release the update stateblock */
1807 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1808 if(This->updateStateBlock != This->stateBlock)
1809 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1811 This->updateStateBlock = NULL;
1813 { /* because were not doing proper internal refcounts releasing the primary state block
1814 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1815 to set this->stateBlock = NULL; first */
1816 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1817 This->stateBlock = NULL;
1819 /* Release the stateblock */
1820 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1821 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1825 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1826 This->blitter->free_private(iface);
1827 This->frag_pipe->free_private(iface);
1828 This->shader_backend->shader_free_private(iface);
1830 /* Release the buffers (with sanity checks)*/
1831 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1832 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1833 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
1834 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
1836 This->stencilBufferTarget = NULL;
1838 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1839 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1840 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1842 TRACE("Setting rendertarget to NULL\n");
1843 This->render_targets[0] = NULL;
1845 if (This->auto_depth_stencil_buffer) {
1846 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
1848 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1850 This->auto_depth_stencil_buffer = NULL;
1853 context_release(context);
1855 for(i=0; i < This->NumberOfSwapChains; i++) {
1856 TRACE("Releasing the implicit swapchain %d\n", i);
1857 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1858 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1862 HeapFree(GetProcessHeap(), 0, This->swapchains);
1863 This->swapchains = NULL;
1864 This->NumberOfSwapChains = 0;
1866 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1867 HeapFree(GetProcessHeap(), 0, This->palettes);
1868 This->palettes = NULL;
1869 This->NumberOfPalettes = 0;
1871 HeapFree(GetProcessHeap(), 0, This->render_targets);
1872 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1873 This->render_targets = NULL;
1874 This->draw_buffers = NULL;
1876 This->d3d_initialized = FALSE;
1880 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1884 for(i=0; i < This->NumberOfSwapChains; i++) {
1885 TRACE("Releasing the implicit swapchain %d\n", i);
1886 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1887 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1891 HeapFree(GetProcessHeap(), 0, This->swapchains);
1892 This->swapchains = NULL;
1893 This->NumberOfSwapChains = 0;
1897 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1898 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1899 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1901 * There is no way to deactivate thread safety once it is enabled.
1903 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1906 /*For now just store the flag(needed in case of ddraw) */
1907 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1912 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1913 const WINED3DDISPLAYMODE* pMode) {
1915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1917 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1920 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1922 /* Resize the screen even without a window:
1923 * The app could have unset it with SetCooperativeLevel, but not called
1924 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1925 * but we don't have any hwnd
1928 memset(&devmode, 0, sizeof(devmode));
1929 devmode.dmSize = sizeof(devmode);
1930 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1931 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1932 devmode.dmPelsWidth = pMode->Width;
1933 devmode.dmPelsHeight = pMode->Height;
1935 devmode.dmDisplayFrequency = pMode->RefreshRate;
1936 if (pMode->RefreshRate != 0) {
1937 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1940 /* Only change the mode if necessary */
1941 if( (This->ddraw_width == pMode->Width) &&
1942 (This->ddraw_height == pMode->Height) &&
1943 (This->ddraw_format == pMode->Format) &&
1944 (pMode->RefreshRate == 0) ) {
1948 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1949 if (ret != DISP_CHANGE_SUCCESSFUL) {
1950 if(devmode.dmDisplayFrequency != 0) {
1951 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1952 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1953 devmode.dmDisplayFrequency = 0;
1954 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1956 if(ret != DISP_CHANGE_SUCCESSFUL) {
1957 return WINED3DERR_NOTAVAILABLE;
1961 /* Store the new values */
1962 This->ddraw_width = pMode->Width;
1963 This->ddraw_height = pMode->Height;
1964 This->ddraw_format = pMode->Format;
1966 /* And finally clip mouse to our screen */
1967 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1968 ClipCursor(&clip_rc);
1973 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1975 *ppD3D = This->wined3d;
1976 TRACE("Returning %p.\n", *ppD3D);
1977 IWineD3D_AddRef(*ppD3D);
1981 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1984 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1985 (This->adapter->TextureRam/(1024*1024)),
1986 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
1987 /* return simulated texture memory left */
1988 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
1992 * Get / Set Stream Source
1994 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
1995 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
1997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1998 IWineD3DBuffer *oldSrc;
2000 if (StreamNumber >= MAX_STREAMS) {
2001 WARN("Stream out of range %d\n", StreamNumber);
2002 return WINED3DERR_INVALIDCALL;
2003 } else if(OffsetInBytes & 0x3) {
2004 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2005 return WINED3DERR_INVALIDCALL;
2008 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2009 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2011 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2013 if(oldSrc == pStreamData &&
2014 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2015 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2016 TRACE("Application is setting the old values over, nothing to do\n");
2020 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2022 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2023 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2026 /* Handle recording of state blocks */
2027 if (This->isRecordingState) {
2028 TRACE("Recording... not performing anything\n");
2029 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2030 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2034 if (pStreamData != NULL) {
2035 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2036 IWineD3DBuffer_AddRef(pStreamData);
2038 if (oldSrc != NULL) {
2039 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2040 IWineD3DBuffer_Release(oldSrc);
2043 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2048 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2049 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2053 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2054 This->stateBlock->streamSource[StreamNumber],
2055 This->stateBlock->streamOffset[StreamNumber],
2056 This->stateBlock->streamStride[StreamNumber]);
2058 if (StreamNumber >= MAX_STREAMS) {
2059 WARN("Stream out of range %d\n", StreamNumber);
2060 return WINED3DERR_INVALIDCALL;
2062 *pStream = This->stateBlock->streamSource[StreamNumber];
2063 *pStride = This->stateBlock->streamStride[StreamNumber];
2065 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2068 if (*pStream != NULL) {
2069 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2074 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2076 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2077 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2079 /* Verify input at least in d3d9 this is invalid*/
2080 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2081 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2082 return WINED3DERR_INVALIDCALL;
2084 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2085 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2086 return WINED3DERR_INVALIDCALL;
2089 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2090 return WINED3DERR_INVALIDCALL;
2093 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2094 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2096 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2097 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2099 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2100 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2101 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2107 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2110 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2111 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2113 TRACE("(%p) : returning %d\n", This, *Divider);
2119 * Get / Set & Multiply Transform
2121 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2124 /* Most of this routine, comments included copied from ddraw tree initially: */
2125 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2127 /* Handle recording of state blocks */
2128 if (This->isRecordingState) {
2129 TRACE("Recording... not performing anything\n");
2130 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2131 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2136 * If the new matrix is the same as the current one,
2137 * we cut off any further processing. this seems to be a reasonable
2138 * optimization because as was noticed, some apps (warcraft3 for example)
2139 * tend towards setting the same matrix repeatedly for some reason.
2141 * From here on we assume that the new matrix is different, wherever it matters.
2143 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2144 TRACE("The app is setting the same matrix over again\n");
2147 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2151 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2152 where ViewMat = Camera space, WorldMat = world space.
2154 In OpenGL, camera and world space is combined into GL_MODELVIEW
2155 matrix. The Projection matrix stay projection matrix.
2158 /* Capture the times we can just ignore the change for now */
2159 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2160 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2161 /* Handled by the state manager */
2164 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2168 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2170 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2171 *pMatrix = This->stateBlock->transforms[State];
2175 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2176 const WINED3DMATRIX *mat = NULL;
2179 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2180 * below means it will be recorded in a state block change, but it
2181 * works regardless where it is recorded.
2182 * If this is found to be wrong, change to StateBlock.
2184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2185 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2187 if (State <= HIGHEST_TRANSFORMSTATE)
2189 mat = &This->updateStateBlock->transforms[State];
2191 FIXME("Unhandled transform state!!\n");
2194 multiply_matrix(&temp, mat, pMatrix);
2196 /* Apply change via set transform - will reapply to eg. lights this way */
2197 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2203 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2204 you can reference any indexes you want as long as that number max are enabled at any
2205 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2206 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2207 but when recording, just build a chain pretty much of commands to be replayed. */
2209 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2211 struct wined3d_light_info *object = NULL;
2212 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2216 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2218 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2222 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2223 return WINED3DERR_INVALIDCALL;
2226 switch(pLight->Type) {
2227 case WINED3DLIGHT_POINT:
2228 case WINED3DLIGHT_SPOT:
2229 case WINED3DLIGHT_PARALLELPOINT:
2230 case WINED3DLIGHT_GLSPOT:
2231 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2234 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2236 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2237 return WINED3DERR_INVALIDCALL;
2241 case WINED3DLIGHT_DIRECTIONAL:
2242 /* Ignores attenuation */
2246 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2247 return WINED3DERR_INVALIDCALL;
2250 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2252 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2253 if(object->OriginalIndex == Index) break;
2258 TRACE("Adding new light\n");
2259 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2261 ERR("Out of memory error when allocating a light\n");
2262 return E_OUTOFMEMORY;
2264 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2265 object->glIndex = -1;
2266 object->OriginalIndex = Index;
2269 /* Initialize the object */
2270 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,
2271 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2272 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2273 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2274 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2275 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2276 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2278 /* Save away the information */
2279 object->OriginalParms = *pLight;
2281 switch (pLight->Type) {
2282 case WINED3DLIGHT_POINT:
2284 object->lightPosn[0] = pLight->Position.x;
2285 object->lightPosn[1] = pLight->Position.y;
2286 object->lightPosn[2] = pLight->Position.z;
2287 object->lightPosn[3] = 1.0f;
2288 object->cutoff = 180.0f;
2292 case WINED3DLIGHT_DIRECTIONAL:
2294 object->lightPosn[0] = -pLight->Direction.x;
2295 object->lightPosn[1] = -pLight->Direction.y;
2296 object->lightPosn[2] = -pLight->Direction.z;
2297 object->lightPosn[3] = 0.0f;
2298 object->exponent = 0.0f;
2299 object->cutoff = 180.0f;
2302 case WINED3DLIGHT_SPOT:
2304 object->lightPosn[0] = pLight->Position.x;
2305 object->lightPosn[1] = pLight->Position.y;
2306 object->lightPosn[2] = pLight->Position.z;
2307 object->lightPosn[3] = 1.0f;
2310 object->lightDirn[0] = pLight->Direction.x;
2311 object->lightDirn[1] = pLight->Direction.y;
2312 object->lightDirn[2] = pLight->Direction.z;
2313 object->lightDirn[3] = 1.0f;
2316 * opengl-ish and d3d-ish spot lights use too different models for the
2317 * light "intensity" as a function of the angle towards the main light direction,
2318 * so we only can approximate very roughly.
2319 * however spot lights are rather rarely used in games (if ever used at all).
2320 * furthermore if still used, probably nobody pays attention to such details.
2322 if (pLight->Falloff == 0) {
2323 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2324 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2325 * will always be 1.0 for both of them, and we don't have to care for the
2326 * rest of the rather complex calculation
2328 object->exponent = 0.0f;
2330 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2331 if (rho < 0.0001f) rho = 0.0001f;
2332 object->exponent = -0.3f/logf(cosf(rho/2));
2334 if (object->exponent > 128.0f)
2336 object->exponent = 128.0f;
2338 object->cutoff = pLight->Phi*90/M_PI;
2344 FIXME("Unrecognized light type %d\n", pLight->Type);
2347 /* Update the live definitions if the light is currently assigned a glIndex */
2348 if (object->glIndex != -1 && !This->isRecordingState) {
2349 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2354 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2356 struct wined3d_light_info *lightInfo = NULL;
2357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2358 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2360 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2362 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2364 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2365 if(lightInfo->OriginalIndex == Index) break;
2369 if (lightInfo == NULL) {
2370 TRACE("Light information requested but light not defined\n");
2371 return WINED3DERR_INVALIDCALL;
2374 *pLight = lightInfo->OriginalParms;
2379 * Get / Set Light Enable
2380 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2382 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2384 struct wined3d_light_info *lightInfo = NULL;
2385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2386 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2388 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2390 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2392 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2393 if(lightInfo->OriginalIndex == Index) break;
2396 TRACE("Found light: %p\n", lightInfo);
2398 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2399 if (lightInfo == NULL) {
2401 TRACE("Light enabled requested but light not defined, so defining one!\n");
2402 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2404 /* Search for it again! Should be fairly quick as near head of list */
2405 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2407 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2408 if(lightInfo->OriginalIndex == Index) break;
2411 if (lightInfo == NULL) {
2412 FIXME("Adding default lights has failed dismally\n");
2413 return WINED3DERR_INVALIDCALL;
2418 if(lightInfo->glIndex != -1) {
2419 if(!This->isRecordingState) {
2420 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2423 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2424 lightInfo->glIndex = -1;
2426 TRACE("Light already disabled, nothing to do\n");
2428 lightInfo->enabled = FALSE;
2430 lightInfo->enabled = TRUE;
2431 if (lightInfo->glIndex != -1) {
2433 TRACE("Nothing to do as light was enabled\n");
2436 /* Find a free gl light */
2437 for(i = 0; i < This->maxConcurrentLights; i++) {
2438 if(This->updateStateBlock->activeLights[i] == NULL) {
2439 This->updateStateBlock->activeLights[i] = lightInfo;
2440 lightInfo->glIndex = i;
2444 if(lightInfo->glIndex == -1) {
2445 /* Our tests show that Windows returns D3D_OK in this situation, even with
2446 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2447 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2448 * as well for those lights.
2450 * TODO: Test how this affects rendering
2452 WARN("Too many concurrently active lights\n");
2456 /* i == lightInfo->glIndex */
2457 if(!This->isRecordingState) {
2458 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2466 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2468 struct wined3d_light_info *lightInfo = NULL;
2469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2471 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2472 TRACE("(%p) : for idx(%d)\n", This, Index);
2474 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2476 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2477 if(lightInfo->OriginalIndex == Index) break;
2481 if (lightInfo == NULL) {
2482 TRACE("Light enabled state requested but light not defined\n");
2483 return WINED3DERR_INVALIDCALL;
2485 /* true is 128 according to SetLightEnable */
2486 *pEnable = lightInfo->enabled ? 128 : 0;
2491 * Get / Set Clip Planes
2493 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2494 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2495 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2497 /* Validate Index */
2498 if (Index >= This->adapter->gl_info.limits.clipplanes)
2500 TRACE("Application has requested clipplane this device doesn't support\n");
2501 return WINED3DERR_INVALIDCALL;
2504 This->updateStateBlock->changed.clipplane |= 1 << Index;
2506 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2507 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2508 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2509 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2510 TRACE("Application is setting old values over, nothing to do\n");
2514 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2515 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2516 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2517 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2519 /* Handle recording of state blocks */
2520 if (This->isRecordingState) {
2521 TRACE("Recording... not performing anything\n");
2525 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2530 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2532 TRACE("(%p) : for idx %d\n", This, Index);
2534 /* Validate Index */
2535 if (Index >= This->adapter->gl_info.limits.clipplanes)
2537 TRACE("Application has requested clipplane this device doesn't support\n");
2538 return WINED3DERR_INVALIDCALL;
2541 pPlane[0] = This->stateBlock->clipplane[Index][0];
2542 pPlane[1] = This->stateBlock->clipplane[Index][1];
2543 pPlane[2] = This->stateBlock->clipplane[Index][2];
2544 pPlane[3] = This->stateBlock->clipplane[Index][3];
2549 * Get / Set Clip Plane Status
2550 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2552 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2554 FIXME("(%p) : stub\n", This);
2555 if (NULL == pClipStatus) {
2556 return WINED3DERR_INVALIDCALL;
2558 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2559 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2563 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2565 FIXME("(%p) : stub\n", This);
2566 if (NULL == pClipStatus) {
2567 return WINED3DERR_INVALIDCALL;
2569 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2570 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2575 * Get / Set Material
2577 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2580 This->updateStateBlock->changed.material = TRUE;
2581 This->updateStateBlock->material = *pMaterial;
2583 /* Handle recording of state blocks */
2584 if (This->isRecordingState) {
2585 TRACE("Recording... not performing anything\n");
2589 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2593 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2595 *pMaterial = This->updateStateBlock->material;
2596 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2597 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2598 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2599 pMaterial->Ambient.b, pMaterial->Ambient.a);
2600 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2601 pMaterial->Specular.b, pMaterial->Specular.a);
2602 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2603 pMaterial->Emissive.b, pMaterial->Emissive.a);
2604 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2612 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2613 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2616 IWineD3DBuffer *oldIdxs;
2618 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2619 oldIdxs = This->updateStateBlock->pIndexData;
2621 This->updateStateBlock->changed.indices = TRUE;
2622 This->updateStateBlock->pIndexData = pIndexData;
2623 This->updateStateBlock->IndexFmt = fmt;
2625 /* Handle recording of state blocks */
2626 if (This->isRecordingState) {
2627 TRACE("Recording... not performing anything\n");
2628 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2629 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2633 if(oldIdxs != pIndexData) {
2634 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2636 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2637 IWineD3DBuffer_AddRef(pIndexData);
2640 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2641 IWineD3DBuffer_Release(oldIdxs);
2648 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2652 *ppIndexData = This->stateBlock->pIndexData;
2654 /* up ref count on ppindexdata */
2656 IWineD3DBuffer_AddRef(*ppIndexData);
2657 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2659 TRACE("(%p) No index data set\n", This);
2661 TRACE("Returning %p\n", *ppIndexData);
2666 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2667 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2669 TRACE("(%p)->(%d)\n", This, BaseIndex);
2671 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2672 TRACE("Application is setting the old value over, nothing to do\n");
2676 This->updateStateBlock->baseVertexIndex = BaseIndex;
2678 if (This->isRecordingState) {
2679 TRACE("Recording... not performing anything\n");
2682 /* The base vertex index affects the stream sources */
2683 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2687 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2689 TRACE("(%p) : base_index %p\n", This, base_index);
2691 *base_index = This->stateBlock->baseVertexIndex;
2693 TRACE("Returning %u\n", *base_index);
2699 * Get / Set Viewports
2701 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2704 TRACE("(%p)\n", This);
2705 This->updateStateBlock->changed.viewport = TRUE;
2706 This->updateStateBlock->viewport = *pViewport;
2708 /* Handle recording of state blocks */
2709 if (This->isRecordingState) {
2710 TRACE("Recording... not performing anything\n");
2714 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2715 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2722 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2724 TRACE("(%p)\n", This);
2725 *pViewport = This->stateBlock->viewport;
2730 * Get / Set Render States
2731 * TODO: Verify against dx9 definitions
2733 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2736 DWORD oldValue = This->stateBlock->renderState[State];
2738 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2740 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2741 This->updateStateBlock->renderState[State] = Value;
2743 /* Handle recording of state blocks */
2744 if (This->isRecordingState) {
2745 TRACE("Recording... not performing anything\n");
2749 /* Compared here and not before the assignment to allow proper stateblock recording */
2750 if(Value == oldValue) {
2751 TRACE("Application is setting the old value over, nothing to do\n");
2753 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2759 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2761 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2762 *pValue = This->stateBlock->renderState[State];
2767 * Get / Set Sampler States
2768 * TODO: Verify against dx9 definitions
2771 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2775 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2776 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2778 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2779 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2782 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2783 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2784 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2787 * SetSampler is designed to allow for more than the standard up to 8 textures
2788 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2789 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2791 * http://developer.nvidia.com/object/General_FAQ.html#t6
2793 * There are two new settings for GForce
2795 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2796 * and the texture one:
2797 * GL_MAX_TEXTURE_COORDS_ARB.
2798 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2801 oldValue = This->stateBlock->samplerState[Sampler][Type];
2802 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2803 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2805 /* Handle recording of state blocks */
2806 if (This->isRecordingState) {
2807 TRACE("Recording... not performing anything\n");
2811 if(oldValue == Value) {
2812 TRACE("Application is setting the old value over, nothing to do\n");
2816 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2821 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2824 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2825 This, Sampler, debug_d3dsamplerstate(Type), Type);
2827 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2828 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2831 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2832 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2833 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2835 *Value = This->stateBlock->samplerState[Sampler][Type];
2836 TRACE("(%p) : Returning %#x\n", This, *Value);
2841 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2844 This->updateStateBlock->changed.scissorRect = TRUE;
2845 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2846 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2849 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2851 if(This->isRecordingState) {
2852 TRACE("Recording... not performing anything\n");
2856 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2861 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2864 *pRect = This->updateStateBlock->scissorRect;
2865 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2869 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2871 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2873 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2875 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2876 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2878 This->updateStateBlock->vertexDecl = pDecl;
2879 This->updateStateBlock->changed.vertexDecl = TRUE;
2881 if (This->isRecordingState) {
2882 TRACE("Recording... not performing anything\n");
2884 } else if(pDecl == oldDecl) {
2885 /* Checked after the assignment to allow proper stateblock recording */
2886 TRACE("Application is setting the old declaration over, nothing to do\n");
2890 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2894 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2897 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2899 *ppDecl = This->stateBlock->vertexDecl;
2900 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2904 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2906 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2908 This->updateStateBlock->vertexShader = pShader;
2909 This->updateStateBlock->changed.vertexShader = TRUE;
2911 if (This->isRecordingState) {
2912 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2913 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2914 TRACE("Recording... not performing anything\n");
2916 } else if(oldShader == pShader) {
2917 /* Checked here to allow proper stateblock recording */
2918 TRACE("App is setting the old shader over, nothing to do\n");
2922 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2923 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2924 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2926 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2931 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2934 if (NULL == ppShader) {
2935 return WINED3DERR_INVALIDCALL;
2937 *ppShader = This->stateBlock->vertexShader;
2938 if( NULL != *ppShader)
2939 IWineD3DVertexShader_AddRef(*ppShader);
2941 TRACE("(%p) : returning %p\n", This, *ppShader);
2945 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2946 IWineD3DDevice *iface,
2948 CONST BOOL *srcData,
2951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2952 unsigned int i, cnt = min(count, MAX_CONST_B - start);
2954 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2955 iface, srcData, start, count);
2957 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
2959 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2960 for (i = 0; i < cnt; i++)
2961 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2963 for (i = start; i < cnt + start; ++i) {
2964 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
2967 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2972 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2973 IWineD3DDevice *iface,
2978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2979 int cnt = min(count, MAX_CONST_B - start);
2981 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2982 iface, dstData, start, count);
2984 if (dstData == NULL || cnt < 0)
2985 return WINED3DERR_INVALIDCALL;
2987 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2991 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2992 IWineD3DDevice *iface,
2997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2998 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3000 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3001 iface, srcData, start, count);
3003 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3005 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3006 for (i = 0; i < cnt; i++)
3007 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3008 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3010 for (i = start; i < cnt + start; ++i) {
3011 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3014 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3019 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3020 IWineD3DDevice *iface,
3025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3026 int cnt = min(count, MAX_CONST_I - start);
3028 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3029 iface, dstData, start, count);
3031 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3032 return WINED3DERR_INVALIDCALL;
3034 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3038 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3039 IWineD3DDevice *iface,
3041 CONST float *srcData,
3044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3047 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3048 iface, srcData, start, count);
3050 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3051 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3052 return WINED3DERR_INVALIDCALL;
3054 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3056 for (i = 0; i < count; i++)
3057 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3058 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3061 if (!This->isRecordingState)
3063 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3064 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3067 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3068 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3073 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3074 IWineD3DDevice *iface,
3079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3080 int cnt = min(count, This->d3d_vshader_constantF - start);
3082 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3083 iface, dstData, start, count);
3085 if (dstData == NULL || cnt < 0)
3086 return WINED3DERR_INVALIDCALL;
3088 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3092 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3094 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3096 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3100 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3102 DWORD i = This->rev_tex_unit_map[unit];
3103 DWORD j = This->texUnitMap[stage];
3105 This->texUnitMap[stage] = unit;
3106 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3108 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3111 This->rev_tex_unit_map[unit] = stage;
3112 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3114 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3118 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3121 This->fixed_function_usage_map = 0;
3122 for (i = 0; i < MAX_TEXTURES; ++i) {
3123 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3124 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3125 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3126 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3127 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3128 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3129 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3130 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3132 if (color_op == WINED3DTOP_DISABLE) {
3133 /* Not used, and disable higher stages */
3137 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3138 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3139 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3140 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3141 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3142 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3143 This->fixed_function_usage_map |= (1 << i);
3146 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3147 This->fixed_function_usage_map |= (1 << (i + 1));
3152 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3153 unsigned int i, tex;
3156 device_update_fixed_function_usage_map(This);
3157 ffu_map = This->fixed_function_usage_map;
3159 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3160 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3161 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3163 if (!(ffu_map & 1)) continue;
3165 if (This->texUnitMap[i] != i) {
3166 device_map_stage(This, i, i);
3167 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3168 markTextureStagesDirty(This, i);
3174 /* Now work out the mapping */
3176 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3178 if (!(ffu_map & 1)) continue;
3180 if (This->texUnitMap[i] != tex) {
3181 device_map_stage(This, i, tex);
3182 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3183 markTextureStagesDirty(This, i);
3190 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3191 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3192 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3195 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3196 if (sampler_type[i] && This->texUnitMap[i] != i)
3198 device_map_stage(This, i, i);
3199 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3200 if (i < MAX_TEXTURES) {
3201 markTextureStagesDirty(This, i);
3207 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3208 const DWORD *vshader_sampler_tokens, DWORD unit)
3210 DWORD current_mapping = This->rev_tex_unit_map[unit];
3212 /* Not currently used */
3213 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3215 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3216 /* Used by a fragment sampler */
3218 if (!pshader_sampler_tokens) {
3219 /* No pixel shader, check fixed function */
3220 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3223 /* Pixel shader, check the shader's sampler map */
3224 return !pshader_sampler_tokens[current_mapping];
3227 /* Used by a vertex sampler */
3228 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3231 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3232 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3233 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3234 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3235 int start = min(MAX_COMBINED_SAMPLERS, This->adapter->gl_info.limits.combined_samplers) - 1;
3239 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3241 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3242 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3243 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3246 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3247 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3248 if (vshader_sampler_type[i])
3250 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3252 /* Already mapped somewhere */
3256 while (start >= 0) {
3257 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3259 device_map_stage(This, vsampler_idx, start);
3260 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3272 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3273 BOOL vs = use_vs(This->stateBlock);
3274 BOOL ps = use_ps(This->stateBlock);
3277 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3278 * that would be really messy and require shader recompilation
3279 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3280 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3283 device_map_psamplers(This);
3285 device_map_fixed_function_samplers(This);
3289 device_map_vsamplers(This, ps);
3293 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3295 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3296 This->updateStateBlock->pixelShader = pShader;
3297 This->updateStateBlock->changed.pixelShader = TRUE;
3299 /* Handle recording of state blocks */
3300 if (This->isRecordingState) {
3301 TRACE("Recording... not performing anything\n");
3304 if (This->isRecordingState) {
3305 TRACE("Recording... not performing anything\n");
3306 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3307 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3311 if(pShader == oldShader) {
3312 TRACE("App is setting the old pixel shader over, nothing to do\n");
3316 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3317 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3319 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3320 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3325 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3328 if (NULL == ppShader) {
3329 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3330 return WINED3DERR_INVALIDCALL;
3333 *ppShader = This->stateBlock->pixelShader;
3334 if (NULL != *ppShader) {
3335 IWineD3DPixelShader_AddRef(*ppShader);
3337 TRACE("(%p) : returning %p\n", This, *ppShader);
3341 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3342 IWineD3DDevice *iface,
3344 CONST BOOL *srcData,
3347 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3348 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3350 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3351 iface, srcData, start, count);
3353 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3355 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3356 for (i = 0; i < cnt; i++)
3357 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3359 for (i = start; i < cnt + start; ++i) {
3360 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3363 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3368 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3369 IWineD3DDevice *iface,
3374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3375 int cnt = min(count, MAX_CONST_B - start);
3377 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3378 iface, dstData, start, count);
3380 if (dstData == NULL || cnt < 0)
3381 return WINED3DERR_INVALIDCALL;
3383 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3387 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3388 IWineD3DDevice *iface,
3393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3394 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3396 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3397 iface, srcData, start, count);
3399 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3401 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3402 for (i = 0; i < cnt; i++)
3403 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3404 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3406 for (i = start; i < cnt + start; ++i) {
3407 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3410 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3415 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3416 IWineD3DDevice *iface,
3421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3422 int cnt = min(count, MAX_CONST_I - start);
3424 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3425 iface, dstData, start, count);
3427 if (dstData == NULL || cnt < 0)
3428 return WINED3DERR_INVALIDCALL;
3430 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3434 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3435 IWineD3DDevice *iface,
3437 CONST float *srcData,
3440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3443 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3444 iface, srcData, start, count);
3446 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3447 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3448 return WINED3DERR_INVALIDCALL;
3450 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3452 for (i = 0; i < count; i++)
3453 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3454 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3457 if (!This->isRecordingState)
3459 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3460 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3463 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3464 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3469 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3470 IWineD3DDevice *iface,
3475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3476 int cnt = min(count, This->d3d_pshader_constantF - start);
3478 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3479 iface, dstData, start, count);
3481 if (dstData == NULL || cnt < 0)
3482 return WINED3DERR_INVALIDCALL;
3484 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3488 /* Context activation is done by the caller. */
3489 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3490 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3491 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3494 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3495 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3498 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3502 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3504 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3507 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3509 ERR("Source has no position mask\n");
3510 return WINED3DERR_INVALIDCALL;
3513 /* We might access VBOs from this code, so hold the lock */
3516 if (dest->resource.allocatedMemory == NULL) {
3517 buffer_get_sysmem(dest);
3520 /* Get a pointer into the destination vbo(create one if none exists) and
3521 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3523 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3525 dest->flags |= WINED3D_BUFFER_CREATEBO;
3526 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3529 if (dest->buffer_object)
3531 unsigned char extrabytes = 0;
3532 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3533 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3534 * this may write 4 extra bytes beyond the area that should be written
3536 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3537 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3538 if(!dest_conv_addr) {
3539 ERR("Out of memory\n");
3540 /* Continue without storing converted vertices */
3542 dest_conv = dest_conv_addr;
3546 * a) WINED3DRS_CLIPPING is enabled
3547 * b) WINED3DVOP_CLIP is passed
3549 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3550 static BOOL warned = FALSE;
3552 * The clipping code is not quite correct. Some things need
3553 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3554 * so disable clipping for now.
3555 * (The graphics in Half-Life are broken, and my processvertices
3556 * test crashes with IDirect3DDevice3)
3562 FIXME("Clipping is broken and disabled for now\n");
3564 } else doClip = FALSE;
3565 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3567 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3570 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3571 WINED3DTS_PROJECTION,
3573 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3574 WINED3DTS_WORLDMATRIX(0),
3577 TRACE("View mat:\n");
3578 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);
3579 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);
3580 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);
3581 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);
3583 TRACE("Proj mat:\n");
3584 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);
3585 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);
3586 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);
3587 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);
3589 TRACE("World mat:\n");
3590 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);
3591 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);
3592 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);
3593 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);
3595 /* Get the viewport */
3596 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3597 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3598 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3600 multiply_matrix(&mat,&view_mat,&world_mat);
3601 multiply_matrix(&mat,&proj_mat,&mat);
3603 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3605 for (i = 0; i < dwCount; i+= 1) {
3606 unsigned int tex_index;
3608 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3609 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3610 /* The position first */
3611 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3612 const float *p = (const float *)(element->data + i * element->stride);
3614 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3616 /* Multiplication with world, view and projection matrix */
3617 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);
3618 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);
3619 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);
3620 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);
3622 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3624 /* WARNING: The following things are taken from d3d7 and were not yet checked
3625 * against d3d8 or d3d9!
3628 /* Clipping conditions: From msdn
3630 * A vertex is clipped if it does not match the following requirements
3634 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3636 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3637 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3642 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3643 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3646 /* "Normal" viewport transformation (not clipped)
3647 * 1) The values are divided by rhw
3648 * 2) The y axis is negative, so multiply it with -1
3649 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3650 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3651 * 4) Multiply x with Width/2 and add Width/2
3652 * 5) The same for the height
3653 * 6) Add the viewpoint X and Y to the 2D coordinates and
3654 * The minimum Z value to z
3655 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3657 * Well, basically it's simply a linear transformation into viewport
3669 z *= vp.MaxZ - vp.MinZ;
3671 x += vp.Width / 2 + vp.X;
3672 y += vp.Height / 2 + vp.Y;
3677 /* That vertex got clipped
3678 * Contrary to OpenGL it is not dropped completely, it just
3679 * undergoes a different calculation.
3681 TRACE("Vertex got clipped\n");
3688 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3689 * outside of the main vertex buffer memory. That needs some more
3694 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3697 ( (float *) dest_ptr)[0] = x;
3698 ( (float *) dest_ptr)[1] = y;
3699 ( (float *) dest_ptr)[2] = z;
3700 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3702 dest_ptr += 3 * sizeof(float);
3704 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3705 dest_ptr += sizeof(float);
3710 ( (float *) dest_conv)[0] = x * w;
3711 ( (float *) dest_conv)[1] = y * w;
3712 ( (float *) dest_conv)[2] = z * w;
3713 ( (float *) dest_conv)[3] = w;
3715 dest_conv += 3 * sizeof(float);
3717 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3718 dest_conv += sizeof(float);
3722 if (DestFVF & WINED3DFVF_PSIZE) {
3723 dest_ptr += sizeof(DWORD);
3724 if(dest_conv) dest_conv += sizeof(DWORD);
3726 if (DestFVF & WINED3DFVF_NORMAL) {
3727 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3728 const float *normal = (const float *)(element->data + i * element->stride);
3729 /* AFAIK this should go into the lighting information */
3730 FIXME("Didn't expect the destination to have a normal\n");
3731 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3733 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3737 if (DestFVF & WINED3DFVF_DIFFUSE) {
3738 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3739 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3740 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3742 static BOOL warned = FALSE;
3745 ERR("No diffuse color in source, but destination has one\n");
3749 *( (DWORD *) dest_ptr) = 0xffffffff;
3750 dest_ptr += sizeof(DWORD);
3753 *( (DWORD *) dest_conv) = 0xffffffff;
3754 dest_conv += sizeof(DWORD);
3758 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3760 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3761 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3762 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3763 dest_conv += sizeof(DWORD);
3768 if (DestFVF & WINED3DFVF_SPECULAR)
3770 /* What's the color value in the feedback buffer? */
3771 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3772 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3773 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3775 static BOOL warned = FALSE;
3778 ERR("No specular color in source, but destination has one\n");
3782 *( (DWORD *) dest_ptr) = 0xFF000000;
3783 dest_ptr += sizeof(DWORD);
3786 *( (DWORD *) dest_conv) = 0xFF000000;
3787 dest_conv += sizeof(DWORD);
3791 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3793 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3794 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3795 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3796 dest_conv += sizeof(DWORD);
3801 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3802 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3803 const float *tex_coord = (const float *)(element->data + i * element->stride);
3804 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3806 ERR("No source texture, but destination requests one\n");
3807 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3808 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3811 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3813 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3820 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3821 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3822 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3823 dwCount * get_flexible_vertex_size(DestFVF),
3825 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3826 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3833 #undef copy_and_next
3835 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3836 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3840 struct wined3d_stream_info stream_info;
3841 struct wined3d_context *context;
3842 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3845 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3848 ERR("Output vertex declaration not implemented yet\n");
3851 /* Need any context to write to the vbo. */
3852 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
3854 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3855 * control the streamIsUP flag, thus restore it afterwards.
3857 This->stateBlock->streamIsUP = FALSE;
3858 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3859 This->stateBlock->streamIsUP = streamWasUP;
3861 if(vbo || SrcStartIndex) {
3863 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3864 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3866 * Also get the start index in, but only loop over all elements if there's something to add at all.
3868 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3870 struct wined3d_stream_info_element *e;
3872 if (!(stream_info.use_map & (1 << i))) continue;
3874 e = &stream_info.elements[i];
3875 if (e->buffer_object)
3877 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3878 e->buffer_object = 0;
3879 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3881 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3882 vb->buffer_object = 0;
3885 if (e->data) e->data += e->stride * SrcStartIndex;
3889 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3890 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3892 context_release(context);
3898 * Get / Set Texture Stage States
3899 * TODO: Verify against dx9 definitions
3901 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3903 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3905 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3907 if (Stage >= MAX_TEXTURES) {
3908 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
3912 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3913 This->updateStateBlock->textureState[Stage][Type] = Value;
3915 if (This->isRecordingState) {
3916 TRACE("Recording... not performing anything\n");
3920 /* Checked after the assignments to allow proper stateblock recording */
3921 if(oldValue == Value) {
3922 TRACE("App is setting the old value over, nothing to do\n");
3926 if(Stage > This->stateBlock->lowest_disabled_stage &&
3927 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3928 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3929 * Changes in other states are important on disabled stages too
3934 if(Type == WINED3DTSS_COLOROP) {
3937 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3938 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3939 * they have to be disabled
3941 * The current stage is dirtified below.
3943 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3944 TRACE("Additionally dirtifying stage %u\n", i);
3945 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3947 This->stateBlock->lowest_disabled_stage = Stage;
3948 TRACE("New lowest disabled: %u\n", Stage);
3949 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3950 /* Previously disabled stage enabled. Stages above it may need enabling
3951 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3952 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3954 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3957 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
3959 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3962 TRACE("Additionally dirtifying stage %u due to enable\n", i);
3963 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3965 This->stateBlock->lowest_disabled_stage = i;
3966 TRACE("New lowest disabled: %u\n", i);
3970 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3975 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3977 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3978 *pValue = This->updateStateBlock->textureState[Stage][Type];
3985 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
3986 DWORD stage, IWineD3DBaseTexture *texture)
3988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3989 IWineD3DBaseTexture *prev;
3991 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
3993 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
3994 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3996 /* Windows accepts overflowing this array... we do not. */
3997 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
3999 WARN("Ignoring invalid stage %u.\n", stage);
4003 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4004 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4006 WARN("Rejecting attempt to set scratch texture.\n");
4007 return WINED3DERR_INVALIDCALL;
4010 This->updateStateBlock->changed.textures |= 1 << stage;
4012 prev = This->updateStateBlock->textures[stage];
4013 TRACE("Previous texture %p.\n", prev);
4015 if (texture == prev)
4017 TRACE("App is setting the same texture again, nothing to do.\n");
4021 TRACE("Setting new texture to %p.\n", texture);
4022 This->updateStateBlock->textures[stage] = texture;
4024 if (This->isRecordingState)
4026 TRACE("Recording... not performing anything\n");
4028 if (texture) IWineD3DBaseTexture_AddRef(texture);
4029 if (prev) IWineD3DBaseTexture_Release(prev);
4036 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4037 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4038 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4040 IWineD3DBaseTexture_AddRef(texture);
4042 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4044 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4047 if (!prev && stage < MAX_TEXTURES)
4049 /* The source arguments for color and alpha ops have different
4050 * meanings when a NULL texture is bound, so the COLOROP and
4051 * ALPHAOP have to be dirtified. */
4052 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4053 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4056 if (bind_count == 1) t->baseTexture.sampler = stage;
4061 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4062 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4064 IWineD3DBaseTexture_Release(prev);
4066 if (!texture && stage < MAX_TEXTURES)
4068 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4069 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4072 if (bind_count && t->baseTexture.sampler == stage)
4076 /* Search for other stages the texture is bound to. Shouldn't
4077 * happen if applications bind textures to a single stage only. */
4078 TRACE("Searching for other stages the texture is bound to.\n");
4079 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4081 if (This->updateStateBlock->textures[i] == prev)
4083 TRACE("Texture is also bound to stage %u.\n", i);
4084 t->baseTexture.sampler = i;
4091 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4096 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4099 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4101 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4102 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4105 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4106 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4107 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4110 *ppTexture=This->stateBlock->textures[Stage];
4112 IWineD3DBaseTexture_AddRef(*ppTexture);
4114 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4122 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4123 IWineD3DSurface **ppBackBuffer) {
4124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4125 IWineD3DSwapChain *swapChain;
4128 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4130 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4131 if (hr == WINED3D_OK) {
4132 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4133 IWineD3DSwapChain_Release(swapChain);
4135 *ppBackBuffer = NULL;
4140 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4142 WARN("(%p) : stub, calling idirect3d for now\n", This);
4143 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4146 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4148 IWineD3DSwapChain *swapChain;
4151 if(iSwapChain > 0) {
4152 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4153 if (hr == WINED3D_OK) {
4154 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4155 IWineD3DSwapChain_Release(swapChain);
4157 FIXME("(%p) Error getting display mode\n", This);
4160 /* Don't read the real display mode,
4161 but return the stored mode instead. X11 can't change the color
4162 depth, and some apps are pretty angry if they SetDisplayMode from
4163 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4165 Also don't relay to the swapchain because with ddraw it's possible
4166 that there isn't a swapchain at all */
4167 pMode->Width = This->ddraw_width;
4168 pMode->Height = This->ddraw_height;
4169 pMode->Format = This->ddraw_format;
4170 pMode->RefreshRate = 0;
4178 * Stateblock related functions
4181 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4183 IWineD3DStateBlock *stateblock;
4186 TRACE("(%p)\n", This);
4188 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4190 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4191 if (FAILED(hr)) return hr;
4193 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4194 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4195 This->isRecordingState = TRUE;
4197 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4202 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4204 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4206 if (!This->isRecordingState) {
4207 WARN("(%p) not recording! returning error\n", This);
4208 *ppStateBlock = NULL;
4209 return WINED3DERR_INVALIDCALL;
4212 stateblock_init_contained_states(object);
4214 *ppStateBlock = (IWineD3DStateBlock*) object;
4215 This->isRecordingState = FALSE;
4216 This->updateStateBlock = This->stateBlock;
4217 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4218 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4219 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4224 * Scene related functions
4226 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4227 /* At the moment we have no need for any functionality at the beginning
4229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4230 TRACE("(%p)\n", This);
4233 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4234 return WINED3DERR_INVALIDCALL;
4236 This->inScene = TRUE;
4240 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4243 struct wined3d_context *context;
4245 TRACE("(%p)\n", This);
4247 if(!This->inScene) {
4248 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4249 return WINED3DERR_INVALIDCALL;
4252 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4253 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4255 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4257 context_release(context);
4259 This->inScene = FALSE;
4263 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4264 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4265 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4267 IWineD3DSwapChain *swapChain = NULL;
4269 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4271 TRACE("(%p) Presenting the frame\n", This);
4273 for(i = 0 ; i < swapchains ; i ++) {
4275 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4276 TRACE("presentinng chain %d, %p\n", i, swapChain);
4277 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4278 IWineD3DSwapChain_Release(swapChain);
4284 /* Not called from the VTable (internal subroutine) */
4285 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4286 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4287 float Z, DWORD Stencil) {
4288 GLbitfield glMask = 0;
4290 WINED3DRECT curRect;
4292 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4293 UINT drawable_width, drawable_height;
4294 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4295 IWineD3DSwapChainImpl *swapchain = NULL;
4296 struct wined3d_context *context;
4298 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4299 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4300 * for the cleared parts, and the untouched parts.
4302 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4303 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4304 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4305 * checking all this if the dest surface is in the drawable anyway.
4307 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4309 if(vp->X != 0 || vp->Y != 0 ||
4310 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4311 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4314 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4315 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4316 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4317 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4318 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4321 if(Count > 0 && pRects && (
4322 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4323 pRects[0].x2 < target->currentDesc.Width ||
4324 pRects[0].y2 < target->currentDesc.Height)) {
4325 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4332 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4334 target->get_drawable_size(context, &drawable_width, &drawable_height);
4338 /* Only set the values up once, as they are not changing */
4339 if (Flags & WINED3DCLEAR_STENCIL) {
4340 glClearStencil(Stencil);
4341 checkGLcall("glClearStencil");
4342 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4343 glStencilMask(0xFFFFFFFF);
4346 if (Flags & WINED3DCLEAR_ZBUFFER) {
4347 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4348 glDepthMask(GL_TRUE);
4350 checkGLcall("glClearDepth");
4351 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4352 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4354 if (vp->X != 0 || vp->Y != 0 ||
4355 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4356 surface_load_ds_location(This->stencilBufferTarget, context, location);
4358 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4359 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4360 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4361 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4362 surface_load_ds_location(This->stencilBufferTarget, context, location);
4364 else if (Count > 0 && pRects && (
4365 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4366 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4367 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4368 surface_load_ds_location(This->stencilBufferTarget, context, location);
4372 if (Flags & WINED3DCLEAR_TARGET) {
4373 TRACE("Clearing screen with glClear to color %x\n", Color);
4374 glClearColor(D3DCOLOR_R(Color),
4378 checkGLcall("glClearColor");
4380 /* Clear ALL colors! */
4381 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4382 glMask = glMask | GL_COLOR_BUFFER_BIT;
4385 vp_rect.left = vp->X;
4386 vp_rect.top = vp->Y;
4387 vp_rect.right = vp->X + vp->Width;
4388 vp_rect.bottom = vp->Y + vp->Height;
4389 if (!(Count > 0 && pRects)) {
4390 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4391 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4393 if (context->render_offscreen)
4395 glScissor(vp_rect.left, vp_rect.top,
4396 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4398 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4399 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4401 checkGLcall("glScissor");
4403 checkGLcall("glClear");
4405 /* Now process each rect in turn */
4406 for (i = 0; i < Count; i++) {
4407 /* Note gl uses lower left, width/height */
4408 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4409 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4410 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4412 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4413 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4414 curRect.x1, (target->currentDesc.Height - curRect.y2),
4415 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4417 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4418 * The rectangle is not cleared, no error is returned, but further rectanlges are
4419 * still cleared if they are valid
4421 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4422 TRACE("Rectangle with negative dimensions, ignoring\n");
4426 if (context->render_offscreen)
4428 glScissor(curRect.x1, curRect.y1,
4429 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4431 glScissor(curRect.x1, drawable_height - curRect.y2,
4432 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4434 checkGLcall("glScissor");
4437 checkGLcall("glClear");
4441 /* Restore the old values (why..?) */
4442 if (Flags & WINED3DCLEAR_STENCIL) {
4443 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4445 if (Flags & WINED3DCLEAR_TARGET) {
4446 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4447 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4448 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4449 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4450 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4452 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4453 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4455 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4457 if (Flags & WINED3DCLEAR_ZBUFFER) {
4458 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4459 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4460 surface_modify_ds_location(This->stencilBufferTarget, location);
4465 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
4466 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
4469 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
4472 context_release(context);
4477 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4478 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4480 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4482 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4483 Count, pRects, Flags, Color, Z, Stencil);
4485 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4486 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4487 /* TODO: What about depth stencil buffers without stencil bits? */
4488 return WINED3DERR_INVALIDCALL;
4491 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4498 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4499 WINED3DPRIMITIVETYPE primitive_type)
4501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4503 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4505 This->updateStateBlock->changed.primitive_type = TRUE;
4506 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4509 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4510 WINED3DPRIMITIVETYPE *primitive_type)
4512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4514 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4516 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4518 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4521 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4525 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4527 if(!This->stateBlock->vertexDecl) {
4528 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4529 return WINED3DERR_INVALIDCALL;
4532 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4533 if(This->stateBlock->streamIsUP) {
4534 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4535 This->stateBlock->streamIsUP = FALSE;
4538 if(This->stateBlock->loadBaseVertexIndex != 0) {
4539 This->stateBlock->loadBaseVertexIndex = 0;
4540 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4542 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4543 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4547 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4551 IWineD3DBuffer *pIB;
4554 pIB = This->stateBlock->pIndexData;
4556 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4557 * without an index buffer set. (The first time at least...)
4558 * D3D8 simply dies, but I doubt it can do much harm to return
4559 * D3DERR_INVALIDCALL there as well. */
4560 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4561 return WINED3DERR_INVALIDCALL;
4564 if(!This->stateBlock->vertexDecl) {
4565 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4566 return WINED3DERR_INVALIDCALL;
4569 if(This->stateBlock->streamIsUP) {
4570 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4571 This->stateBlock->streamIsUP = FALSE;
4573 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4575 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4577 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4583 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4584 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4585 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4588 drawPrimitive(iface, index_count, startIndex, idxStride,
4589 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4594 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4595 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4600 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4601 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4603 if(!This->stateBlock->vertexDecl) {
4604 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4605 return WINED3DERR_INVALIDCALL;
4608 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4609 vb = This->stateBlock->streamSource[0];
4610 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4611 if (vb) IWineD3DBuffer_Release(vb);
4612 This->stateBlock->streamOffset[0] = 0;
4613 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4614 This->stateBlock->streamIsUP = TRUE;
4615 This->stateBlock->loadBaseVertexIndex = 0;
4617 /* TODO: Only mark dirty if drawing from a different UP address */
4618 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4620 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4622 /* MSDN specifies stream zero settings must be set to NULL */
4623 This->stateBlock->streamStride[0] = 0;
4624 This->stateBlock->streamSource[0] = NULL;
4626 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4627 * the new stream sources or use UP drawing again
4632 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4633 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4634 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4641 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4642 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4644 if(!This->stateBlock->vertexDecl) {
4645 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4646 return WINED3DERR_INVALIDCALL;
4649 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4655 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4656 vb = This->stateBlock->streamSource[0];
4657 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4658 if (vb) IWineD3DBuffer_Release(vb);
4659 This->stateBlock->streamIsUP = TRUE;
4660 This->stateBlock->streamOffset[0] = 0;
4661 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4663 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4664 This->stateBlock->baseVertexIndex = 0;
4665 This->stateBlock->loadBaseVertexIndex = 0;
4666 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4667 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4668 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4670 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4672 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4673 This->stateBlock->streamSource[0] = NULL;
4674 This->stateBlock->streamStride[0] = 0;
4675 ib = This->stateBlock->pIndexData;
4677 IWineD3DBuffer_Release(ib);
4678 This->stateBlock->pIndexData = NULL;
4680 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4681 * SetStreamSource to specify a vertex buffer
4687 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4688 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4692 /* Mark the state dirty until we have nicer tracking
4693 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4696 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4697 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4698 This->stateBlock->baseVertexIndex = 0;
4699 This->up_strided = DrawPrimStrideData;
4700 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4701 This->up_strided = NULL;
4705 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4706 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4707 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4710 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4712 /* Mark the state dirty until we have nicer tracking
4713 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4716 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4718 This->stateBlock->streamIsUP = TRUE;
4719 This->stateBlock->baseVertexIndex = 0;
4720 This->up_strided = DrawPrimStrideData;
4721 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4722 This->up_strided = NULL;
4726 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
4727 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
4728 * not callable by the app directly no parameter validation checks are needed here.
4730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4731 WINED3DLOCKED_BOX src;
4732 WINED3DLOCKED_BOX dst;
4734 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
4736 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4737 * dirtification to improve loading performance.
4739 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4740 if(FAILED(hr)) return hr;
4741 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4743 IWineD3DVolume_UnlockBox(pSourceVolume);
4747 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4749 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4751 IWineD3DVolume_UnlockBox(pSourceVolume);
4753 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4758 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4759 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4761 unsigned int level_count, i;
4762 WINED3DRESOURCETYPE type;
4765 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4767 /* Verify that the source and destination textures are non-NULL. */
4768 if (!src_texture || !dst_texture)
4770 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4771 return WINED3DERR_INVALIDCALL;
4774 if (src_texture == dst_texture)
4776 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4777 return WINED3DERR_INVALIDCALL;
4780 /* Verify that the source and destination textures are the same type. */
4781 type = IWineD3DBaseTexture_GetType(src_texture);
4782 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4784 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4785 return WINED3DERR_INVALIDCALL;
4788 /* Check that both textures have the identical numbers of levels. */
4789 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4790 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4792 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4793 return WINED3DERR_INVALIDCALL;
4796 /* Make sure that the destination texture is loaded. */
4797 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4799 /* Update every surface level of the texture. */
4802 case WINED3DRTYPE_TEXTURE:
4804 IWineD3DSurface *src_surface;
4805 IWineD3DSurface *dst_surface;
4807 for (i = 0; i < level_count; ++i)
4809 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4810 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4811 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4812 IWineD3DSurface_Release(dst_surface);
4813 IWineD3DSurface_Release(src_surface);
4816 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4823 case WINED3DRTYPE_CUBETEXTURE:
4825 IWineD3DSurface *src_surface;
4826 IWineD3DSurface *dst_surface;
4827 WINED3DCUBEMAP_FACES face;
4829 for (i = 0; i < level_count; ++i)
4831 /* Update each cube face. */
4832 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4834 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4835 face, i, &src_surface);
4836 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4837 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4838 face, i, &dst_surface);
4839 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4840 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4841 IWineD3DSurface_Release(dst_surface);
4842 IWineD3DSurface_Release(src_surface);
4845 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4853 case WINED3DRTYPE_VOLUMETEXTURE:
4855 IWineD3DVolume *src_volume;
4856 IWineD3DVolume *dst_volume;
4858 for (i = 0; i < level_count; ++i)
4860 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4861 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4862 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4863 IWineD3DVolume_Release(dst_volume);
4864 IWineD3DVolume_Release(src_volume);
4867 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4875 FIXME("Unsupported texture type %#x.\n", type);
4876 return WINED3DERR_INVALIDCALL;
4882 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4883 IWineD3DSwapChain *swapChain;
4885 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4886 if(hr == WINED3D_OK) {
4887 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4888 IWineD3DSwapChain_Release(swapChain);
4893 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4895 IWineD3DBaseTextureImpl *texture;
4898 TRACE("(%p) : %p\n", This, pNumPasses);
4900 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4901 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
4902 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4903 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4905 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
4906 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4907 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4910 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
4911 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
4913 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
4914 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4917 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
4918 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4921 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
4922 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
4923 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4928 /* return a sensible default */
4931 TRACE("returning D3D_OK\n");
4935 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
4939 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4941 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
4942 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
4943 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
4945 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
4950 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4954 PALETTEENTRY **palettes;
4956 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4958 if (PaletteNumber >= MAX_PALETTES) {
4959 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4960 return WINED3DERR_INVALIDCALL;
4963 if (PaletteNumber >= This->NumberOfPalettes) {
4964 NewSize = This->NumberOfPalettes;
4967 } while(PaletteNumber >= NewSize);
4968 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
4970 ERR("Out of memory!\n");
4971 return E_OUTOFMEMORY;
4973 This->palettes = palettes;
4974 This->NumberOfPalettes = NewSize;
4977 if (!This->palettes[PaletteNumber]) {
4978 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
4979 if (!This->palettes[PaletteNumber]) {
4980 ERR("Out of memory!\n");
4981 return E_OUTOFMEMORY;
4985 for (j = 0; j < 256; ++j) {
4986 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4987 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4988 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4989 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4991 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
4992 TRACE("(%p) : returning\n", This);
4996 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4999 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5000 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5001 /* What happens in such situation isn't documented; Native seems to silently abort
5002 on such conditions. Return Invalid Call. */
5003 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5004 return WINED3DERR_INVALIDCALL;
5006 for (j = 0; j < 256; ++j) {
5007 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5008 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5009 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5010 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5012 TRACE("(%p) : returning\n", This);
5016 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5018 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5019 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5020 (tested with reference rasterizer). Return Invalid Call. */
5021 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5022 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5023 return WINED3DERR_INVALIDCALL;
5025 /*TODO: stateblocks */
5026 if (This->currentPalette != PaletteNumber) {
5027 This->currentPalette = PaletteNumber;
5028 dirtify_p8_texture_samplers(This);
5030 TRACE("(%p) : returning\n", This);
5034 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5036 if (PaletteNumber == NULL) {
5037 WARN("(%p) : returning Invalid Call\n", This);
5038 return WINED3DERR_INVALIDCALL;
5040 /*TODO: stateblocks */
5041 *PaletteNumber = This->currentPalette;
5042 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5046 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5051 FIXME("(%p) : stub\n", This);
5055 This->softwareVertexProcessing = bSoftware;
5060 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5065 FIXME("(%p) : stub\n", This);
5068 return This->softwareVertexProcessing;
5072 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5073 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5074 IWineD3DSwapChain *swapChain;
5077 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5079 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5080 if(hr == WINED3D_OK){
5081 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5082 IWineD3DSwapChain_Release(swapChain);
5084 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5090 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5093 if(nSegments != 0.0f) {
5096 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5103 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5108 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5114 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5116 /** TODO: remove casts to IWineD3DSurfaceImpl
5117 * NOTE: move code to surface to accomplish this
5118 ****************************************/
5119 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5120 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5121 int srcWidth, srcHeight;
5122 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5123 WINED3DFORMAT destFormat, srcFormat;
5125 int srcLeft, destLeft, destTop;
5126 WINED3DPOOL srcPool, destPool;
5128 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5129 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5133 CONVERT_TYPES convert = NO_CONVERSION;
5134 struct wined3d_context *context;
5136 WINED3DSURFACE_DESC winedesc;
5138 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5140 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5141 srcSurfaceWidth = winedesc.width;
5142 srcSurfaceHeight = winedesc.height;
5143 srcPool = winedesc.pool;
5144 srcFormat = winedesc.format;
5146 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5147 destSurfaceWidth = winedesc.width;
5148 destSurfaceHeight = winedesc.height;
5149 destPool = winedesc.pool;
5150 destFormat = winedesc.format;
5151 destSize = winedesc.size;
5153 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5154 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5155 return WINED3DERR_INVALIDCALL;
5158 /* This call loads the opengl surface directly, instead of copying the surface to the
5159 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5160 * copy in sysmem and use regular surface loading.
5162 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5163 if(convert != NO_CONVERSION) {
5164 return IWineD3DSurface_BltFast(pDestinationSurface,
5165 pDestPoint ? pDestPoint->x : 0,
5166 pDestPoint ? pDestPoint->y : 0,
5167 pSourceSurface, pSourceRect, 0);
5170 if (destFormat == WINED3DFMT_UNKNOWN) {
5171 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5172 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5174 /* Get the update surface description */
5175 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5178 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5181 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5182 checkGLcall("glActiveTextureARB");
5185 /* Make sure the surface is loaded and up to date */
5186 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5187 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5189 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5190 dst_format_desc = dst_impl->resource.format_desc;
5192 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5193 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5194 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5195 srcLeft = pSourceRect ? pSourceRect->left : 0;
5196 destLeft = pDestPoint ? pDestPoint->x : 0;
5197 destTop = pDestPoint ? pDestPoint->y : 0;
5200 /* This function doesn't support compressed textures
5201 the pitch is just bytesPerPixel * width */
5202 if(srcWidth != srcSurfaceWidth || srcLeft ){
5203 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5204 offset += srcLeft * src_format_desc->byte_count;
5205 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5207 /* TODO DXT formats */
5209 if(pSourceRect != NULL && pSourceRect->top != 0){
5210 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5212 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5213 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5214 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5217 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5219 /* need to lock the surface to get the data */
5220 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5225 /* TODO: Cube and volume support */
5227 /* not a whole row so we have to do it a line at a time */
5230 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5231 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5233 for (j = destTop; j < (srcHeight + destTop); ++j)
5235 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5236 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5240 } else { /* Full width, so just write out the whole texture */
5241 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5243 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5245 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5247 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5248 FIXME("Updating part of a compressed texture is not supported.\n");
5250 if (destFormat != srcFormat)
5252 FIXME("Updating mixed format compressed textures is not supported.\n");
5256 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5257 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5262 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5263 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5266 checkGLcall("glTexSubImage2D");
5269 context_release(context);
5271 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5272 sampler = This->rev_tex_unit_map[0];
5273 if (sampler != WINED3D_UNMAPPED_STAGE)
5275 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5281 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5283 struct WineD3DRectPatch *patch;
5284 GLenum old_primitive_type;
5288 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5290 if(!(Handle || pRectPatchInfo)) {
5291 /* TODO: Write a test for the return value, thus the FIXME */
5292 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5293 return WINED3DERR_INVALIDCALL;
5297 i = PATCHMAP_HASHFUNC(Handle);
5299 LIST_FOR_EACH(e, &This->patches[i]) {
5300 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5301 if(patch->Handle == Handle) {
5308 TRACE("Patch does not exist. Creating a new one\n");
5309 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5310 patch->Handle = Handle;
5311 list_add_head(&This->patches[i], &patch->entry);
5313 TRACE("Found existing patch %p\n", patch);
5316 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5317 * attributes we have to tesselate, read back, and draw. This needs a patch
5318 * management structure instance. Create one.
5320 * A possible improvement is to check if a vertex shader is used, and if not directly
5323 FIXME("Drawing an uncached patch. This is slow\n");
5324 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5327 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5328 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5329 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5331 TRACE("Tesselation density or patch info changed, retesselating\n");
5333 if(pRectPatchInfo) {
5334 patch->RectPatchInfo = *pRectPatchInfo;
5336 patch->numSegs[0] = pNumSegs[0];
5337 patch->numSegs[1] = pNumSegs[1];
5338 patch->numSegs[2] = pNumSegs[2];
5339 patch->numSegs[3] = pNumSegs[3];
5341 hr = tesselate_rectpatch(This, patch);
5343 WARN("Patch tesselation failed\n");
5345 /* Do not release the handle to store the params of the patch */
5347 HeapFree(GetProcessHeap(), 0, patch);
5353 This->currentPatch = patch;
5354 old_primitive_type = This->stateBlock->gl_primitive_type;
5355 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5356 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5357 This->stateBlock->gl_primitive_type = old_primitive_type;
5358 This->currentPatch = NULL;
5360 /* Destroy uncached patches */
5362 HeapFree(GetProcessHeap(), 0, patch->mem);
5363 HeapFree(GetProcessHeap(), 0, patch);
5368 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5370 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5371 FIXME("(%p) : Stub\n", This);
5375 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5378 struct WineD3DRectPatch *patch;
5380 TRACE("(%p) Handle(%d)\n", This, Handle);
5382 i = PATCHMAP_HASHFUNC(Handle);
5383 LIST_FOR_EACH(e, &This->patches[i]) {
5384 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5385 if(patch->Handle == Handle) {
5386 TRACE("Deleting patch %p\n", patch);
5387 list_remove(&patch->entry);
5388 HeapFree(GetProcessHeap(), 0, patch->mem);
5389 HeapFree(GetProcessHeap(), 0, patch);
5394 /* TODO: Write a test for the return value */
5395 FIXME("Attempt to destroy nonexistent patch\n");
5396 return WINED3DERR_INVALIDCALL;
5399 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5401 IWineD3DSwapChain *swapchain;
5403 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5404 if (SUCCEEDED(hr)) {
5405 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5412 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5413 const WINED3DRECT *rect, const float color[4])
5415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5416 struct wined3d_context *context;
5417 IWineD3DSwapChain *swapchain;
5419 swapchain = get_swapchain(surface);
5420 if (!surface_is_offscreen(surface))
5422 TRACE("Surface %p is onscreen\n", surface);
5424 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5426 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5427 context_set_draw_buffer(context, surface_get_gl_buffer(surface, swapchain));
5431 TRACE("Surface %p is offscreen\n", surface);
5433 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5435 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5436 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5437 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5441 glEnable(GL_SCISSOR_TEST);
5442 if(surface_is_offscreen(surface)) {
5443 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5445 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5446 rect->x2 - rect->x1, rect->y2 - rect->y1);
5448 checkGLcall("glScissor");
5449 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5451 glDisable(GL_SCISSOR_TEST);
5453 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5455 glDisable(GL_BLEND);
5456 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5458 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5459 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5461 glClearColor(color[0], color[1], color[2], color[3]);
5462 glClear(GL_COLOR_BUFFER_BIT);
5463 checkGLcall("glClear");
5466 context_release(context);
5469 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5470 unsigned int r, g, b, a;
5473 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5474 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5475 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5478 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5480 a = (color & 0xff000000) >> 24;
5481 r = (color & 0x00ff0000) >> 16;
5482 g = (color & 0x0000ff00) >> 8;
5483 b = (color & 0x000000ff) >> 0;
5487 case WINED3DFMT_B5G6R5_UNORM:
5488 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5495 TRACE("Returning %08x\n", ret);
5498 case WINED3DFMT_B5G5R5X1_UNORM:
5499 case WINED3DFMT_B5G5R5A1_UNORM:
5508 TRACE("Returning %08x\n", ret);
5511 case WINED3DFMT_A8_UNORM:
5512 TRACE("Returning %08x\n", a);
5515 case WINED3DFMT_B4G4R4X4_UNORM:
5516 case WINED3DFMT_B4G4R4A4_UNORM:
5525 TRACE("Returning %08x\n", ret);
5528 case WINED3DFMT_B2G3R3_UNORM:
5535 TRACE("Returning %08x\n", ret);
5538 case WINED3DFMT_R8G8B8X8_UNORM:
5539 case WINED3DFMT_R8G8B8A8_UNORM:
5544 TRACE("Returning %08x\n", ret);
5547 case WINED3DFMT_B10G10R10A2_UNORM:
5549 r = (r * 1024) / 256;
5550 g = (g * 1024) / 256;
5551 b = (b * 1024) / 256;
5556 TRACE("Returning %08x\n", ret);
5559 case WINED3DFMT_R10G10B10A2_UNORM:
5561 r = (r * 1024) / 256;
5562 g = (g * 1024) / 256;
5563 b = (b * 1024) / 256;
5568 TRACE("Returning %08x\n", ret);
5572 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5577 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5579 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5581 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5583 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5584 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5585 return WINED3DERR_INVALIDCALL;
5588 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5589 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5590 color_fill_fbo(iface, pSurface, pRect, c);
5593 /* Just forward this to the DirectDraw blitting engine */
5594 memset(&BltFx, 0, sizeof(BltFx));
5595 BltFx.dwSize = sizeof(BltFx);
5596 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5597 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5598 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5602 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5603 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5605 IWineD3DResource *resource;
5606 IWineD3DSurface *surface;
5609 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5612 ERR("Failed to get resource, hr %#x\n", hr);
5616 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5618 FIXME("Only supported on surface resources\n");
5619 IWineD3DResource_Release(resource);
5623 surface = (IWineD3DSurface *)resource;
5625 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5627 color_fill_fbo(iface, surface, NULL, color);
5634 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5636 c = ((DWORD)(color[2] * 255.0f));
5637 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5638 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5639 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5641 /* Just forward this to the DirectDraw blitting engine */
5642 memset(&BltFx, 0, sizeof(BltFx));
5643 BltFx.dwSize = sizeof(BltFx);
5644 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5645 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5648 ERR("Blt failed, hr %#x\n", hr);
5652 IWineD3DResource_Release(resource);
5655 /* rendertarget and depth stencil functions */
5656 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5659 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5661 ERR("(%p) : Only %d render targets are supported.\n",
5662 This, This->adapter->gl_info.limits.buffers);
5663 return WINED3DERR_INVALIDCALL;
5666 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5667 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5668 /* Note inc ref on returned surface */
5669 if(*ppRenderTarget != NULL)
5670 IWineD3DSurface_AddRef(*ppRenderTarget);
5674 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5676 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5677 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5678 IWineD3DSwapChainImpl *Swapchain;
5681 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5683 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5684 if(hr != WINED3D_OK) {
5685 ERR("Can't get the swapchain\n");
5689 /* Make sure to release the swapchain */
5690 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5692 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5693 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5694 return WINED3DERR_INVALIDCALL;
5696 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5697 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5698 return WINED3DERR_INVALIDCALL;
5701 if(Swapchain->frontBuffer != Front) {
5702 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5704 if(Swapchain->frontBuffer)
5706 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5707 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5709 Swapchain->frontBuffer = Front;
5711 if(Swapchain->frontBuffer) {
5712 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5713 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5717 if(Back && !Swapchain->backBuffer) {
5718 /* We need memory for the back buffer array - only one back buffer this way */
5719 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5720 if(!Swapchain->backBuffer) {
5721 ERR("Out of memory\n");
5722 return E_OUTOFMEMORY;
5726 if(Swapchain->backBuffer[0] != Back) {
5727 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5729 /* What to do about the context here in the case of multithreading? Not sure.
5730 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5732 WARN("No active context?\n");
5735 if(!Swapchain->backBuffer[0]) {
5736 /* GL was told to draw to the front buffer at creation,
5739 glDrawBuffer(GL_BACK);
5740 checkGLcall("glDrawBuffer(GL_BACK)");
5741 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5742 Swapchain->presentParms.BackBufferCount = 1;
5744 /* That makes problems - disable for now */
5745 /* glDrawBuffer(GL_FRONT); */
5746 checkGLcall("glDrawBuffer(GL_FRONT)");
5747 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5748 Swapchain->presentParms.BackBufferCount = 0;
5752 if(Swapchain->backBuffer[0])
5754 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5755 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5757 Swapchain->backBuffer[0] = Back;
5759 if(Swapchain->backBuffer[0]) {
5760 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5761 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
5763 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5764 Swapchain->backBuffer = NULL;
5772 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5774 *ppZStencilSurface = This->stencilBufferTarget;
5775 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5777 if(*ppZStencilSurface != NULL) {
5778 /* Note inc ref on returned surface */
5779 IWineD3DSurface_AddRef(*ppZStencilSurface);
5782 return WINED3DERR_NOTFOUND;
5786 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5787 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
5789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5790 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5791 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5792 const struct wined3d_gl_info *gl_info;
5793 struct wined3d_context *context;
5795 POINT offset = {0, 0};
5797 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5798 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5799 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5800 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5803 case WINED3DTEXF_LINEAR:
5804 gl_filter = GL_LINEAR;
5808 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5809 case WINED3DTEXF_NONE:
5810 case WINED3DTEXF_POINT:
5811 gl_filter = GL_NEAREST;
5815 /* Attach src surface to src fbo */
5816 src_swapchain = get_swapchain(src_surface);
5817 dst_swapchain = get_swapchain(dst_surface);
5819 if (src_swapchain) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
5820 else if (dst_swapchain) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5821 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5823 gl_info = context->gl_info;
5825 if (!surface_is_offscreen(src_surface)) {
5826 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5828 TRACE("Source surface %p is onscreen\n", src_surface);
5829 /* Make sure the drawable is up to date. In the offscreen case
5830 * attach_surface_fbo() implicitly takes care of this. */
5831 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
5833 if(buffer == GL_FRONT) {
5836 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
5837 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
5838 h = windowsize.bottom - windowsize.top;
5839 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
5840 src_rect->y1 = offset.y + h - src_rect->y1;
5841 src_rect->y2 = offset.y + h - src_rect->y2;
5843 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5844 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5848 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5849 glReadBuffer(buffer);
5850 checkGLcall("glReadBuffer()");
5852 TRACE("Source surface %p is offscreen\n", src_surface);
5854 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5855 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
5856 glReadBuffer(GL_COLOR_ATTACHMENT0);
5857 checkGLcall("glReadBuffer()");
5858 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5862 /* Attach dst surface to dst fbo */
5863 if (!surface_is_offscreen(dst_surface)) {
5864 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5866 TRACE("Destination surface %p is onscreen\n", dst_surface);
5867 /* Make sure the drawable is up to date. In the offscreen case
5868 * attach_surface_fbo() implicitly takes care of this. */
5869 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
5871 if(buffer == GL_FRONT) {
5874 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
5875 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
5876 h = windowsize.bottom - windowsize.top;
5877 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
5878 dst_rect->y1 = offset.y + h - dst_rect->y1;
5879 dst_rect->y2 = offset.y + h - dst_rect->y2;
5881 /* Screen coords = window coords, surface height = window height */
5882 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5883 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5887 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5888 glDrawBuffer(buffer);
5889 checkGLcall("glDrawBuffer()");
5891 TRACE("Destination surface %p is offscreen\n", dst_surface);
5894 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5895 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
5896 glDrawBuffer(GL_COLOR_ATTACHMENT0);
5897 checkGLcall("glDrawBuffer()");
5898 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5900 glDisable(GL_SCISSOR_TEST);
5901 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5904 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5905 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
5906 checkGLcall("glBlitFramebuffer()");
5908 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5909 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
5910 checkGLcall("glBlitFramebuffer()");
5913 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
5915 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5916 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5917 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5918 glDrawBuffer(GL_BACK);
5919 checkGLcall("glDrawBuffer()");
5923 context_release(context);
5926 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5927 BOOL set_viewport) {
5928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5930 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5932 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5934 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5935 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5936 return WINED3DERR_INVALIDCALL;
5939 /* MSDN says that null disables the render target
5940 but a device must always be associated with a render target
5941 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5943 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5944 FIXME("Trying to set render target 0 to NULL\n");
5945 return WINED3DERR_INVALIDCALL;
5947 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5948 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);
5949 return WINED3DERR_INVALIDCALL;
5952 /* If we are trying to set what we already have, don't bother */
5953 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5954 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5957 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5958 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5959 This->render_targets[RenderTargetIndex] = pRenderTarget;
5961 /* Render target 0 is special */
5962 if(RenderTargetIndex == 0 && set_viewport) {
5963 /* Finally, reset the viewport and scissor rect as the MSDN states.
5964 * Tests show that stateblock recording is ignored, the change goes
5965 * directly into the primary stateblock.
5967 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5968 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5969 This->stateBlock->viewport.X = 0;
5970 This->stateBlock->viewport.Y = 0;
5971 This->stateBlock->viewport.MaxZ = 1.0f;
5972 This->stateBlock->viewport.MinZ = 0.0f;
5973 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5975 This->stateBlock->scissorRect.top = 0;
5976 This->stateBlock->scissorRect.left = 0;
5977 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5978 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5979 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5984 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5986 HRESULT hr = WINED3D_OK;
5987 IWineD3DSurface *tmp;
5989 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
5991 if (pNewZStencil == This->stencilBufferTarget) {
5992 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5994 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
5995 * depending on the renter target implementation being used.
5996 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5997 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5998 * stencil buffer and incur an extra memory overhead
5999 ******************************************************/
6001 if (This->stencilBufferTarget) {
6002 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6003 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6004 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6006 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6007 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
6008 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6009 context_release(context);
6013 tmp = This->stencilBufferTarget;
6014 This->stencilBufferTarget = pNewZStencil;
6015 /* should we be calling the parent or the wined3d surface? */
6016 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6017 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6020 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6021 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6022 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6023 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6024 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6031 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6032 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6034 /* TODO: the use of Impl is deprecated. */
6035 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6036 WINED3DLOCKED_RECT lockedRect;
6038 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6040 /* some basic validation checks */
6041 if(This->cursorTexture) {
6042 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6044 glDeleteTextures(1, &This->cursorTexture);
6046 context_release(context);
6047 This->cursorTexture = 0;
6050 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6051 This->haveHardwareCursor = TRUE;
6053 This->haveHardwareCursor = FALSE;
6056 WINED3DLOCKED_RECT rect;
6058 /* MSDN: Cursor must be A8R8G8B8 */
6059 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6061 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6062 return WINED3DERR_INVALIDCALL;
6065 /* MSDN: Cursor must be smaller than the display mode */
6066 if(pSur->currentDesc.Width > This->ddraw_width ||
6067 pSur->currentDesc.Height > This->ddraw_height) {
6068 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);
6069 return WINED3DERR_INVALIDCALL;
6072 if (!This->haveHardwareCursor) {
6073 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6075 /* Do not store the surface's pointer because the application may
6076 * release it after setting the cursor image. Windows doesn't
6077 * addref the set surface, so we can't do this either without
6078 * creating circular refcount dependencies. Copy out the gl texture
6081 This->cursorWidth = pSur->currentDesc.Width;
6082 This->cursorHeight = pSur->currentDesc.Height;
6083 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6085 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6086 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6087 struct wined3d_context *context;
6088 char *mem, *bits = rect.pBits;
6089 GLint intfmt = glDesc->glInternal;
6090 GLint format = glDesc->glFormat;
6091 GLint type = glDesc->glType;
6092 INT height = This->cursorHeight;
6093 INT width = This->cursorWidth;
6094 INT bpp = glDesc->byte_count;
6098 /* Reformat the texture memory (pitch and width can be
6100 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6101 for(i = 0; i < height; i++)
6102 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6103 IWineD3DSurface_UnlockRect(pCursorBitmap);
6105 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6109 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6111 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6112 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6115 /* Make sure that a proper texture unit is selected */
6116 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6117 checkGLcall("glActiveTextureARB");
6118 sampler = This->rev_tex_unit_map[0];
6119 if (sampler != WINED3D_UNMAPPED_STAGE)
6121 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6123 /* Create a new cursor texture */
6124 glGenTextures(1, &This->cursorTexture);
6125 checkGLcall("glGenTextures");
6126 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6127 checkGLcall("glBindTexture");
6128 /* Copy the bitmap memory into the cursor texture */
6129 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6130 HeapFree(GetProcessHeap(), 0, mem);
6131 checkGLcall("glTexImage2D");
6133 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6135 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6136 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6141 context_release(context);
6145 FIXME("A cursor texture was not returned.\n");
6146 This->cursorTexture = 0;
6151 /* Draw a hardware cursor */
6152 ICONINFO cursorInfo;
6154 /* Create and clear maskBits because it is not needed for
6155 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6157 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6158 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6159 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6160 WINED3DLOCK_NO_DIRTY_UPDATE |
6161 WINED3DLOCK_READONLY
6163 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6164 pSur->currentDesc.Height);
6166 cursorInfo.fIcon = FALSE;
6167 cursorInfo.xHotspot = XHotSpot;
6168 cursorInfo.yHotspot = YHotSpot;
6169 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6171 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6172 1, 32, lockedRect.pBits);
6173 IWineD3DSurface_UnlockRect(pCursorBitmap);
6174 /* Create our cursor and clean up. */
6175 cursor = CreateIconIndirect(&cursorInfo);
6177 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6178 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6179 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6180 This->hardwareCursor = cursor;
6181 HeapFree(GetProcessHeap(), 0, maskBits);
6185 This->xHotSpot = XHotSpot;
6186 This->yHotSpot = YHotSpot;
6190 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6192 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6194 This->xScreenSpace = XScreenSpace;
6195 This->yScreenSpace = YScreenSpace;
6201 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6203 BOOL oldVisible = This->bCursorVisible;
6206 TRACE("(%p) : visible(%d)\n", This, bShow);
6209 * When ShowCursor is first called it should make the cursor appear at the OS's last
6210 * known cursor position. Because of this, some applications just repetitively call
6211 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6214 This->xScreenSpace = pt.x;
6215 This->yScreenSpace = pt.y;
6217 if (This->haveHardwareCursor) {
6218 This->bCursorVisible = bShow;
6220 SetCursor(This->hardwareCursor);
6226 if (This->cursorTexture)
6227 This->bCursorVisible = bShow;
6233 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6234 TRACE("checking resource %p for eviction\n", resource);
6235 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6236 TRACE("Evicting %p\n", resource);
6237 IWineD3DResource_UnLoad(resource);
6239 IWineD3DResource_Release(resource);
6243 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6245 TRACE("(%p)\n", This);
6247 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6251 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6253 IWineD3DDeviceImpl *device = surface->resource.device;
6254 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6256 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6257 if(surface->Flags & SFLAG_DIBSECTION) {
6258 /* Release the DC */
6259 SelectObject(surface->hDC, surface->dib.holdbitmap);
6260 DeleteDC(surface->hDC);
6261 /* Release the DIB section */
6262 DeleteObject(surface->dib.DIBsection);
6263 surface->dib.bitmap_data = NULL;
6264 surface->resource.allocatedMemory = NULL;
6265 surface->Flags &= ~SFLAG_DIBSECTION;
6267 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6268 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6269 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6270 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6272 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6273 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6275 surface->pow2Width = surface->pow2Height = 1;
6276 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6277 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6279 surface->glRect.left = 0;
6280 surface->glRect.top = 0;
6281 surface->glRect.right = surface->pow2Width;
6282 surface->glRect.bottom = surface->pow2Height;
6284 if (surface->texture_name)
6286 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6288 glDeleteTextures(1, &surface->texture_name);
6290 context_release(context);
6291 surface->texture_name = 0;
6292 surface->Flags &= ~SFLAG_CLIENT;
6294 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6295 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6296 surface->Flags |= SFLAG_NONPOW2;
6298 surface->Flags &= ~SFLAG_NONPOW2;
6300 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6301 surface->resource.allocatedMemory = NULL;
6302 surface->resource.heapMemory = NULL;
6303 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6305 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6307 if(!surface_init_sysmem((IWineD3DSurface *) surface))
6309 return E_OUTOFMEMORY;
6314 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6315 TRACE("Unloading resource %p\n", resource);
6316 IWineD3DResource_UnLoad(resource);
6317 IWineD3DResource_Release(resource);
6321 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6324 WINED3DDISPLAYMODE m;
6327 /* All Windowed modes are supported, as is leaving the current mode */
6328 if(pp->Windowed) return TRUE;
6329 if(!pp->BackBufferWidth) return TRUE;
6330 if(!pp->BackBufferHeight) return TRUE;
6332 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6333 for(i = 0; i < count; i++) {
6334 memset(&m, 0, sizeof(m));
6335 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6337 ERR("EnumAdapterModes failed\n");
6339 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6340 /* Mode found, it is supported */
6344 /* Mode not found -> not supported */
6348 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6350 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6351 const struct wined3d_gl_info *gl_info;
6352 struct wined3d_context *context;
6354 IWineD3DBaseShaderImpl *shader;
6356 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6357 gl_info = context->gl_info;
6359 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6360 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6361 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6365 if(This->depth_blt_texture) {
6366 glDeleteTextures(1, &This->depth_blt_texture);
6367 This->depth_blt_texture = 0;
6369 if (This->depth_blt_rb) {
6370 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6371 This->depth_blt_rb = 0;
6372 This->depth_blt_rb_w = 0;
6373 This->depth_blt_rb_h = 0;
6377 This->blitter->free_private(iface);
6378 This->frag_pipe->free_private(iface);
6379 This->shader_backend->shader_free_private(iface);
6382 for (i = 0; i < This->adapter->gl_info.limits.textures; ++i)
6384 /* Textures are recreated below */
6385 glDeleteTextures(1, &This->dummyTextureName[i]);
6386 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6387 This->dummyTextureName[i] = 0;
6391 context_release(context);
6393 while (This->numContexts)
6395 context_destroy(This, This->contexts[0]);
6397 HeapFree(GetProcessHeap(), 0, swapchain->context);
6398 swapchain->context = NULL;
6399 swapchain->num_contexts = 0;
6402 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6404 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6406 IWineD3DSurfaceImpl *target;
6408 /* Recreate the primary swapchain's context */
6409 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6410 if(swapchain->backBuffer) {
6411 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6413 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6415 swapchain->context[0] = context_create(This, target, swapchain->win_handle, FALSE, &swapchain->presentParms);
6416 swapchain->num_contexts = 1;
6417 swapchain->context[0]->render_offscreen = swapchain->render_to_fbo;
6419 create_dummy_textures(This);
6421 context_release(swapchain->context[0]);
6423 hr = This->shader_backend->shader_alloc_private(iface);
6425 ERR("Failed to recreate shader private data\n");
6428 hr = This->frag_pipe->alloc_private(iface);
6430 TRACE("Fragment pipeline private data couldn't be allocated\n");
6433 hr = This->blitter->alloc_private(iface);
6435 TRACE("Blitter private data couldn't be allocated\n");
6442 This->blitter->free_private(iface);
6443 This->frag_pipe->free_private(iface);
6444 This->shader_backend->shader_free_private(iface);
6448 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6449 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6450 IWineD3DSwapChainImpl *swapchain;
6452 BOOL DisplayModeChanged = FALSE;
6453 WINED3DDISPLAYMODE mode;
6454 TRACE("(%p)\n", This);
6456 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6458 ERR("Failed to get the first implicit swapchain\n");
6462 if(!is_display_mode_supported(This, pPresentationParameters)) {
6463 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6464 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6465 pPresentationParameters->BackBufferHeight);
6466 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6467 return WINED3DERR_INVALIDCALL;
6470 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6471 * on an existing gl context, so there's no real need for recreation.
6473 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6475 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6477 TRACE("New params:\n");
6478 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6479 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6480 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6481 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6482 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6483 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6484 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6485 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6486 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6487 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6488 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6489 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6490 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6492 /* No special treatment of these parameters. Just store them */
6493 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6494 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6495 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6496 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6498 /* What to do about these? */
6499 if(pPresentationParameters->BackBufferCount != 0 &&
6500 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6501 ERR("Cannot change the back buffer count yet\n");
6503 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6504 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6505 ERR("Cannot change the back buffer format yet\n");
6507 if(pPresentationParameters->hDeviceWindow != NULL &&
6508 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6509 ERR("Cannot change the device window yet\n");
6511 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6514 TRACE("Creating the depth stencil buffer\n");
6516 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6518 pPresentationParameters->BackBufferWidth,
6519 pPresentationParameters->BackBufferHeight,
6520 pPresentationParameters->AutoDepthStencilFormat,
6521 pPresentationParameters->MultiSampleType,
6522 pPresentationParameters->MultiSampleQuality,
6524 &This->auto_depth_stencil_buffer);
6527 ERR("Failed to create the depth stencil buffer\n");
6528 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6529 return WINED3DERR_INVALIDCALL;
6533 /* Reset the depth stencil */
6534 if (pPresentationParameters->EnableAutoDepthStencil)
6535 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6537 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6539 TRACE("Resetting stateblock\n");
6540 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6541 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6543 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6545 if(pPresentationParameters->Windowed) {
6546 mode.Width = swapchain->orig_width;
6547 mode.Height = swapchain->orig_height;
6548 mode.RefreshRate = 0;
6549 mode.Format = swapchain->presentParms.BackBufferFormat;
6551 mode.Width = pPresentationParameters->BackBufferWidth;
6552 mode.Height = pPresentationParameters->BackBufferHeight;
6553 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6554 mode.Format = swapchain->presentParms.BackBufferFormat;
6557 /* Should Width == 800 && Height == 0 set 800x600? */
6558 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6559 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6560 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6564 if(!pPresentationParameters->Windowed) {
6565 DisplayModeChanged = TRUE;
6567 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6568 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6570 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6573 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6577 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6578 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6581 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6585 if(This->auto_depth_stencil_buffer) {
6586 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6589 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6595 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6596 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6597 DisplayModeChanged) {
6599 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6601 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
6602 if(swapchain->presentParms.Windowed) {
6603 /* switch from windowed to fs */
6604 IWineD3DDeviceImpl_SetupFullscreenWindow(This, swapchain->win_handle,
6605 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight);
6607 /* Fullscreen -> fullscreen mode change */
6608 MoveWindow(swapchain->win_handle, 0, 0,
6609 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6612 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
6613 /* Fullscreen -> windowed switch */
6614 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
6616 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6617 } else if(!pPresentationParameters->Windowed) {
6618 DWORD style = This->style, exStyle = This->exStyle;
6619 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6620 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6621 * Reset to clear up their mess. Guild Wars also loses the device during that.
6625 IWineD3DDeviceImpl_SetupFullscreenWindow(This, swapchain->win_handle,
6626 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight);
6627 This->style = style;
6628 This->exStyle = exStyle;
6631 /* Note: No parent needed for initial internal stateblock */
6632 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6633 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6634 else TRACE("Created stateblock %p\n", This->stateBlock);
6635 This->updateStateBlock = This->stateBlock;
6636 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6638 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6640 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6643 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6646 GetClientRect(swapchain->win_handle, &client_rect);
6648 if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6649 swapchain->presentParms.BackBufferHeight != client_rect.bottom)
6651 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6652 swapchain->presentParms.BackBufferWidth,
6653 swapchain->presentParms.BackBufferHeight,
6654 client_rect.right, client_rect.bottom);
6655 swapchain->render_to_fbo = TRUE;
6659 TRACE("Rendering directly to GL_BACK\n");
6660 swapchain->render_to_fbo = FALSE;
6664 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6665 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6667 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6673 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6675 /** FIXME: always true at the moment **/
6676 if(!bEnableDialogs) {
6677 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6683 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6685 TRACE("(%p) : pParameters %p\n", This, pParameters);
6687 *pParameters = This->createParms;
6691 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6692 IWineD3DSwapChain *swapchain;
6694 TRACE("Relaying to swapchain\n");
6696 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6697 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6698 IWineD3DSwapChain_Release(swapchain);
6703 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6704 IWineD3DSwapChain *swapchain;
6706 TRACE("Relaying to swapchain\n");
6708 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6709 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6710 IWineD3DSwapChain_Release(swapchain);
6716 /** ********************************************************
6717 * Notification functions
6718 ** ********************************************************/
6719 /** This function must be called in the release of a resource when ref == 0,
6720 * the contents of resource must still be correct,
6721 * any handles to other resource held by the caller must be closed
6722 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6723 *****************************************************/
6724 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6726 TRACE("(%p) : Adding resource %p\n", This, resource);
6728 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6731 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6733 TRACE("(%p) : Removing resource %p\n", This, resource);
6735 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6738 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6740 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6743 TRACE("(%p) : resource %p\n", This, resource);
6745 context_resource_released((IWineD3DDevice *)This, resource, type);
6748 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6749 case WINED3DRTYPE_SURFACE: {
6752 if (This->d3d_initialized)
6754 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6756 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6757 This->render_targets[i] = NULL;
6760 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6761 This->stencilBufferTarget = NULL;
6767 case WINED3DRTYPE_TEXTURE:
6768 case WINED3DRTYPE_CUBETEXTURE:
6769 case WINED3DRTYPE_VOLUMETEXTURE:
6770 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6771 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6772 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6773 This->stateBlock->textures[counter] = NULL;
6775 if (This->updateStateBlock != This->stateBlock ){
6776 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6777 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6778 This->updateStateBlock->textures[counter] = NULL;
6783 case WINED3DRTYPE_VOLUME:
6784 /* TODO: nothing really? */
6786 case WINED3DRTYPE_BUFFER:
6789 TRACE("Cleaning up stream pointers\n");
6791 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6792 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6793 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6795 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6796 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6797 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6798 This->updateStateBlock->streamSource[streamNumber] = 0;
6799 /* Set changed flag? */
6802 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) */
6803 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6804 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6805 This->stateBlock->streamSource[streamNumber] = 0;
6810 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6811 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6812 This->updateStateBlock->pIndexData = NULL;
6815 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6816 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6817 This->stateBlock->pIndexData = NULL;
6824 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6829 /* Remove the resource from the resourceStore */
6830 device_resource_remove(This, resource);
6832 TRACE("Resource released\n");
6836 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6838 IWineD3DResourceImpl *resource, *cursor;
6840 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6842 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6843 TRACE("enumerating resource %p\n", resource);
6844 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6845 ret = pCallback((IWineD3DResource *) resource, pData);
6846 if(ret == S_FALSE) {
6847 TRACE("Canceling enumeration\n");
6854 /**********************************************************
6855 * IWineD3DDevice VTbl follows
6856 **********************************************************/
6858 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6860 /*** IUnknown methods ***/
6861 IWineD3DDeviceImpl_QueryInterface,
6862 IWineD3DDeviceImpl_AddRef,
6863 IWineD3DDeviceImpl_Release,
6864 /*** IWineD3DDevice methods ***/
6865 IWineD3DDeviceImpl_GetParent,
6866 /*** Creation methods**/
6867 IWineD3DDeviceImpl_CreateBuffer,
6868 IWineD3DDeviceImpl_CreateVertexBuffer,
6869 IWineD3DDeviceImpl_CreateIndexBuffer,
6870 IWineD3DDeviceImpl_CreateStateBlock,
6871 IWineD3DDeviceImpl_CreateSurface,
6872 IWineD3DDeviceImpl_CreateRendertargetView,
6873 IWineD3DDeviceImpl_CreateTexture,
6874 IWineD3DDeviceImpl_CreateVolumeTexture,
6875 IWineD3DDeviceImpl_CreateVolume,
6876 IWineD3DDeviceImpl_CreateCubeTexture,
6877 IWineD3DDeviceImpl_CreateQuery,
6878 IWineD3DDeviceImpl_CreateSwapChain,
6879 IWineD3DDeviceImpl_CreateVertexDeclaration,
6880 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6881 IWineD3DDeviceImpl_CreateVertexShader,
6882 IWineD3DDeviceImpl_CreatePixelShader,
6883 IWineD3DDeviceImpl_CreatePalette,
6884 /*** Odd functions **/
6885 IWineD3DDeviceImpl_Init3D,
6886 IWineD3DDeviceImpl_InitGDI,
6887 IWineD3DDeviceImpl_Uninit3D,
6888 IWineD3DDeviceImpl_UninitGDI,
6889 IWineD3DDeviceImpl_SetMultithreaded,
6890 IWineD3DDeviceImpl_EvictManagedResources,
6891 IWineD3DDeviceImpl_GetAvailableTextureMem,
6892 IWineD3DDeviceImpl_GetBackBuffer,
6893 IWineD3DDeviceImpl_GetCreationParameters,
6894 IWineD3DDeviceImpl_GetDeviceCaps,
6895 IWineD3DDeviceImpl_GetDirect3D,
6896 IWineD3DDeviceImpl_GetDisplayMode,
6897 IWineD3DDeviceImpl_SetDisplayMode,
6898 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6899 IWineD3DDeviceImpl_GetRasterStatus,
6900 IWineD3DDeviceImpl_GetSwapChain,
6901 IWineD3DDeviceImpl_Reset,
6902 IWineD3DDeviceImpl_SetDialogBoxMode,
6903 IWineD3DDeviceImpl_SetCursorProperties,
6904 IWineD3DDeviceImpl_SetCursorPosition,
6905 IWineD3DDeviceImpl_ShowCursor,
6906 /*** Getters and setters **/
6907 IWineD3DDeviceImpl_SetClipPlane,
6908 IWineD3DDeviceImpl_GetClipPlane,
6909 IWineD3DDeviceImpl_SetClipStatus,
6910 IWineD3DDeviceImpl_GetClipStatus,
6911 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6912 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6913 IWineD3DDeviceImpl_SetDepthStencilSurface,
6914 IWineD3DDeviceImpl_GetDepthStencilSurface,
6915 IWineD3DDeviceImpl_SetGammaRamp,
6916 IWineD3DDeviceImpl_GetGammaRamp,
6917 IWineD3DDeviceImpl_SetIndexBuffer,
6918 IWineD3DDeviceImpl_GetIndexBuffer,
6919 IWineD3DDeviceImpl_SetBaseVertexIndex,
6920 IWineD3DDeviceImpl_GetBaseVertexIndex,
6921 IWineD3DDeviceImpl_SetLight,
6922 IWineD3DDeviceImpl_GetLight,
6923 IWineD3DDeviceImpl_SetLightEnable,
6924 IWineD3DDeviceImpl_GetLightEnable,
6925 IWineD3DDeviceImpl_SetMaterial,
6926 IWineD3DDeviceImpl_GetMaterial,
6927 IWineD3DDeviceImpl_SetNPatchMode,
6928 IWineD3DDeviceImpl_GetNPatchMode,
6929 IWineD3DDeviceImpl_SetPaletteEntries,
6930 IWineD3DDeviceImpl_GetPaletteEntries,
6931 IWineD3DDeviceImpl_SetPixelShader,
6932 IWineD3DDeviceImpl_GetPixelShader,
6933 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6934 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6935 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6936 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6937 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6938 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6939 IWineD3DDeviceImpl_SetRenderState,
6940 IWineD3DDeviceImpl_GetRenderState,
6941 IWineD3DDeviceImpl_SetRenderTarget,
6942 IWineD3DDeviceImpl_GetRenderTarget,
6943 IWineD3DDeviceImpl_SetFrontBackBuffers,
6944 IWineD3DDeviceImpl_SetSamplerState,
6945 IWineD3DDeviceImpl_GetSamplerState,
6946 IWineD3DDeviceImpl_SetScissorRect,
6947 IWineD3DDeviceImpl_GetScissorRect,
6948 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6949 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6950 IWineD3DDeviceImpl_SetStreamSource,
6951 IWineD3DDeviceImpl_GetStreamSource,
6952 IWineD3DDeviceImpl_SetStreamSourceFreq,
6953 IWineD3DDeviceImpl_GetStreamSourceFreq,
6954 IWineD3DDeviceImpl_SetTexture,
6955 IWineD3DDeviceImpl_GetTexture,
6956 IWineD3DDeviceImpl_SetTextureStageState,
6957 IWineD3DDeviceImpl_GetTextureStageState,
6958 IWineD3DDeviceImpl_SetTransform,
6959 IWineD3DDeviceImpl_GetTransform,
6960 IWineD3DDeviceImpl_SetVertexDeclaration,
6961 IWineD3DDeviceImpl_GetVertexDeclaration,
6962 IWineD3DDeviceImpl_SetVertexShader,
6963 IWineD3DDeviceImpl_GetVertexShader,
6964 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6965 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6966 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6967 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6968 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6969 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6970 IWineD3DDeviceImpl_SetViewport,
6971 IWineD3DDeviceImpl_GetViewport,
6972 IWineD3DDeviceImpl_MultiplyTransform,
6973 IWineD3DDeviceImpl_ValidateDevice,
6974 IWineD3DDeviceImpl_ProcessVertices,
6975 /*** State block ***/
6976 IWineD3DDeviceImpl_BeginStateBlock,
6977 IWineD3DDeviceImpl_EndStateBlock,
6978 /*** Scene management ***/
6979 IWineD3DDeviceImpl_BeginScene,
6980 IWineD3DDeviceImpl_EndScene,
6981 IWineD3DDeviceImpl_Present,
6982 IWineD3DDeviceImpl_Clear,
6983 IWineD3DDeviceImpl_ClearRendertargetView,
6985 IWineD3DDeviceImpl_SetPrimitiveType,
6986 IWineD3DDeviceImpl_GetPrimitiveType,
6987 IWineD3DDeviceImpl_DrawPrimitive,
6988 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6989 IWineD3DDeviceImpl_DrawPrimitiveUP,
6990 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6991 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6992 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6993 IWineD3DDeviceImpl_DrawRectPatch,
6994 IWineD3DDeviceImpl_DrawTriPatch,
6995 IWineD3DDeviceImpl_DeletePatch,
6996 IWineD3DDeviceImpl_ColorFill,
6997 IWineD3DDeviceImpl_UpdateTexture,
6998 IWineD3DDeviceImpl_UpdateSurface,
6999 IWineD3DDeviceImpl_GetFrontBufferData,
7000 /*** object tracking ***/
7001 IWineD3DDeviceImpl_EnumResources
7004 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
7005 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
7006 IUnknown *parent, IWineD3DDeviceParent *device_parent)
7008 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
7009 const struct fragment_pipeline *fragment_pipeline;
7010 struct shader_caps shader_caps;
7011 struct fragment_caps ffp_caps;
7012 WINED3DDISPLAYMODE mode;
7016 device->lpVtbl = &IWineD3DDevice_Vtbl;
7018 device->wined3d = (IWineD3D *)wined3d;
7019 IWineD3D_AddRef(device->wined3d);
7020 device->adapter = wined3d->adapter_count ? adapter : NULL;
7021 device->parent = parent;
7022 device->device_parent = device_parent;
7023 list_init(&device->resources);
7024 list_init(&device->shaders);
7026 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7027 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
7029 /* Get the initial screen setup for ddraw. */
7030 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
7033 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7034 IWineD3D_Release(device->wined3d);
7037 device->ddraw_width = mode.Width;
7038 device->ddraw_height = mode.Height;
7039 device->ddraw_format = mode.Format;
7041 /* Save the creation parameters. */
7042 device->createParms.AdapterOrdinal = adapter_idx;
7043 device->createParms.DeviceType = device_type;
7044 device->createParms.hFocusWindow = focus_window;
7045 device->createParms.BehaviorFlags = flags;
7047 device->devType = device_type;
7048 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7050 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7051 device->shader_backend = select_shader_backend(adapter, device_type);
7053 memset(&shader_caps, 0, sizeof(shader_caps));
7054 device->shader_backend->shader_get_caps(device_type, &adapter->gl_info, &shader_caps);
7055 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7056 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7057 device->vs_clipping = shader_caps.VSClipping;
7059 memset(&ffp_caps, 0, sizeof(ffp_caps));
7060 fragment_pipeline = select_fragment_implementation(adapter, device_type);
7061 device->frag_pipe = fragment_pipeline;
7062 fragment_pipeline->get_caps(device_type, &adapter->gl_info, &ffp_caps);
7063 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7064 device->max_ffp_texture_stages = ffp_caps.MaxTextureBlendStages;
7066 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7067 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7070 ERR("Failed to compile state table, hr %#x.\n", hr);
7071 IWineD3D_Release(device->wined3d);
7075 device->blitter = select_blit_implementation(adapter, device_type);
7081 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7082 DWORD rep = This->StateTable[state].representative;
7083 struct wined3d_context *context;
7088 for(i = 0; i < This->numContexts; i++) {
7089 context = This->contexts[i];
7090 if(isStateDirty(context, rep)) continue;
7092 context->dirtyArray[context->numDirtyEntries++] = rep;
7095 context->isStateDirty[idx] |= (1 << shift);
7099 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7101 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.device;
7102 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7103 *width = device->pbufferWidth;
7104 *height = device->pbufferHeight;
7107 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7109 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7110 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7111 *width = surface->pow2Width;
7112 *height = surface->pow2Height;
7115 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7117 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7118 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7119 * current context's drawable, which is the size of the back buffer of the swapchain
7120 * the active context belongs to. The back buffer of the swapchain is stored as the
7121 * surface the context belongs to. */
7122 *width = surface->currentDesc.Width;
7123 *height = surface->currentDesc.Height;