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");
643 return WINED3DERR_OUTOFVIDEOMEMORY;
646 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
647 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
650 WARN("Failed to initialize surface, returning %#x.\n", hr);
651 HeapFree(GetProcessHeap(), 0, object);
655 TRACE("(%p) : Created surface %p\n", This, object);
657 *ppSurface = (IWineD3DSurface *)object;
662 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
663 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
665 struct wined3d_rendertarget_view *object;
667 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
670 ERR("Failed to allocate memory\n");
671 return E_OUTOFMEMORY;
674 object->vtbl = &wined3d_rendertarget_view_vtbl;
675 object->refcount = 1;
676 IWineD3DResource_AddRef(resource);
677 object->resource = resource;
678 object->parent = parent;
680 *rendertarget_view = (IWineD3DRendertargetView *)object;
685 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
686 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
687 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
690 IWineD3DTextureImpl *object;
693 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
694 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
695 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
697 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
700 ERR("Out of memory\n");
702 return WINED3DERR_OUTOFVIDEOMEMORY;
705 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
708 WARN("Failed to initialize texture, returning %#x\n", hr);
709 HeapFree(GetProcessHeap(), 0, object);
714 *ppTexture = (IWineD3DTexture *)object;
716 TRACE("(%p) : Created texture %p\n", This, object);
721 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
722 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
723 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
726 IWineD3DVolumeTextureImpl *object;
729 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
730 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
732 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
735 ERR("Out of memory\n");
736 *ppVolumeTexture = NULL;
737 return WINED3DERR_OUTOFVIDEOMEMORY;
740 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
743 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
744 HeapFree(GetProcessHeap(), 0, object);
745 *ppVolumeTexture = NULL;
749 TRACE("(%p) : Created volume texture %p.\n", This, object);
750 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
755 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
756 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
757 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
760 IWineD3DVolumeImpl *object;
763 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
764 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
766 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
769 ERR("Out of memory\n");
771 return WINED3DERR_OUTOFVIDEOMEMORY;
774 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
777 WARN("Failed to initialize volume, returning %#x.\n", hr);
778 HeapFree(GetProcessHeap(), 0, object);
782 TRACE("(%p) : Created volume %p.\n", This, object);
783 *ppVolume = (IWineD3DVolume *)object;
788 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
789 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
790 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
793 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
796 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
799 ERR("Out of memory\n");
800 *ppCubeTexture = NULL;
801 return WINED3DERR_OUTOFVIDEOMEMORY;
804 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
807 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
808 HeapFree(GetProcessHeap(), 0, object);
809 *ppCubeTexture = NULL;
813 TRACE("(%p) : Created Cube Texture %p\n", This, object);
814 *ppCubeTexture = (IWineD3DCubeTexture *)object;
819 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
821 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
822 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
823 HRESULT hr = WINED3DERR_NOTAVAILABLE;
824 const IWineD3DQueryVtbl *vtable;
826 /* Just a check to see if we support this type of query */
828 case WINED3DQUERYTYPE_OCCLUSION:
829 TRACE("(%p) occlusion query\n", This);
830 if (gl_info->supported[ARB_OCCLUSION_QUERY])
833 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
835 vtable = &IWineD3DOcclusionQuery_Vtbl;
838 case WINED3DQUERYTYPE_EVENT:
839 if (!gl_info->supported[NV_FENCE] && !gl_info->supported[APPLE_FENCE])
841 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
842 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
844 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
846 vtable = &IWineD3DEventQuery_Vtbl;
850 case WINED3DQUERYTYPE_VCACHE:
851 case WINED3DQUERYTYPE_RESOURCEMANAGER:
852 case WINED3DQUERYTYPE_VERTEXSTATS:
853 case WINED3DQUERYTYPE_TIMESTAMP:
854 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
855 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
856 case WINED3DQUERYTYPE_PIPELINETIMINGS:
857 case WINED3DQUERYTYPE_INTERFACETIMINGS:
858 case WINED3DQUERYTYPE_VERTEXTIMINGS:
859 case WINED3DQUERYTYPE_PIXELTIMINGS:
860 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
861 case WINED3DQUERYTYPE_CACHEUTILIZATION:
863 /* Use the base Query vtable until we have a special one for each query */
864 vtable = &IWineD3DQuery_Vtbl;
865 FIXME("(%p) Unhandled query type %d\n", This, Type);
867 if(NULL == ppQuery || hr != WINED3D_OK) {
871 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
874 ERR("Out of memory\n");
876 return WINED3DERR_OUTOFVIDEOMEMORY;
879 object->lpVtbl = vtable;
881 object->state = QUERY_CREATED;
882 object->device = This;
883 object->parent = parent;
886 *ppQuery = (IWineD3DQuery *)object;
888 /* allocated the 'extended' data based on the type of query requested */
890 case WINED3DQUERYTYPE_OCCLUSION:
891 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
892 ((struct wined3d_occlusion_query *)object->extendedData)->context = NULL;
895 case WINED3DQUERYTYPE_EVENT:
896 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query));
897 ((struct wined3d_event_query *)object->extendedData)->context = NULL;
900 case WINED3DQUERYTYPE_VCACHE:
901 case WINED3DQUERYTYPE_RESOURCEMANAGER:
902 case WINED3DQUERYTYPE_VERTEXSTATS:
903 case WINED3DQUERYTYPE_TIMESTAMP:
904 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
905 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
906 case WINED3DQUERYTYPE_PIPELINETIMINGS:
907 case WINED3DQUERYTYPE_INTERFACETIMINGS:
908 case WINED3DQUERYTYPE_VERTEXTIMINGS:
909 case WINED3DQUERYTYPE_PIXELTIMINGS:
910 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
911 case WINED3DQUERYTYPE_CACHEUTILIZATION:
913 object->extendedData = 0;
914 FIXME("(%p) Unhandled query type %d\n",This , Type);
916 TRACE("(%p) : Created Query %p\n", This, object);
920 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
921 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
922 IUnknown *parent, WINED3DSURFTYPE surface_type)
924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
925 IWineD3DSwapChainImpl *object;
928 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
929 iface, present_parameters, swapchain, parent, surface_type);
931 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
934 ERR("Failed to allocate swapchain memory.\n");
935 return E_OUTOFMEMORY;
938 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
941 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
942 HeapFree(GetProcessHeap(), 0, object);
946 TRACE("Created swapchain %p.\n", object);
947 *swapchain = (IWineD3DSwapChain *)object;
952 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
953 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
954 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
955 TRACE("(%p)\n", This);
957 return This->NumberOfSwapChains;
960 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
962 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
964 if(iSwapChain < This->NumberOfSwapChains) {
965 *pSwapChain = This->swapchains[iSwapChain];
966 IWineD3DSwapChain_AddRef(*pSwapChain);
967 TRACE("(%p) returning %p\n", This, *pSwapChain);
970 TRACE("Swapchain out of range\n");
972 return WINED3DERR_INVALIDCALL;
976 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
977 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
978 const WINED3DVERTEXELEMENT *elements, UINT element_count)
980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
981 IWineD3DVertexDeclarationImpl *object = NULL;
984 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
985 iface, declaration, parent, elements, element_count);
987 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
990 ERR("Failed to allocate vertex declaration memory.\n");
991 return E_OUTOFMEMORY;
994 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
997 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
998 HeapFree(GetProcessHeap(), 0, object);
1002 TRACE("Created vertex declaration %p.\n", object);
1003 *declaration = (IWineD3DVertexDeclaration *)object;
1008 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1009 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1011 unsigned int idx, idx2;
1012 unsigned int offset;
1013 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1014 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1015 BOOL has_blend_idx = has_blend &&
1016 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1017 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1018 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1019 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1020 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1021 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1022 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1024 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1025 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1026 WINED3DVERTEXELEMENT *elements = NULL;
1029 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1030 if (has_blend_idx) num_blends--;
1032 /* Compute declaration size */
1033 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1034 has_psize + has_diffuse + has_specular + num_textures;
1036 /* convert the declaration */
1037 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1038 if (!elements) return ~0U;
1042 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1043 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1044 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1046 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1047 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1048 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1051 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1052 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1054 elements[idx].usage_idx = 0;
1057 if (has_blend && (num_blends > 0)) {
1058 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1059 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1061 switch(num_blends) {
1062 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1063 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1064 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1065 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1067 ERR("Unexpected amount of blend values: %u\n", num_blends);
1070 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1071 elements[idx].usage_idx = 0;
1074 if (has_blend_idx) {
1075 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1076 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1077 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1078 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1079 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1081 elements[idx].format = WINED3DFMT_R32_FLOAT;
1082 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1083 elements[idx].usage_idx = 0;
1087 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1088 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1089 elements[idx].usage_idx = 0;
1093 elements[idx].format = WINED3DFMT_R32_FLOAT;
1094 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1095 elements[idx].usage_idx = 0;
1099 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1100 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1101 elements[idx].usage_idx = 0;
1105 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1106 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1107 elements[idx].usage_idx = 1;
1110 for (idx2 = 0; idx2 < num_textures; idx2++) {
1111 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1112 switch (numcoords) {
1113 case WINED3DFVF_TEXTUREFORMAT1:
1114 elements[idx].format = WINED3DFMT_R32_FLOAT;
1116 case WINED3DFVF_TEXTUREFORMAT2:
1117 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1119 case WINED3DFVF_TEXTUREFORMAT3:
1120 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1122 case WINED3DFVF_TEXTUREFORMAT4:
1123 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1126 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1127 elements[idx].usage_idx = idx2;
1131 /* Now compute offsets, and initialize the rest of the fields */
1132 for (idx = 0, offset = 0; idx < size; ++idx)
1134 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1135 elements[idx].input_slot = 0;
1136 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1137 elements[idx].offset = offset;
1138 offset += format_desc->component_count * format_desc->component_size;
1141 *ppVertexElements = elements;
1145 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1146 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1147 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1150 WINED3DVERTEXELEMENT *elements;
1154 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1156 size = ConvertFvfToDeclaration(This, fvf, &elements);
1157 if (size == ~0U) return E_OUTOFMEMORY;
1159 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1160 HeapFree(GetProcessHeap(), 0, elements);
1164 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1165 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1166 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1167 const struct wined3d_parent_ops *parent_ops)
1169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1170 IWineD3DVertexShaderImpl *object;
1173 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1176 ERR("Failed to allocate shader memory.\n");
1177 return E_OUTOFMEMORY;
1180 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1183 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1184 HeapFree(GetProcessHeap(), 0, object);
1188 TRACE("Created vertex shader %p.\n", object);
1189 *ppVertexShader = (IWineD3DVertexShader *)object;
1194 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1195 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1196 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1197 const struct wined3d_parent_ops *parent_ops)
1199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1200 IWineD3DPixelShaderImpl *object;
1203 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1206 ERR("Failed to allocate shader memory.\n");
1207 return E_OUTOFMEMORY;
1210 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1213 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1214 HeapFree(GetProcessHeap(), 0, object);
1218 TRACE("Created pixel shader %p.\n", object);
1219 *ppPixelShader = (IWineD3DPixelShader *)object;
1224 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1225 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1228 IWineD3DPaletteImpl *object;
1230 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1232 /* Create the new object */
1233 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1235 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1236 return E_OUTOFMEMORY;
1239 object->lpVtbl = &IWineD3DPalette_Vtbl;
1241 object->Flags = Flags;
1242 object->parent = Parent;
1243 object->device = This;
1244 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1245 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1248 HeapFree( GetProcessHeap(), 0, object);
1249 return E_OUTOFMEMORY;
1252 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1254 IWineD3DPalette_Release((IWineD3DPalette *) object);
1258 *Palette = (IWineD3DPalette *) object;
1263 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1267 HDC dcb = NULL, dcs = NULL;
1268 WINEDDCOLORKEY colorkey;
1270 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1273 GetObjectA(hbm, sizeof(BITMAP), &bm);
1274 dcb = CreateCompatibleDC(NULL);
1276 SelectObject(dcb, hbm);
1280 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1281 * couldn't be loaded
1283 memset(&bm, 0, sizeof(bm));
1288 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1289 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1290 NULL, &wined3d_null_parent_ops);
1292 ERR("Wine logo requested, but failed to create surface\n");
1297 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1298 if(FAILED(hr)) goto out;
1299 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1300 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1302 colorkey.dwColorSpaceLowValue = 0;
1303 colorkey.dwColorSpaceHighValue = 0;
1304 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1306 /* Fill the surface with a white color to show that wined3d is there */
1307 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1320 /* Context activation is done by the caller. */
1321 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1323 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1325 /* Under DirectX you can have texture stage operations even if no texture is
1326 bound, whereas opengl will only do texture operations when a valid texture is
1327 bound. We emulate this by creating dummy textures and binding them to each
1328 texture stage, but disable all stages by default. Hence if a stage is enabled
1329 then the default texture will kick in until replaced by a SetTexture call */
1332 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1334 /* The dummy texture does not have client storage backing */
1335 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1336 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1339 for (i = 0; i < gl_info->limits.textures; ++i)
1341 GLubyte white = 255;
1343 /* Make appropriate texture active */
1344 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1345 checkGLcall("glActiveTextureARB");
1347 /* Generate an opengl texture name */
1348 glGenTextures(1, &This->dummyTextureName[i]);
1349 checkGLcall("glGenTextures");
1350 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1352 /* Generate a dummy 2d texture (not using 1d because they cause many
1353 * DRI drivers fall back to sw) */
1354 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1355 checkGLcall("glBindTexture");
1357 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1358 checkGLcall("glTexImage2D");
1361 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1363 /* Reenable because if supported it is enabled by default */
1364 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1365 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1371 /* Context activation is done by the caller. */
1372 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1375 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1376 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1379 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1382 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1383 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1386 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1387 IWineD3DSwapChainImpl *swapchain = NULL;
1388 struct wined3d_context *context;
1393 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1395 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1396 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1398 This-> focus_window = This->createParms.hFocusWindow;
1399 if (!This->focus_window) This->focus_window = pPresentationParameters->hDeviceWindow;
1400 if (!wined3d_register_window(This->focus_window, This))
1402 ERR("Failed to register window %p.\n", This->focus_window);
1406 TRACE("(%p) : Creating stateblock\n", This);
1407 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1408 hr = IWineD3DDevice_CreateStateBlock(iface,
1410 (IWineD3DStateBlock **)&This->stateBlock,
1412 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1413 WARN("Failed to create stateblock\n");
1416 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1417 This->updateStateBlock = This->stateBlock;
1418 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1420 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1421 sizeof(IWineD3DSurface *) * gl_info->limits.buffers);
1422 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1423 sizeof(GLenum) * gl_info->limits.buffers);
1425 This->NumberOfPalettes = 1;
1426 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1427 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1428 ERR("Out of memory!\n");
1432 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1433 if(!This->palettes[0]) {
1434 ERR("Out of memory!\n");
1438 for (i = 0; i < 256; ++i) {
1439 This->palettes[0][i].peRed = 0xFF;
1440 This->palettes[0][i].peGreen = 0xFF;
1441 This->palettes[0][i].peBlue = 0xFF;
1442 This->palettes[0][i].peFlags = 0xFF;
1444 This->currentPalette = 0;
1446 /* Initialize the texture unit mapping to a 1:1 mapping */
1447 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1449 if (state < gl_info->limits.fragment_samplers)
1451 This->texUnitMap[state] = state;
1452 This->rev_tex_unit_map[state] = state;
1454 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1455 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1459 SetFocus(This->focus_window);
1461 /* Setup the implicit swapchain. This also initializes a context. */
1462 TRACE("Creating implicit swapchain\n");
1463 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1464 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1467 WARN("Failed to create implicit swapchain\n");
1471 This->NumberOfSwapChains = 1;
1472 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1473 if(!This->swapchains) {
1474 ERR("Out of memory!\n");
1477 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1479 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1480 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1481 This->render_targets[0] = swapchain->backBuffer[0];
1484 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1485 This->render_targets[0] = swapchain->frontBuffer;
1487 IWineD3DSurface_AddRef(This->render_targets[0]);
1489 /* Depth Stencil support */
1490 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1491 if (NULL != This->stencilBufferTarget) {
1492 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1495 hr = This->shader_backend->shader_alloc_private(iface);
1497 TRACE("Shader private data couldn't be allocated\n");
1500 hr = This->frag_pipe->alloc_private(iface);
1502 TRACE("Fragment pipeline private data couldn't be allocated\n");
1505 hr = This->blitter->alloc_private(iface);
1507 TRACE("Blitter private data couldn't be allocated\n");
1511 /* Set up some starting GL setup */
1513 /* Setup all the devices defaults */
1514 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1516 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1518 create_dummy_textures(This);
1522 /* Initialize the current view state */
1523 This->view_ident = 1;
1524 This->contexts[0]->last_was_rhw = 0;
1525 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1526 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1528 switch(wined3d_settings.offscreen_rendering_mode) {
1530 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1534 This->offscreenBuffer = GL_BACK;
1537 case ORM_BACKBUFFER:
1539 if (context_get_current()->aux_buffers > 0)
1541 TRACE("Using auxilliary buffer for offscreen rendering\n");
1542 This->offscreenBuffer = GL_AUX0;
1544 TRACE("Using back buffer for offscreen rendering\n");
1545 This->offscreenBuffer = GL_BACK;
1550 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1553 context_release(context);
1555 /* Clear the screen */
1556 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1557 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1560 This->d3d_initialized = TRUE;
1562 if(wined3d_settings.logo) {
1563 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1565 This->highest_dirty_ps_const = 0;
1566 This->highest_dirty_vs_const = 0;
1570 HeapFree(GetProcessHeap(), 0, This->render_targets);
1571 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1572 HeapFree(GetProcessHeap(), 0, This->swapchains);
1573 This->NumberOfSwapChains = 0;
1574 if(This->palettes) {
1575 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1576 HeapFree(GetProcessHeap(), 0, This->palettes);
1578 This->NumberOfPalettes = 0;
1580 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1582 if(This->stateBlock) {
1583 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1584 This->stateBlock = NULL;
1586 if (This->blit_priv) {
1587 This->blitter->free_private(iface);
1589 if (This->fragment_priv) {
1590 This->frag_pipe->free_private(iface);
1592 if (This->shader_priv) {
1593 This->shader_backend->shader_free_private(iface);
1595 wined3d_unregister_window(This->focus_window);
1599 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1600 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1603 IWineD3DSwapChainImpl *swapchain = NULL;
1606 /* Setup the implicit swapchain */
1607 TRACE("Creating implicit swapchain\n");
1608 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1609 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1612 WARN("Failed to create implicit swapchain\n");
1616 This->NumberOfSwapChains = 1;
1617 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1618 if(!This->swapchains) {
1619 ERR("Out of memory!\n");
1622 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1626 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1630 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1632 IWineD3DResource_UnLoad(resource);
1633 IWineD3DResource_Release(resource);
1637 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1638 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1641 const struct wined3d_gl_info *gl_info;
1642 struct wined3d_context *context;
1645 TRACE("(%p)\n", This);
1647 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1649 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1650 * it was created. Thus make sure a context is active for the glDelete* calls
1652 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1653 gl_info = context->gl_info;
1655 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1657 /* Unload resources */
1658 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1660 TRACE("Deleting high order patches\n");
1661 for(i = 0; i < PATCHMAP_SIZE; i++) {
1662 struct list *e1, *e2;
1663 struct WineD3DRectPatch *patch;
1664 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1665 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1666 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1670 /* Delete the palette conversion shader if it is around */
1671 if(This->paletteConversionShader) {
1673 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
1675 This->paletteConversionShader = 0;
1678 /* Delete the pbuffer context if there is any */
1679 if(This->pbufferContext) context_destroy(This, This->pbufferContext);
1681 /* Delete the mouse cursor texture */
1682 if(This->cursorTexture) {
1684 glDeleteTextures(1, &This->cursorTexture);
1686 This->cursorTexture = 0;
1689 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1690 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1692 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1693 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1696 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1697 * private data, it might contain opengl pointers
1699 if(This->depth_blt_texture) {
1701 glDeleteTextures(1, &This->depth_blt_texture);
1703 This->depth_blt_texture = 0;
1705 if (This->depth_blt_rb) {
1707 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1709 This->depth_blt_rb = 0;
1710 This->depth_blt_rb_w = 0;
1711 This->depth_blt_rb_h = 0;
1714 /* Release the update stateblock */
1715 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1716 if(This->updateStateBlock != This->stateBlock)
1717 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1719 This->updateStateBlock = NULL;
1721 { /* because were not doing proper internal refcounts releasing the primary state block
1722 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1723 to set this->stateBlock = NULL; first */
1724 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1725 This->stateBlock = NULL;
1727 /* Release the stateblock */
1728 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1729 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1733 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1734 This->blitter->free_private(iface);
1735 This->frag_pipe->free_private(iface);
1736 This->shader_backend->shader_free_private(iface);
1738 /* Release the buffers (with sanity checks)*/
1739 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1740 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1741 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
1742 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
1744 This->stencilBufferTarget = NULL;
1746 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1747 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1748 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1750 TRACE("Setting rendertarget to NULL\n");
1751 This->render_targets[0] = NULL;
1753 if (This->auto_depth_stencil_buffer) {
1754 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
1756 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1758 This->auto_depth_stencil_buffer = NULL;
1761 context_release(context);
1763 for(i=0; i < This->NumberOfSwapChains; i++) {
1764 TRACE("Releasing the implicit swapchain %d\n", i);
1765 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1766 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1770 HeapFree(GetProcessHeap(), 0, This->swapchains);
1771 This->swapchains = NULL;
1772 This->NumberOfSwapChains = 0;
1774 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1775 HeapFree(GetProcessHeap(), 0, This->palettes);
1776 This->palettes = NULL;
1777 This->NumberOfPalettes = 0;
1779 HeapFree(GetProcessHeap(), 0, This->render_targets);
1780 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1781 This->render_targets = NULL;
1782 This->draw_buffers = NULL;
1784 This->d3d_initialized = FALSE;
1786 wined3d_unregister_window(This->focus_window);
1791 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1795 for(i=0; i < This->NumberOfSwapChains; i++) {
1796 TRACE("Releasing the implicit swapchain %d\n", i);
1797 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1798 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1802 HeapFree(GetProcessHeap(), 0, This->swapchains);
1803 This->swapchains = NULL;
1804 This->NumberOfSwapChains = 0;
1808 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1809 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1810 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1812 * There is no way to deactivate thread safety once it is enabled.
1814 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1817 /*For now just store the flag(needed in case of ddraw) */
1818 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1823 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1824 const WINED3DDISPLAYMODE* pMode) {
1826 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1828 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1831 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1833 /* Resize the screen even without a window:
1834 * The app could have unset it with SetCooperativeLevel, but not called
1835 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1836 * but we don't have any hwnd
1839 memset(&devmode, 0, sizeof(devmode));
1840 devmode.dmSize = sizeof(devmode);
1841 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1842 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1843 devmode.dmPelsWidth = pMode->Width;
1844 devmode.dmPelsHeight = pMode->Height;
1846 devmode.dmDisplayFrequency = pMode->RefreshRate;
1847 if (pMode->RefreshRate != 0) {
1848 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1851 /* Only change the mode if necessary */
1852 if( (This->ddraw_width == pMode->Width) &&
1853 (This->ddraw_height == pMode->Height) &&
1854 (This->ddraw_format == pMode->Format) &&
1855 (pMode->RefreshRate == 0) ) {
1859 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1860 if (ret != DISP_CHANGE_SUCCESSFUL) {
1861 if(devmode.dmDisplayFrequency != 0) {
1862 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1863 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1864 devmode.dmDisplayFrequency = 0;
1865 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1867 if(ret != DISP_CHANGE_SUCCESSFUL) {
1868 return WINED3DERR_NOTAVAILABLE;
1872 /* Store the new values */
1873 This->ddraw_width = pMode->Width;
1874 This->ddraw_height = pMode->Height;
1875 This->ddraw_format = pMode->Format;
1877 /* And finally clip mouse to our screen */
1878 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1879 ClipCursor(&clip_rc);
1884 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1886 *ppD3D = This->wined3d;
1887 TRACE("Returning %p.\n", *ppD3D);
1888 IWineD3D_AddRef(*ppD3D);
1892 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1895 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1896 (This->adapter->TextureRam/(1024*1024)),
1897 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
1898 /* return simulated texture memory left */
1899 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
1903 * Get / Set Stream Source
1905 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
1906 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
1908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1909 IWineD3DBuffer *oldSrc;
1911 if (StreamNumber >= MAX_STREAMS) {
1912 WARN("Stream out of range %d\n", StreamNumber);
1913 return WINED3DERR_INVALIDCALL;
1914 } else if(OffsetInBytes & 0x3) {
1915 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
1916 return WINED3DERR_INVALIDCALL;
1919 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
1920 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
1922 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
1924 if(oldSrc == pStreamData &&
1925 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
1926 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
1927 TRACE("Application is setting the old values over, nothing to do\n");
1931 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
1933 This->updateStateBlock->streamStride[StreamNumber] = Stride;
1934 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
1937 /* Handle recording of state blocks */
1938 if (This->isRecordingState) {
1939 TRACE("Recording... not performing anything\n");
1940 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
1941 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
1945 if (pStreamData != NULL) {
1946 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
1947 IWineD3DBuffer_AddRef(pStreamData);
1949 if (oldSrc != NULL) {
1950 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
1951 IWineD3DBuffer_Release(oldSrc);
1954 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
1959 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
1960 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
1962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1964 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
1965 This->stateBlock->streamSource[StreamNumber],
1966 This->stateBlock->streamOffset[StreamNumber],
1967 This->stateBlock->streamStride[StreamNumber]);
1969 if (StreamNumber >= MAX_STREAMS) {
1970 WARN("Stream out of range %d\n", StreamNumber);
1971 return WINED3DERR_INVALIDCALL;
1973 *pStream = This->stateBlock->streamSource[StreamNumber];
1974 *pStride = This->stateBlock->streamStride[StreamNumber];
1976 *pOffset = This->stateBlock->streamOffset[StreamNumber];
1979 if (*pStream != NULL) {
1980 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
1985 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
1986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1987 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
1988 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
1990 /* Verify input at least in d3d9 this is invalid*/
1991 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
1992 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
1993 return WINED3DERR_INVALIDCALL;
1995 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
1996 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
1997 return WINED3DERR_INVALIDCALL;
2000 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2001 return WINED3DERR_INVALIDCALL;
2004 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2005 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2007 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2008 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2010 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2011 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2012 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2018 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2021 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2022 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2024 TRACE("(%p) : returning %d\n", This, *Divider);
2030 * Get / Set & Multiply Transform
2032 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2035 /* Most of this routine, comments included copied from ddraw tree initially: */
2036 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2038 /* Handle recording of state blocks */
2039 if (This->isRecordingState) {
2040 TRACE("Recording... not performing anything\n");
2041 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2042 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2047 * If the new matrix is the same as the current one,
2048 * we cut off any further processing. this seems to be a reasonable
2049 * optimization because as was noticed, some apps (warcraft3 for example)
2050 * tend towards setting the same matrix repeatedly for some reason.
2052 * From here on we assume that the new matrix is different, wherever it matters.
2054 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2055 TRACE("The app is setting the same matrix over again\n");
2058 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2062 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2063 where ViewMat = Camera space, WorldMat = world space.
2065 In OpenGL, camera and world space is combined into GL_MODELVIEW
2066 matrix. The Projection matrix stay projection matrix.
2069 /* Capture the times we can just ignore the change for now */
2070 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2071 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2072 /* Handled by the state manager */
2075 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2079 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2080 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2081 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2082 *pMatrix = This->stateBlock->transforms[State];
2086 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2087 const WINED3DMATRIX *mat = NULL;
2090 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2091 * below means it will be recorded in a state block change, but it
2092 * works regardless where it is recorded.
2093 * If this is found to be wrong, change to StateBlock.
2095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2096 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2098 if (State <= HIGHEST_TRANSFORMSTATE)
2100 mat = &This->updateStateBlock->transforms[State];
2102 FIXME("Unhandled transform state!!\n");
2105 multiply_matrix(&temp, mat, pMatrix);
2107 /* Apply change via set transform - will reapply to eg. lights this way */
2108 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2114 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2115 you can reference any indexes you want as long as that number max are enabled at any
2116 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2117 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2118 but when recording, just build a chain pretty much of commands to be replayed. */
2120 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2122 struct wined3d_light_info *object = NULL;
2123 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2127 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2129 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2133 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2134 return WINED3DERR_INVALIDCALL;
2137 switch(pLight->Type) {
2138 case WINED3DLIGHT_POINT:
2139 case WINED3DLIGHT_SPOT:
2140 case WINED3DLIGHT_PARALLELPOINT:
2141 case WINED3DLIGHT_GLSPOT:
2142 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2145 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2147 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2148 return WINED3DERR_INVALIDCALL;
2152 case WINED3DLIGHT_DIRECTIONAL:
2153 /* Ignores attenuation */
2157 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2158 return WINED3DERR_INVALIDCALL;
2161 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2163 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2164 if(object->OriginalIndex == Index) break;
2169 TRACE("Adding new light\n");
2170 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2172 ERR("Out of memory error when allocating a light\n");
2173 return E_OUTOFMEMORY;
2175 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2176 object->glIndex = -1;
2177 object->OriginalIndex = Index;
2180 /* Initialize the object */
2181 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,
2182 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2183 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2184 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2185 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2186 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2187 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2189 /* Save away the information */
2190 object->OriginalParms = *pLight;
2192 switch (pLight->Type) {
2193 case WINED3DLIGHT_POINT:
2195 object->lightPosn[0] = pLight->Position.x;
2196 object->lightPosn[1] = pLight->Position.y;
2197 object->lightPosn[2] = pLight->Position.z;
2198 object->lightPosn[3] = 1.0f;
2199 object->cutoff = 180.0f;
2203 case WINED3DLIGHT_DIRECTIONAL:
2205 object->lightPosn[0] = -pLight->Direction.x;
2206 object->lightPosn[1] = -pLight->Direction.y;
2207 object->lightPosn[2] = -pLight->Direction.z;
2208 object->lightPosn[3] = 0.0f;
2209 object->exponent = 0.0f;
2210 object->cutoff = 180.0f;
2213 case WINED3DLIGHT_SPOT:
2215 object->lightPosn[0] = pLight->Position.x;
2216 object->lightPosn[1] = pLight->Position.y;
2217 object->lightPosn[2] = pLight->Position.z;
2218 object->lightPosn[3] = 1.0f;
2221 object->lightDirn[0] = pLight->Direction.x;
2222 object->lightDirn[1] = pLight->Direction.y;
2223 object->lightDirn[2] = pLight->Direction.z;
2224 object->lightDirn[3] = 1.0f;
2227 * opengl-ish and d3d-ish spot lights use too different models for the
2228 * light "intensity" as a function of the angle towards the main light direction,
2229 * so we only can approximate very roughly.
2230 * however spot lights are rather rarely used in games (if ever used at all).
2231 * furthermore if still used, probably nobody pays attention to such details.
2233 if (pLight->Falloff == 0) {
2234 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2235 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2236 * will always be 1.0 for both of them, and we don't have to care for the
2237 * rest of the rather complex calculation
2239 object->exponent = 0.0f;
2241 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2242 if (rho < 0.0001f) rho = 0.0001f;
2243 object->exponent = -0.3f/logf(cosf(rho/2));
2245 if (object->exponent > 128.0f)
2247 object->exponent = 128.0f;
2249 object->cutoff = pLight->Phi*90/M_PI;
2255 FIXME("Unrecognized light type %d\n", pLight->Type);
2258 /* Update the live definitions if the light is currently assigned a glIndex */
2259 if (object->glIndex != -1 && !This->isRecordingState) {
2260 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2265 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2267 struct wined3d_light_info *lightInfo = NULL;
2268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2269 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2271 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2273 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2275 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2276 if(lightInfo->OriginalIndex == Index) break;
2280 if (lightInfo == NULL) {
2281 TRACE("Light information requested but light not defined\n");
2282 return WINED3DERR_INVALIDCALL;
2285 *pLight = lightInfo->OriginalParms;
2290 * Get / Set Light Enable
2291 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2293 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2295 struct wined3d_light_info *lightInfo = NULL;
2296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2297 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2299 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2301 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2303 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2304 if(lightInfo->OriginalIndex == Index) break;
2307 TRACE("Found light: %p\n", lightInfo);
2309 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2310 if (lightInfo == NULL) {
2312 TRACE("Light enabled requested but light not defined, so defining one!\n");
2313 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2315 /* Search for it again! Should be fairly quick as near head of list */
2316 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2318 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2319 if(lightInfo->OriginalIndex == Index) break;
2322 if (lightInfo == NULL) {
2323 FIXME("Adding default lights has failed dismally\n");
2324 return WINED3DERR_INVALIDCALL;
2329 if(lightInfo->glIndex != -1) {
2330 if(!This->isRecordingState) {
2331 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2334 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2335 lightInfo->glIndex = -1;
2337 TRACE("Light already disabled, nothing to do\n");
2339 lightInfo->enabled = FALSE;
2341 lightInfo->enabled = TRUE;
2342 if (lightInfo->glIndex != -1) {
2344 TRACE("Nothing to do as light was enabled\n");
2347 /* Find a free gl light */
2348 for(i = 0; i < This->maxConcurrentLights; i++) {
2349 if(This->updateStateBlock->activeLights[i] == NULL) {
2350 This->updateStateBlock->activeLights[i] = lightInfo;
2351 lightInfo->glIndex = i;
2355 if(lightInfo->glIndex == -1) {
2356 /* Our tests show that Windows returns D3D_OK in this situation, even with
2357 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2358 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2359 * as well for those lights.
2361 * TODO: Test how this affects rendering
2363 WARN("Too many concurrently active lights\n");
2367 /* i == lightInfo->glIndex */
2368 if(!This->isRecordingState) {
2369 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2377 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2379 struct wined3d_light_info *lightInfo = NULL;
2380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2382 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2383 TRACE("(%p) : for idx(%d)\n", This, Index);
2385 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2387 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2388 if(lightInfo->OriginalIndex == Index) break;
2392 if (lightInfo == NULL) {
2393 TRACE("Light enabled state requested but light not defined\n");
2394 return WINED3DERR_INVALIDCALL;
2396 /* true is 128 according to SetLightEnable */
2397 *pEnable = lightInfo->enabled ? 128 : 0;
2402 * Get / Set Clip Planes
2404 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2406 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2408 /* Validate Index */
2409 if (Index >= This->adapter->gl_info.limits.clipplanes)
2411 TRACE("Application has requested clipplane this device doesn't support\n");
2412 return WINED3DERR_INVALIDCALL;
2415 This->updateStateBlock->changed.clipplane |= 1 << Index;
2417 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2418 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2419 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2420 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2421 TRACE("Application is setting old values over, nothing to do\n");
2425 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2426 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2427 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2428 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2430 /* Handle recording of state blocks */
2431 if (This->isRecordingState) {
2432 TRACE("Recording... not performing anything\n");
2436 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2441 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2443 TRACE("(%p) : for idx %d\n", This, Index);
2445 /* Validate Index */
2446 if (Index >= This->adapter->gl_info.limits.clipplanes)
2448 TRACE("Application has requested clipplane this device doesn't support\n");
2449 return WINED3DERR_INVALIDCALL;
2452 pPlane[0] = This->stateBlock->clipplane[Index][0];
2453 pPlane[1] = This->stateBlock->clipplane[Index][1];
2454 pPlane[2] = This->stateBlock->clipplane[Index][2];
2455 pPlane[3] = This->stateBlock->clipplane[Index][3];
2460 * Get / Set Clip Plane Status
2461 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2463 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2465 FIXME("(%p) : stub\n", This);
2466 if (NULL == pClipStatus) {
2467 return WINED3DERR_INVALIDCALL;
2469 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2470 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2474 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2476 FIXME("(%p) : stub\n", This);
2477 if (NULL == pClipStatus) {
2478 return WINED3DERR_INVALIDCALL;
2480 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2481 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2486 * Get / Set Material
2488 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2491 This->updateStateBlock->changed.material = TRUE;
2492 This->updateStateBlock->material = *pMaterial;
2494 /* Handle recording of state blocks */
2495 if (This->isRecordingState) {
2496 TRACE("Recording... not performing anything\n");
2500 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2504 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2506 *pMaterial = This->updateStateBlock->material;
2507 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2508 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2509 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2510 pMaterial->Ambient.b, pMaterial->Ambient.a);
2511 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2512 pMaterial->Specular.b, pMaterial->Specular.a);
2513 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2514 pMaterial->Emissive.b, pMaterial->Emissive.a);
2515 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2523 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2524 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2527 IWineD3DBuffer *oldIdxs;
2529 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2530 oldIdxs = This->updateStateBlock->pIndexData;
2532 This->updateStateBlock->changed.indices = TRUE;
2533 This->updateStateBlock->pIndexData = pIndexData;
2534 This->updateStateBlock->IndexFmt = fmt;
2536 /* Handle recording of state blocks */
2537 if (This->isRecordingState) {
2538 TRACE("Recording... not performing anything\n");
2539 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2540 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2544 if(oldIdxs != pIndexData) {
2545 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2547 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2548 IWineD3DBuffer_AddRef(pIndexData);
2551 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2552 IWineD3DBuffer_Release(oldIdxs);
2559 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2563 *ppIndexData = This->stateBlock->pIndexData;
2565 /* up ref count on ppindexdata */
2567 IWineD3DBuffer_AddRef(*ppIndexData);
2568 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2570 TRACE("(%p) No index data set\n", This);
2572 TRACE("Returning %p\n", *ppIndexData);
2577 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2578 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2580 TRACE("(%p)->(%d)\n", This, BaseIndex);
2582 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2583 TRACE("Application is setting the old value over, nothing to do\n");
2587 This->updateStateBlock->baseVertexIndex = BaseIndex;
2589 if (This->isRecordingState) {
2590 TRACE("Recording... not performing anything\n");
2593 /* The base vertex index affects the stream sources */
2594 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2598 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2600 TRACE("(%p) : base_index %p\n", This, base_index);
2602 *base_index = This->stateBlock->baseVertexIndex;
2604 TRACE("Returning %u\n", *base_index);
2610 * Get / Set Viewports
2612 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2615 TRACE("(%p)\n", This);
2616 This->updateStateBlock->changed.viewport = TRUE;
2617 This->updateStateBlock->viewport = *pViewport;
2619 /* Handle recording of state blocks */
2620 if (This->isRecordingState) {
2621 TRACE("Recording... not performing anything\n");
2625 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2626 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2628 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2633 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2635 TRACE("(%p)\n", This);
2636 *pViewport = This->stateBlock->viewport;
2641 * Get / Set Render States
2642 * TODO: Verify against dx9 definitions
2644 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2647 DWORD oldValue = This->stateBlock->renderState[State];
2649 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2651 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2652 This->updateStateBlock->renderState[State] = Value;
2654 /* Handle recording of state blocks */
2655 if (This->isRecordingState) {
2656 TRACE("Recording... not performing anything\n");
2660 /* Compared here and not before the assignment to allow proper stateblock recording */
2661 if(Value == oldValue) {
2662 TRACE("Application is setting the old value over, nothing to do\n");
2664 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2670 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2672 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2673 *pValue = This->stateBlock->renderState[State];
2678 * Get / Set Sampler States
2679 * TODO: Verify against dx9 definitions
2682 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2686 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2687 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2689 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2690 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2693 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2694 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2695 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2698 * SetSampler is designed to allow for more than the standard up to 8 textures
2699 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2700 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2702 * http://developer.nvidia.com/object/General_FAQ.html#t6
2704 * There are two new settings for GForce
2706 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2707 * and the texture one:
2708 * GL_MAX_TEXTURE_COORDS_ARB.
2709 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2712 oldValue = This->stateBlock->samplerState[Sampler][Type];
2713 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2714 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2716 /* Handle recording of state blocks */
2717 if (This->isRecordingState) {
2718 TRACE("Recording... not performing anything\n");
2722 if(oldValue == Value) {
2723 TRACE("Application is setting the old value over, nothing to do\n");
2727 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2732 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2735 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2736 This, Sampler, debug_d3dsamplerstate(Type), Type);
2738 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2739 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2742 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2743 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2744 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2746 *Value = This->stateBlock->samplerState[Sampler][Type];
2747 TRACE("(%p) : Returning %#x\n", This, *Value);
2752 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2755 This->updateStateBlock->changed.scissorRect = TRUE;
2756 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2757 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2760 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2762 if(This->isRecordingState) {
2763 TRACE("Recording... not performing anything\n");
2767 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2772 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2775 *pRect = This->updateStateBlock->scissorRect;
2776 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2780 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2782 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2784 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2786 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2787 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2789 This->updateStateBlock->vertexDecl = pDecl;
2790 This->updateStateBlock->changed.vertexDecl = TRUE;
2792 if (This->isRecordingState) {
2793 TRACE("Recording... not performing anything\n");
2795 } else if(pDecl == oldDecl) {
2796 /* Checked after the assignment to allow proper stateblock recording */
2797 TRACE("Application is setting the old declaration over, nothing to do\n");
2801 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2805 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2808 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2810 *ppDecl = This->stateBlock->vertexDecl;
2811 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2815 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2817 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2819 This->updateStateBlock->vertexShader = pShader;
2820 This->updateStateBlock->changed.vertexShader = TRUE;
2822 if (This->isRecordingState) {
2823 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2824 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2825 TRACE("Recording... not performing anything\n");
2827 } else if(oldShader == pShader) {
2828 /* Checked here to allow proper stateblock recording */
2829 TRACE("App is setting the old shader over, nothing to do\n");
2833 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2834 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2835 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2837 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2842 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2845 if (NULL == ppShader) {
2846 return WINED3DERR_INVALIDCALL;
2848 *ppShader = This->stateBlock->vertexShader;
2849 if( NULL != *ppShader)
2850 IWineD3DVertexShader_AddRef(*ppShader);
2852 TRACE("(%p) : returning %p\n", This, *ppShader);
2856 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2857 IWineD3DDevice *iface,
2859 CONST BOOL *srcData,
2862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2863 unsigned int i, cnt = min(count, MAX_CONST_B - start);
2865 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2866 iface, srcData, start, count);
2868 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
2870 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2871 for (i = 0; i < cnt; i++)
2872 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2874 for (i = start; i < cnt + start; ++i) {
2875 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
2878 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2883 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2884 IWineD3DDevice *iface,
2889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2890 int cnt = min(count, MAX_CONST_B - start);
2892 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2893 iface, dstData, start, count);
2895 if (dstData == NULL || cnt < 0)
2896 return WINED3DERR_INVALIDCALL;
2898 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2902 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2903 IWineD3DDevice *iface,
2908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2909 unsigned int i, cnt = min(count, MAX_CONST_I - start);
2911 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2912 iface, srcData, start, count);
2914 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
2916 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2917 for (i = 0; i < cnt; i++)
2918 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2919 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2921 for (i = start; i < cnt + start; ++i) {
2922 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
2925 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2930 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2931 IWineD3DDevice *iface,
2936 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2937 int cnt = min(count, MAX_CONST_I - start);
2939 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2940 iface, dstData, start, count);
2942 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2943 return WINED3DERR_INVALIDCALL;
2945 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
2949 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
2950 IWineD3DDevice *iface,
2952 CONST float *srcData,
2955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2958 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2959 iface, srcData, start, count);
2961 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
2962 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
2963 return WINED3DERR_INVALIDCALL;
2965 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
2967 for (i = 0; i < count; i++)
2968 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
2969 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2972 if (!This->isRecordingState)
2974 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
2975 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2978 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
2979 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
2984 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
2985 IWineD3DDevice *iface,
2990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2991 int cnt = min(count, This->d3d_vshader_constantF - start);
2993 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2994 iface, dstData, start, count);
2996 if (dstData == NULL || cnt < 0)
2997 return WINED3DERR_INVALIDCALL;
2999 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3003 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3005 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3007 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3011 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3013 DWORD i = This->rev_tex_unit_map[unit];
3014 DWORD j = This->texUnitMap[stage];
3016 This->texUnitMap[stage] = unit;
3017 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3019 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3022 This->rev_tex_unit_map[unit] = stage;
3023 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3025 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3029 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3032 This->fixed_function_usage_map = 0;
3033 for (i = 0; i < MAX_TEXTURES; ++i) {
3034 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3035 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3036 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3037 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3038 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3039 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3040 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3041 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3043 if (color_op == WINED3DTOP_DISABLE) {
3044 /* Not used, and disable higher stages */
3048 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3049 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3050 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3051 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3052 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3053 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3054 This->fixed_function_usage_map |= (1 << i);
3057 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3058 This->fixed_function_usage_map |= (1 << (i + 1));
3063 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3064 unsigned int i, tex;
3067 device_update_fixed_function_usage_map(This);
3068 ffu_map = This->fixed_function_usage_map;
3070 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3071 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3072 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3074 if (!(ffu_map & 1)) continue;
3076 if (This->texUnitMap[i] != i) {
3077 device_map_stage(This, i, i);
3078 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3079 markTextureStagesDirty(This, i);
3085 /* Now work out the mapping */
3087 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3089 if (!(ffu_map & 1)) continue;
3091 if (This->texUnitMap[i] != tex) {
3092 device_map_stage(This, i, tex);
3093 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3094 markTextureStagesDirty(This, i);
3101 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3102 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3103 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3106 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3107 if (sampler_type[i] && This->texUnitMap[i] != i)
3109 device_map_stage(This, i, i);
3110 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3111 if (i < MAX_TEXTURES) {
3112 markTextureStagesDirty(This, i);
3118 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3119 const DWORD *vshader_sampler_tokens, DWORD unit)
3121 DWORD current_mapping = This->rev_tex_unit_map[unit];
3123 /* Not currently used */
3124 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3126 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3127 /* Used by a fragment sampler */
3129 if (!pshader_sampler_tokens) {
3130 /* No pixel shader, check fixed function */
3131 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3134 /* Pixel shader, check the shader's sampler map */
3135 return !pshader_sampler_tokens[current_mapping];
3138 /* Used by a vertex sampler */
3139 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3142 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3143 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3144 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3145 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3146 int start = min(MAX_COMBINED_SAMPLERS, This->adapter->gl_info.limits.combined_samplers) - 1;
3150 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3152 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3153 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3154 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3157 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3158 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3159 if (vshader_sampler_type[i])
3161 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3163 /* Already mapped somewhere */
3167 while (start >= 0) {
3168 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3170 device_map_stage(This, vsampler_idx, start);
3171 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3183 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3184 BOOL vs = use_vs(This->stateBlock);
3185 BOOL ps = use_ps(This->stateBlock);
3188 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3189 * that would be really messy and require shader recompilation
3190 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3191 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3194 device_map_psamplers(This);
3196 device_map_fixed_function_samplers(This);
3200 device_map_vsamplers(This, ps);
3204 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3206 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3207 This->updateStateBlock->pixelShader = pShader;
3208 This->updateStateBlock->changed.pixelShader = TRUE;
3210 /* Handle recording of state blocks */
3211 if (This->isRecordingState) {
3212 TRACE("Recording... not performing anything\n");
3215 if (This->isRecordingState) {
3216 TRACE("Recording... not performing anything\n");
3217 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3218 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3222 if(pShader == oldShader) {
3223 TRACE("App is setting the old pixel shader over, nothing to do\n");
3227 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3228 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3230 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3231 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3236 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3239 if (NULL == ppShader) {
3240 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3241 return WINED3DERR_INVALIDCALL;
3244 *ppShader = This->stateBlock->pixelShader;
3245 if (NULL != *ppShader) {
3246 IWineD3DPixelShader_AddRef(*ppShader);
3248 TRACE("(%p) : returning %p\n", This, *ppShader);
3252 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3253 IWineD3DDevice *iface,
3255 CONST BOOL *srcData,
3258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3259 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3261 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3262 iface, srcData, start, count);
3264 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3266 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3267 for (i = 0; i < cnt; i++)
3268 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3270 for (i = start; i < cnt + start; ++i) {
3271 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3274 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3279 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3280 IWineD3DDevice *iface,
3285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3286 int cnt = min(count, MAX_CONST_B - start);
3288 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3289 iface, dstData, start, count);
3291 if (dstData == NULL || cnt < 0)
3292 return WINED3DERR_INVALIDCALL;
3294 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3298 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3299 IWineD3DDevice *iface,
3304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3305 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3307 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3308 iface, srcData, start, count);
3310 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3312 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3313 for (i = 0; i < cnt; i++)
3314 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3315 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3317 for (i = start; i < cnt + start; ++i) {
3318 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3321 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3326 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3327 IWineD3DDevice *iface,
3332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3333 int cnt = min(count, MAX_CONST_I - start);
3335 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3336 iface, dstData, start, count);
3338 if (dstData == NULL || cnt < 0)
3339 return WINED3DERR_INVALIDCALL;
3341 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3345 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3346 IWineD3DDevice *iface,
3348 CONST float *srcData,
3351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3354 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3355 iface, srcData, start, count);
3357 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3358 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3359 return WINED3DERR_INVALIDCALL;
3361 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3363 for (i = 0; i < count; i++)
3364 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3365 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3368 if (!This->isRecordingState)
3370 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3374 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3375 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3380 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3381 IWineD3DDevice *iface,
3386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3387 int cnt = min(count, This->d3d_pshader_constantF - start);
3389 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3390 iface, dstData, start, count);
3392 if (dstData == NULL || cnt < 0)
3393 return WINED3DERR_INVALIDCALL;
3395 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3399 /* Context activation is done by the caller. */
3400 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3401 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3402 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3405 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3406 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3409 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3413 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3415 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3418 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3420 ERR("Source has no position mask\n");
3421 return WINED3DERR_INVALIDCALL;
3424 /* We might access VBOs from this code, so hold the lock */
3427 if (dest->resource.allocatedMemory == NULL) {
3428 buffer_get_sysmem(dest);
3431 /* Get a pointer into the destination vbo(create one if none exists) and
3432 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3434 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3436 dest->flags |= WINED3D_BUFFER_CREATEBO;
3437 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3440 if (dest->buffer_object)
3442 unsigned char extrabytes = 0;
3443 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3444 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3445 * this may write 4 extra bytes beyond the area that should be written
3447 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3448 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3449 if(!dest_conv_addr) {
3450 ERR("Out of memory\n");
3451 /* Continue without storing converted vertices */
3453 dest_conv = dest_conv_addr;
3457 * a) WINED3DRS_CLIPPING is enabled
3458 * b) WINED3DVOP_CLIP is passed
3460 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3461 static BOOL warned = FALSE;
3463 * The clipping code is not quite correct. Some things need
3464 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3465 * so disable clipping for now.
3466 * (The graphics in Half-Life are broken, and my processvertices
3467 * test crashes with IDirect3DDevice3)
3473 FIXME("Clipping is broken and disabled for now\n");
3475 } else doClip = FALSE;
3476 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3478 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3481 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3482 WINED3DTS_PROJECTION,
3484 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3485 WINED3DTS_WORLDMATRIX(0),
3488 TRACE("View mat:\n");
3489 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);
3490 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);
3491 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);
3492 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);
3494 TRACE("Proj mat:\n");
3495 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);
3496 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);
3497 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);
3498 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);
3500 TRACE("World mat:\n");
3501 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);
3502 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);
3503 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);
3504 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);
3506 /* Get the viewport */
3507 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3508 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3509 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3511 multiply_matrix(&mat,&view_mat,&world_mat);
3512 multiply_matrix(&mat,&proj_mat,&mat);
3514 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3516 for (i = 0; i < dwCount; i+= 1) {
3517 unsigned int tex_index;
3519 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3520 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3521 /* The position first */
3522 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3523 const float *p = (const float *)(element->data + i * element->stride);
3525 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3527 /* Multiplication with world, view and projection matrix */
3528 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);
3529 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);
3530 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);
3531 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);
3533 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3535 /* WARNING: The following things are taken from d3d7 and were not yet checked
3536 * against d3d8 or d3d9!
3539 /* Clipping conditions: From msdn
3541 * A vertex is clipped if it does not match the following requirements
3545 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3547 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3548 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3553 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3554 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3557 /* "Normal" viewport transformation (not clipped)
3558 * 1) The values are divided by rhw
3559 * 2) The y axis is negative, so multiply it with -1
3560 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3561 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3562 * 4) Multiply x with Width/2 and add Width/2
3563 * 5) The same for the height
3564 * 6) Add the viewpoint X and Y to the 2D coordinates and
3565 * The minimum Z value to z
3566 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3568 * Well, basically it's simply a linear transformation into viewport
3580 z *= vp.MaxZ - vp.MinZ;
3582 x += vp.Width / 2 + vp.X;
3583 y += vp.Height / 2 + vp.Y;
3588 /* That vertex got clipped
3589 * Contrary to OpenGL it is not dropped completely, it just
3590 * undergoes a different calculation.
3592 TRACE("Vertex got clipped\n");
3599 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3600 * outside of the main vertex buffer memory. That needs some more
3605 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3608 ( (float *) dest_ptr)[0] = x;
3609 ( (float *) dest_ptr)[1] = y;
3610 ( (float *) dest_ptr)[2] = z;
3611 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3613 dest_ptr += 3 * sizeof(float);
3615 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3616 dest_ptr += sizeof(float);
3621 ( (float *) dest_conv)[0] = x * w;
3622 ( (float *) dest_conv)[1] = y * w;
3623 ( (float *) dest_conv)[2] = z * w;
3624 ( (float *) dest_conv)[3] = w;
3626 dest_conv += 3 * sizeof(float);
3628 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3629 dest_conv += sizeof(float);
3633 if (DestFVF & WINED3DFVF_PSIZE) {
3634 dest_ptr += sizeof(DWORD);
3635 if(dest_conv) dest_conv += sizeof(DWORD);
3637 if (DestFVF & WINED3DFVF_NORMAL) {
3638 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3639 const float *normal = (const float *)(element->data + i * element->stride);
3640 /* AFAIK this should go into the lighting information */
3641 FIXME("Didn't expect the destination to have a normal\n");
3642 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3644 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3648 if (DestFVF & WINED3DFVF_DIFFUSE) {
3649 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3650 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3651 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3653 static BOOL warned = FALSE;
3656 ERR("No diffuse color in source, but destination has one\n");
3660 *( (DWORD *) dest_ptr) = 0xffffffff;
3661 dest_ptr += sizeof(DWORD);
3664 *( (DWORD *) dest_conv) = 0xffffffff;
3665 dest_conv += sizeof(DWORD);
3669 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3671 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3672 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3673 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3674 dest_conv += sizeof(DWORD);
3679 if (DestFVF & WINED3DFVF_SPECULAR)
3681 /* What's the color value in the feedback buffer? */
3682 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3683 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3684 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3686 static BOOL warned = FALSE;
3689 ERR("No specular color in source, but destination has one\n");
3693 *( (DWORD *) dest_ptr) = 0xFF000000;
3694 dest_ptr += sizeof(DWORD);
3697 *( (DWORD *) dest_conv) = 0xFF000000;
3698 dest_conv += sizeof(DWORD);
3702 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3704 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3705 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3706 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3707 dest_conv += sizeof(DWORD);
3712 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3713 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3714 const float *tex_coord = (const float *)(element->data + i * element->stride);
3715 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3717 ERR("No source texture, but destination requests one\n");
3718 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3719 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3722 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3724 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3731 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3732 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3733 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3734 dwCount * get_flexible_vertex_size(DestFVF),
3736 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3737 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3744 #undef copy_and_next
3746 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3747 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3751 struct wined3d_stream_info stream_info;
3752 struct wined3d_context *context;
3753 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3756 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3759 ERR("Output vertex declaration not implemented yet\n");
3762 /* Need any context to write to the vbo. */
3763 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
3765 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3766 * control the streamIsUP flag, thus restore it afterwards.
3768 This->stateBlock->streamIsUP = FALSE;
3769 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3770 This->stateBlock->streamIsUP = streamWasUP;
3772 if(vbo || SrcStartIndex) {
3774 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3775 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3777 * Also get the start index in, but only loop over all elements if there's something to add at all.
3779 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3781 struct wined3d_stream_info_element *e;
3783 if (!(stream_info.use_map & (1 << i))) continue;
3785 e = &stream_info.elements[i];
3786 if (e->buffer_object)
3788 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3789 e->buffer_object = 0;
3790 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3792 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3793 vb->buffer_object = 0;
3796 if (e->data) e->data += e->stride * SrcStartIndex;
3800 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3801 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3803 context_release(context);
3809 * Get / Set Texture Stage States
3810 * TODO: Verify against dx9 definitions
3812 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3813 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3814 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3816 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3818 if (Stage >= MAX_TEXTURES) {
3819 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
3823 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3824 This->updateStateBlock->textureState[Stage][Type] = Value;
3826 if (This->isRecordingState) {
3827 TRACE("Recording... not performing anything\n");
3831 /* Checked after the assignments to allow proper stateblock recording */
3832 if(oldValue == Value) {
3833 TRACE("App is setting the old value over, nothing to do\n");
3837 if(Stage > This->stateBlock->lowest_disabled_stage &&
3838 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3839 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3840 * Changes in other states are important on disabled stages too
3845 if(Type == WINED3DTSS_COLOROP) {
3848 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3849 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3850 * they have to be disabled
3852 * The current stage is dirtified below.
3854 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3855 TRACE("Additionally dirtifying stage %u\n", i);
3856 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3858 This->stateBlock->lowest_disabled_stage = Stage;
3859 TRACE("New lowest disabled: %u\n", Stage);
3860 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3861 /* Previously disabled stage enabled. Stages above it may need enabling
3862 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3863 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3865 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3868 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
3870 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3873 TRACE("Additionally dirtifying stage %u due to enable\n", i);
3874 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3876 This->stateBlock->lowest_disabled_stage = i;
3877 TRACE("New lowest disabled: %u\n", i);
3881 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3886 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3888 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3889 *pValue = This->updateStateBlock->textureState[Stage][Type];
3896 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
3897 DWORD stage, IWineD3DBaseTexture *texture)
3899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3900 IWineD3DBaseTexture *prev;
3902 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
3904 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
3905 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3907 /* Windows accepts overflowing this array... we do not. */
3908 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
3910 WARN("Ignoring invalid stage %u.\n", stage);
3914 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
3915 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
3917 WARN("Rejecting attempt to set scratch texture.\n");
3918 return WINED3DERR_INVALIDCALL;
3921 This->updateStateBlock->changed.textures |= 1 << stage;
3923 prev = This->updateStateBlock->textures[stage];
3924 TRACE("Previous texture %p.\n", prev);
3926 if (texture == prev)
3928 TRACE("App is setting the same texture again, nothing to do.\n");
3932 TRACE("Setting new texture to %p.\n", texture);
3933 This->updateStateBlock->textures[stage] = texture;
3935 if (This->isRecordingState)
3937 TRACE("Recording... not performing anything\n");
3939 if (texture) IWineD3DBaseTexture_AddRef(texture);
3940 if (prev) IWineD3DBaseTexture_Release(prev);
3947 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
3948 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
3949 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
3951 IWineD3DBaseTexture_AddRef(texture);
3953 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
3955 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3958 if (!prev && stage < MAX_TEXTURES)
3960 /* The source arguments for color and alpha ops have different
3961 * meanings when a NULL texture is bound, so the COLOROP and
3962 * ALPHAOP have to be dirtified. */
3963 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
3964 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
3967 if (bind_count == 1) t->baseTexture.sampler = stage;
3972 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
3973 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
3975 IWineD3DBaseTexture_Release(prev);
3977 if (!texture && stage < MAX_TEXTURES)
3979 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
3980 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
3983 if (bind_count && t->baseTexture.sampler == stage)
3987 /* Search for other stages the texture is bound to. Shouldn't
3988 * happen if applications bind textures to a single stage only. */
3989 TRACE("Searching for other stages the texture is bound to.\n");
3990 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
3992 if (This->updateStateBlock->textures[i] == prev)
3994 TRACE("Texture is also bound to stage %u.\n", i);
3995 t->baseTexture.sampler = i;
4002 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4007 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4010 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4012 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4013 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4016 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4017 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4018 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4021 *ppTexture=This->stateBlock->textures[Stage];
4023 IWineD3DBaseTexture_AddRef(*ppTexture);
4025 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4033 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4034 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4036 IWineD3DSwapChain *swapchain;
4039 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4040 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4042 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4045 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4049 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4050 IWineD3DSwapChain_Release(swapchain);
4053 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4060 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4062 WARN("(%p) : stub, calling idirect3d for now\n", This);
4063 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4066 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4068 IWineD3DSwapChain *swapChain;
4071 if(iSwapChain > 0) {
4072 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4073 if (hr == WINED3D_OK) {
4074 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4075 IWineD3DSwapChain_Release(swapChain);
4077 FIXME("(%p) Error getting display mode\n", This);
4080 /* Don't read the real display mode,
4081 but return the stored mode instead. X11 can't change the color
4082 depth, and some apps are pretty angry if they SetDisplayMode from
4083 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4085 Also don't relay to the swapchain because with ddraw it's possible
4086 that there isn't a swapchain at all */
4087 pMode->Width = This->ddraw_width;
4088 pMode->Height = This->ddraw_height;
4089 pMode->Format = This->ddraw_format;
4090 pMode->RefreshRate = 0;
4098 * Stateblock related functions
4101 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4103 IWineD3DStateBlock *stateblock;
4106 TRACE("(%p)\n", This);
4108 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4110 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4111 if (FAILED(hr)) return hr;
4113 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4114 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4115 This->isRecordingState = TRUE;
4117 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4122 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4124 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4126 if (!This->isRecordingState) {
4127 WARN("(%p) not recording! returning error\n", This);
4128 *ppStateBlock = NULL;
4129 return WINED3DERR_INVALIDCALL;
4132 stateblock_init_contained_states(object);
4134 *ppStateBlock = (IWineD3DStateBlock*) object;
4135 This->isRecordingState = FALSE;
4136 This->updateStateBlock = This->stateBlock;
4137 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4138 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4139 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4144 * Scene related functions
4146 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4147 /* At the moment we have no need for any functionality at the beginning
4149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4150 TRACE("(%p)\n", This);
4153 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4154 return WINED3DERR_INVALIDCALL;
4156 This->inScene = TRUE;
4160 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4163 struct wined3d_context *context;
4165 TRACE("(%p)\n", This);
4167 if(!This->inScene) {
4168 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4169 return WINED3DERR_INVALIDCALL;
4172 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4173 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4175 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4177 context_release(context);
4179 This->inScene = FALSE;
4183 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4184 const RECT *pSourceRect, const RECT *pDestRect,
4185 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4187 IWineD3DSwapChain *swapChain = NULL;
4189 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4191 TRACE("iface %p.\n", iface);
4193 for(i = 0 ; i < swapchains ; i ++) {
4195 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4196 TRACE("presentinng chain %d, %p\n", i, swapChain);
4197 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4198 IWineD3DSwapChain_Release(swapChain);
4204 /* Not called from the VTable (internal subroutine) */
4205 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4206 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4207 float Z, DWORD Stencil) {
4208 GLbitfield glMask = 0;
4210 WINED3DRECT curRect;
4212 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4213 UINT drawable_width, drawable_height;
4214 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4215 IWineD3DSwapChainImpl *swapchain = NULL;
4216 struct wined3d_context *context;
4218 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4219 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4220 * for the cleared parts, and the untouched parts.
4222 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4223 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4224 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4225 * checking all this if the dest surface is in the drawable anyway.
4227 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4229 if(vp->X != 0 || vp->Y != 0 ||
4230 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4231 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4234 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4235 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4236 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4237 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4238 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4241 if(Count > 0 && pRects && (
4242 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4243 pRects[0].x2 < target->currentDesc.Width ||
4244 pRects[0].y2 < target->currentDesc.Height)) {
4245 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4252 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4254 target->get_drawable_size(context, &drawable_width, &drawable_height);
4258 /* Only set the values up once, as they are not changing */
4259 if (Flags & WINED3DCLEAR_STENCIL) {
4260 glClearStencil(Stencil);
4261 checkGLcall("glClearStencil");
4262 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4263 glStencilMask(0xFFFFFFFF);
4266 if (Flags & WINED3DCLEAR_ZBUFFER) {
4267 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4268 glDepthMask(GL_TRUE);
4270 checkGLcall("glClearDepth");
4271 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4272 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4274 if (vp->X != 0 || vp->Y != 0 ||
4275 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4276 surface_load_ds_location(This->stencilBufferTarget, context, location);
4278 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4279 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4280 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4281 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4282 surface_load_ds_location(This->stencilBufferTarget, context, location);
4284 else if (Count > 0 && pRects && (
4285 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4286 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4287 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4288 surface_load_ds_location(This->stencilBufferTarget, context, location);
4292 if (Flags & WINED3DCLEAR_TARGET) {
4293 TRACE("Clearing screen with glClear to color %x\n", Color);
4294 glClearColor(D3DCOLOR_R(Color),
4298 checkGLcall("glClearColor");
4300 /* Clear ALL colors! */
4301 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4302 glMask = glMask | GL_COLOR_BUFFER_BIT;
4305 vp_rect.left = vp->X;
4306 vp_rect.top = vp->Y;
4307 vp_rect.right = vp->X + vp->Width;
4308 vp_rect.bottom = vp->Y + vp->Height;
4309 if (!(Count > 0 && pRects)) {
4310 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4311 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4313 if (context->render_offscreen)
4315 glScissor(vp_rect.left, vp_rect.top,
4316 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4318 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4319 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4321 checkGLcall("glScissor");
4323 checkGLcall("glClear");
4325 /* Now process each rect in turn */
4326 for (i = 0; i < Count; i++) {
4327 /* Note gl uses lower left, width/height */
4328 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4329 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4330 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4332 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4333 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4334 curRect.x1, (target->currentDesc.Height - curRect.y2),
4335 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4337 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4338 * The rectangle is not cleared, no error is returned, but further rectanlges are
4339 * still cleared if they are valid
4341 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4342 TRACE("Rectangle with negative dimensions, ignoring\n");
4346 if (context->render_offscreen)
4348 glScissor(curRect.x1, curRect.y1,
4349 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4351 glScissor(curRect.x1, drawable_height - curRect.y2,
4352 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4354 checkGLcall("glScissor");
4357 checkGLcall("glClear");
4361 /* Restore the old values (why..?) */
4362 if (Flags & WINED3DCLEAR_STENCIL) {
4363 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4365 if (Flags & WINED3DCLEAR_TARGET) {
4366 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4367 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4368 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4369 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4370 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4372 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4373 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4375 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4377 if (Flags & WINED3DCLEAR_ZBUFFER) {
4378 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4379 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4380 surface_modify_ds_location(This->stencilBufferTarget, location);
4385 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
4386 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
4389 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
4392 context_release(context);
4397 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4398 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4400 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4402 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4403 Count, pRects, Flags, Color, Z, Stencil);
4405 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4406 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4407 /* TODO: What about depth stencil buffers without stencil bits? */
4408 return WINED3DERR_INVALIDCALL;
4411 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4418 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4419 WINED3DPRIMITIVETYPE primitive_type)
4421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4423 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4425 This->updateStateBlock->changed.primitive_type = TRUE;
4426 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4429 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4430 WINED3DPRIMITIVETYPE *primitive_type)
4432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4434 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4436 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4438 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4441 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4445 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4447 if(!This->stateBlock->vertexDecl) {
4448 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4449 return WINED3DERR_INVALIDCALL;
4452 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4453 if(This->stateBlock->streamIsUP) {
4454 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4455 This->stateBlock->streamIsUP = FALSE;
4458 if(This->stateBlock->loadBaseVertexIndex != 0) {
4459 This->stateBlock->loadBaseVertexIndex = 0;
4460 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4462 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4463 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4467 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4471 IWineD3DBuffer *pIB;
4474 pIB = This->stateBlock->pIndexData;
4476 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4477 * without an index buffer set. (The first time at least...)
4478 * D3D8 simply dies, but I doubt it can do much harm to return
4479 * D3DERR_INVALIDCALL there as well. */
4480 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4481 return WINED3DERR_INVALIDCALL;
4484 if(!This->stateBlock->vertexDecl) {
4485 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4486 return WINED3DERR_INVALIDCALL;
4489 if(This->stateBlock->streamIsUP) {
4490 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4491 This->stateBlock->streamIsUP = FALSE;
4493 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4495 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4497 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4503 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4504 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4505 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4508 drawPrimitive(iface, index_count, startIndex, idxStride,
4509 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4514 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4515 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4520 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4521 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4523 if(!This->stateBlock->vertexDecl) {
4524 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4525 return WINED3DERR_INVALIDCALL;
4528 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4529 vb = This->stateBlock->streamSource[0];
4530 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4531 if (vb) IWineD3DBuffer_Release(vb);
4532 This->stateBlock->streamOffset[0] = 0;
4533 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4534 This->stateBlock->streamIsUP = TRUE;
4535 This->stateBlock->loadBaseVertexIndex = 0;
4537 /* TODO: Only mark dirty if drawing from a different UP address */
4538 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4540 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4542 /* MSDN specifies stream zero settings must be set to NULL */
4543 This->stateBlock->streamStride[0] = 0;
4544 This->stateBlock->streamSource[0] = NULL;
4546 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4547 * the new stream sources or use UP drawing again
4552 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4553 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4554 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4561 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4562 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4564 if(!This->stateBlock->vertexDecl) {
4565 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4566 return WINED3DERR_INVALIDCALL;
4569 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4575 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4576 vb = This->stateBlock->streamSource[0];
4577 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4578 if (vb) IWineD3DBuffer_Release(vb);
4579 This->stateBlock->streamIsUP = TRUE;
4580 This->stateBlock->streamOffset[0] = 0;
4581 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4583 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4584 This->stateBlock->baseVertexIndex = 0;
4585 This->stateBlock->loadBaseVertexIndex = 0;
4586 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4587 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4588 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4590 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4592 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4593 This->stateBlock->streamSource[0] = NULL;
4594 This->stateBlock->streamStride[0] = 0;
4595 ib = This->stateBlock->pIndexData;
4597 IWineD3DBuffer_Release(ib);
4598 This->stateBlock->pIndexData = NULL;
4600 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4601 * SetStreamSource to specify a vertex buffer
4607 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4608 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4612 /* Mark the state dirty until we have nicer tracking
4613 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4616 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4617 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4618 This->stateBlock->baseVertexIndex = 0;
4619 This->up_strided = DrawPrimStrideData;
4620 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4621 This->up_strided = NULL;
4625 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4626 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4627 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4630 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4632 /* Mark the state dirty until we have nicer tracking
4633 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4636 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4637 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4638 This->stateBlock->streamIsUP = TRUE;
4639 This->stateBlock->baseVertexIndex = 0;
4640 This->up_strided = DrawPrimStrideData;
4641 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4642 This->up_strided = NULL;
4646 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4647 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4648 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4650 WINED3DLOCKED_BOX src;
4651 WINED3DLOCKED_BOX dst;
4654 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4655 iface, pSourceVolume, pDestinationVolume);
4657 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4658 * dirtification to improve loading performance.
4660 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4661 if(FAILED(hr)) return hr;
4662 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4664 IWineD3DVolume_UnlockBox(pSourceVolume);
4668 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4670 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4672 IWineD3DVolume_UnlockBox(pSourceVolume);
4674 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4679 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4680 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4682 unsigned int level_count, i;
4683 WINED3DRESOURCETYPE type;
4686 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4688 /* Verify that the source and destination textures are non-NULL. */
4689 if (!src_texture || !dst_texture)
4691 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4692 return WINED3DERR_INVALIDCALL;
4695 if (src_texture == dst_texture)
4697 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4698 return WINED3DERR_INVALIDCALL;
4701 /* Verify that the source and destination textures are the same type. */
4702 type = IWineD3DBaseTexture_GetType(src_texture);
4703 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4705 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4706 return WINED3DERR_INVALIDCALL;
4709 /* Check that both textures have the identical numbers of levels. */
4710 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4711 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4713 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4714 return WINED3DERR_INVALIDCALL;
4717 /* Make sure that the destination texture is loaded. */
4718 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4720 /* Update every surface level of the texture. */
4723 case WINED3DRTYPE_TEXTURE:
4725 IWineD3DSurface *src_surface;
4726 IWineD3DSurface *dst_surface;
4728 for (i = 0; i < level_count; ++i)
4730 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4731 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4732 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4733 IWineD3DSurface_Release(dst_surface);
4734 IWineD3DSurface_Release(src_surface);
4737 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4744 case WINED3DRTYPE_CUBETEXTURE:
4746 IWineD3DSurface *src_surface;
4747 IWineD3DSurface *dst_surface;
4748 WINED3DCUBEMAP_FACES face;
4750 for (i = 0; i < level_count; ++i)
4752 /* Update each cube face. */
4753 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4755 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4756 face, i, &src_surface);
4757 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4758 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4759 face, i, &dst_surface);
4760 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4761 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4762 IWineD3DSurface_Release(dst_surface);
4763 IWineD3DSurface_Release(src_surface);
4766 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4774 case WINED3DRTYPE_VOLUMETEXTURE:
4776 IWineD3DVolume *src_volume;
4777 IWineD3DVolume *dst_volume;
4779 for (i = 0; i < level_count; ++i)
4781 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4782 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4783 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4784 IWineD3DVolume_Release(dst_volume);
4785 IWineD3DVolume_Release(src_volume);
4788 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4796 FIXME("Unsupported texture type %#x.\n", type);
4797 return WINED3DERR_INVALIDCALL;
4803 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4804 IWineD3DSwapChain *swapChain;
4806 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4807 if(hr == WINED3D_OK) {
4808 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4809 IWineD3DSwapChain_Release(swapChain);
4814 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4816 IWineD3DBaseTextureImpl *texture;
4819 TRACE("(%p) : %p\n", This, pNumPasses);
4821 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4822 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
4823 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4824 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4826 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
4827 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4828 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4831 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
4832 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
4834 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
4835 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4838 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
4839 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4842 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
4843 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
4844 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4849 /* return a sensible default */
4852 TRACE("returning D3D_OK\n");
4856 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
4860 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4862 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
4863 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
4864 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
4866 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
4871 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4875 PALETTEENTRY **palettes;
4877 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4879 if (PaletteNumber >= MAX_PALETTES) {
4880 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4881 return WINED3DERR_INVALIDCALL;
4884 if (PaletteNumber >= This->NumberOfPalettes) {
4885 NewSize = This->NumberOfPalettes;
4888 } while(PaletteNumber >= NewSize);
4889 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
4891 ERR("Out of memory!\n");
4892 return E_OUTOFMEMORY;
4894 This->palettes = palettes;
4895 This->NumberOfPalettes = NewSize;
4898 if (!This->palettes[PaletteNumber]) {
4899 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
4900 if (!This->palettes[PaletteNumber]) {
4901 ERR("Out of memory!\n");
4902 return E_OUTOFMEMORY;
4906 for (j = 0; j < 256; ++j) {
4907 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4908 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4909 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4910 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4912 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
4913 TRACE("(%p) : returning\n", This);
4917 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4920 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4921 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
4922 /* What happens in such situation isn't documented; Native seems to silently abort
4923 on such conditions. Return Invalid Call. */
4924 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
4925 return WINED3DERR_INVALIDCALL;
4927 for (j = 0; j < 256; ++j) {
4928 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4929 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4930 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4931 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4933 TRACE("(%p) : returning\n", This);
4937 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4939 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4940 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
4941 (tested with reference rasterizer). Return Invalid Call. */
4942 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
4943 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
4944 return WINED3DERR_INVALIDCALL;
4946 /*TODO: stateblocks */
4947 if (This->currentPalette != PaletteNumber) {
4948 This->currentPalette = PaletteNumber;
4949 dirtify_p8_texture_samplers(This);
4951 TRACE("(%p) : returning\n", This);
4955 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4957 if (PaletteNumber == NULL) {
4958 WARN("(%p) : returning Invalid Call\n", This);
4959 return WINED3DERR_INVALIDCALL;
4961 /*TODO: stateblocks */
4962 *PaletteNumber = This->currentPalette;
4963 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4967 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4972 FIXME("(%p) : stub\n", This);
4976 This->softwareVertexProcessing = bSoftware;
4981 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4986 FIXME("(%p) : stub\n", This);
4989 return This->softwareVertexProcessing;
4992 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
4993 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
4995 IWineD3DSwapChain *swapchain;
4998 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
4999 iface, swapchain_idx, raster_status);
5001 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5004 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5008 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5009 IWineD3DSwapChain_Release(swapchain);
5012 WARN("Failed to get raster status, hr %#x.\n", hr);
5019 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5022 if(nSegments != 0.0f) {
5025 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5032 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5037 FIXME("iface %p stub!\n", iface);
5043 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5045 /** TODO: remove casts to IWineD3DSurfaceImpl
5046 * NOTE: move code to surface to accomplish this
5047 ****************************************/
5048 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5049 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5050 int srcWidth, srcHeight;
5051 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5052 WINED3DFORMAT destFormat, srcFormat;
5054 int srcLeft, destLeft, destTop;
5055 WINED3DPOOL srcPool, destPool;
5057 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5058 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5062 CONVERT_TYPES convert = NO_CONVERSION;
5063 struct wined3d_context *context;
5065 WINED3DSURFACE_DESC winedesc;
5067 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5069 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5070 srcSurfaceWidth = winedesc.width;
5071 srcSurfaceHeight = winedesc.height;
5072 srcPool = winedesc.pool;
5073 srcFormat = winedesc.format;
5075 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5076 destSurfaceWidth = winedesc.width;
5077 destSurfaceHeight = winedesc.height;
5078 destPool = winedesc.pool;
5079 destFormat = winedesc.format;
5080 destSize = winedesc.size;
5082 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5083 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5084 return WINED3DERR_INVALIDCALL;
5087 /* This call loads the opengl surface directly, instead of copying the surface to the
5088 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5089 * copy in sysmem and use regular surface loading.
5091 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5092 if(convert != NO_CONVERSION) {
5093 return IWineD3DSurface_BltFast(pDestinationSurface,
5094 pDestPoint ? pDestPoint->x : 0,
5095 pDestPoint ? pDestPoint->y : 0,
5096 pSourceSurface, pSourceRect, 0);
5099 if (destFormat == WINED3DFMT_UNKNOWN) {
5100 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5101 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5103 /* Get the update surface description */
5104 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5107 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5110 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5111 checkGLcall("glActiveTextureARB");
5114 /* Make sure the surface is loaded and up to date */
5115 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5116 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5118 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5119 dst_format_desc = dst_impl->resource.format_desc;
5121 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5122 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5123 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5124 srcLeft = pSourceRect ? pSourceRect->left : 0;
5125 destLeft = pDestPoint ? pDestPoint->x : 0;
5126 destTop = pDestPoint ? pDestPoint->y : 0;
5129 /* This function doesn't support compressed textures
5130 the pitch is just bytesPerPixel * width */
5131 if(srcWidth != srcSurfaceWidth || srcLeft ){
5132 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5133 offset += srcLeft * src_format_desc->byte_count;
5134 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5136 /* TODO DXT formats */
5138 if(pSourceRect != NULL && pSourceRect->top != 0){
5139 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5141 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5142 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5143 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5146 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5148 /* need to lock the surface to get the data */
5149 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5154 /* TODO: Cube and volume support */
5156 /* not a whole row so we have to do it a line at a time */
5159 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5160 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5162 for (j = destTop; j < (srcHeight + destTop); ++j)
5164 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5165 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5169 } else { /* Full width, so just write out the whole texture */
5170 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5172 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5174 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5176 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5177 FIXME("Updating part of a compressed texture is not supported.\n");
5179 if (destFormat != srcFormat)
5181 FIXME("Updating mixed format compressed textures is not supported.\n");
5185 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5186 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5191 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5192 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5195 checkGLcall("glTexSubImage2D");
5198 context_release(context);
5200 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5201 sampler = This->rev_tex_unit_map[0];
5202 if (sampler != WINED3D_UNMAPPED_STAGE)
5204 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5210 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5212 struct WineD3DRectPatch *patch;
5213 GLenum old_primitive_type;
5217 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5219 if(!(Handle || pRectPatchInfo)) {
5220 /* TODO: Write a test for the return value, thus the FIXME */
5221 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5222 return WINED3DERR_INVALIDCALL;
5226 i = PATCHMAP_HASHFUNC(Handle);
5228 LIST_FOR_EACH(e, &This->patches[i]) {
5229 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5230 if(patch->Handle == Handle) {
5237 TRACE("Patch does not exist. Creating a new one\n");
5238 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5239 patch->Handle = Handle;
5240 list_add_head(&This->patches[i], &patch->entry);
5242 TRACE("Found existing patch %p\n", patch);
5245 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5246 * attributes we have to tesselate, read back, and draw. This needs a patch
5247 * management structure instance. Create one.
5249 * A possible improvement is to check if a vertex shader is used, and if not directly
5252 FIXME("Drawing an uncached patch. This is slow\n");
5253 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5256 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5257 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5258 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5260 TRACE("Tesselation density or patch info changed, retesselating\n");
5262 if(pRectPatchInfo) {
5263 patch->RectPatchInfo = *pRectPatchInfo;
5265 patch->numSegs[0] = pNumSegs[0];
5266 patch->numSegs[1] = pNumSegs[1];
5267 patch->numSegs[2] = pNumSegs[2];
5268 patch->numSegs[3] = pNumSegs[3];
5270 hr = tesselate_rectpatch(This, patch);
5272 WARN("Patch tesselation failed\n");
5274 /* Do not release the handle to store the params of the patch */
5276 HeapFree(GetProcessHeap(), 0, patch);
5282 This->currentPatch = patch;
5283 old_primitive_type = This->stateBlock->gl_primitive_type;
5284 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5285 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5286 This->stateBlock->gl_primitive_type = old_primitive_type;
5287 This->currentPatch = NULL;
5289 /* Destroy uncached patches */
5291 HeapFree(GetProcessHeap(), 0, patch->mem);
5292 HeapFree(GetProcessHeap(), 0, patch);
5297 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5298 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5300 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5301 iface, handle, segment_count, patch_info);
5306 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5309 struct WineD3DRectPatch *patch;
5311 TRACE("(%p) Handle(%d)\n", This, Handle);
5313 i = PATCHMAP_HASHFUNC(Handle);
5314 LIST_FOR_EACH(e, &This->patches[i]) {
5315 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5316 if(patch->Handle == Handle) {
5317 TRACE("Deleting patch %p\n", patch);
5318 list_remove(&patch->entry);
5319 HeapFree(GetProcessHeap(), 0, patch->mem);
5320 HeapFree(GetProcessHeap(), 0, patch);
5325 /* TODO: Write a test for the return value */
5326 FIXME("Attempt to destroy nonexistent patch\n");
5327 return WINED3DERR_INVALIDCALL;
5330 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5332 IWineD3DSwapChain *swapchain;
5334 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5335 if (SUCCEEDED(hr)) {
5336 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5343 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5344 const WINED3DRECT *rect, const float color[4])
5346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5347 struct wined3d_context *context;
5349 if (!surface_is_offscreen(surface))
5351 TRACE("Surface %p is onscreen\n", surface);
5353 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5355 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5356 context_set_draw_buffer(context, surface_get_gl_buffer(surface));
5360 TRACE("Surface %p is offscreen\n", surface);
5362 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5364 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5365 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5366 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5370 glEnable(GL_SCISSOR_TEST);
5371 if(surface_is_offscreen(surface)) {
5372 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5374 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5375 rect->x2 - rect->x1, rect->y2 - rect->y1);
5377 checkGLcall("glScissor");
5378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5380 glDisable(GL_SCISSOR_TEST);
5382 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5384 glDisable(GL_BLEND);
5385 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5387 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5388 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5390 glClearColor(color[0], color[1], color[2], color[3]);
5391 glClear(GL_COLOR_BUFFER_BIT);
5392 checkGLcall("glClear");
5395 context_release(context);
5398 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5399 unsigned int r, g, b, a;
5402 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5403 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5404 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5407 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5409 a = (color & 0xff000000) >> 24;
5410 r = (color & 0x00ff0000) >> 16;
5411 g = (color & 0x0000ff00) >> 8;
5412 b = (color & 0x000000ff) >> 0;
5416 case WINED3DFMT_B5G6R5_UNORM:
5417 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5424 TRACE("Returning %08x\n", ret);
5427 case WINED3DFMT_B5G5R5X1_UNORM:
5428 case WINED3DFMT_B5G5R5A1_UNORM:
5437 TRACE("Returning %08x\n", ret);
5440 case WINED3DFMT_A8_UNORM:
5441 TRACE("Returning %08x\n", a);
5444 case WINED3DFMT_B4G4R4X4_UNORM:
5445 case WINED3DFMT_B4G4R4A4_UNORM:
5454 TRACE("Returning %08x\n", ret);
5457 case WINED3DFMT_B2G3R3_UNORM:
5464 TRACE("Returning %08x\n", ret);
5467 case WINED3DFMT_R8G8B8X8_UNORM:
5468 case WINED3DFMT_R8G8B8A8_UNORM:
5473 TRACE("Returning %08x\n", ret);
5476 case WINED3DFMT_B10G10R10A2_UNORM:
5478 r = (r * 1024) / 256;
5479 g = (g * 1024) / 256;
5480 b = (b * 1024) / 256;
5485 TRACE("Returning %08x\n", ret);
5488 case WINED3DFMT_R10G10B10A2_UNORM:
5490 r = (r * 1024) / 256;
5491 g = (g * 1024) / 256;
5492 b = (b * 1024) / 256;
5497 TRACE("Returning %08x\n", ret);
5501 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5506 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5507 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5509 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5512 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5514 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5515 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5516 return WINED3DERR_INVALIDCALL;
5519 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5520 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5521 color_fill_fbo(iface, pSurface, pRect, c);
5524 /* Just forward this to the DirectDraw blitting engine */
5525 memset(&BltFx, 0, sizeof(BltFx));
5526 BltFx.dwSize = sizeof(BltFx);
5527 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5528 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5529 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5533 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5534 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5536 IWineD3DResource *resource;
5537 IWineD3DSurface *surface;
5540 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5543 ERR("Failed to get resource, hr %#x\n", hr);
5547 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5549 FIXME("Only supported on surface resources\n");
5550 IWineD3DResource_Release(resource);
5554 surface = (IWineD3DSurface *)resource;
5556 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5558 color_fill_fbo(iface, surface, NULL, color);
5565 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5567 c = ((DWORD)(color[2] * 255.0f));
5568 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5569 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5570 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5572 /* Just forward this to the DirectDraw blitting engine */
5573 memset(&BltFx, 0, sizeof(BltFx));
5574 BltFx.dwSize = sizeof(BltFx);
5575 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5576 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5579 ERR("Blt failed, hr %#x\n", hr);
5583 IWineD3DResource_Release(resource);
5586 /* rendertarget and depth stencil functions */
5587 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5590 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5592 ERR("(%p) : Only %d render targets are supported.\n",
5593 This, This->adapter->gl_info.limits.buffers);
5594 return WINED3DERR_INVALIDCALL;
5597 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5598 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5599 /* Note inc ref on returned surface */
5600 if(*ppRenderTarget != NULL)
5601 IWineD3DSurface_AddRef(*ppRenderTarget);
5605 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5606 IWineD3DSurface *Front, IWineD3DSurface *Back)
5608 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5609 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5610 IWineD3DSwapChainImpl *Swapchain;
5613 TRACE("iface %p, front %p, back %p.\n", iface, Front, Back);
5615 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5616 if(hr != WINED3D_OK) {
5617 ERR("Can't get the swapchain\n");
5621 /* Make sure to release the swapchain */
5622 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5624 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5625 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5626 return WINED3DERR_INVALIDCALL;
5628 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5629 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5630 return WINED3DERR_INVALIDCALL;
5633 if(Swapchain->frontBuffer != Front) {
5634 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5636 if(Swapchain->frontBuffer)
5638 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5639 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5641 Swapchain->frontBuffer = Front;
5643 if(Swapchain->frontBuffer) {
5644 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5645 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5649 if(Back && !Swapchain->backBuffer) {
5650 /* We need memory for the back buffer array - only one back buffer this way */
5651 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5652 if(!Swapchain->backBuffer) {
5653 ERR("Out of memory\n");
5654 return E_OUTOFMEMORY;
5658 if(Swapchain->backBuffer[0] != Back) {
5659 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5661 /* What to do about the context here in the case of multithreading? Not sure.
5662 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5664 WARN("No active context?\n");
5667 if(!Swapchain->backBuffer[0]) {
5668 /* GL was told to draw to the front buffer at creation,
5671 glDrawBuffer(GL_BACK);
5672 checkGLcall("glDrawBuffer(GL_BACK)");
5673 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5674 Swapchain->presentParms.BackBufferCount = 1;
5676 /* That makes problems - disable for now */
5677 /* glDrawBuffer(GL_FRONT); */
5678 checkGLcall("glDrawBuffer(GL_FRONT)");
5679 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5680 Swapchain->presentParms.BackBufferCount = 0;
5684 if(Swapchain->backBuffer[0])
5686 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5687 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5689 Swapchain->backBuffer[0] = Back;
5691 if(Swapchain->backBuffer[0]) {
5692 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5693 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
5695 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5696 Swapchain->backBuffer = NULL;
5704 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5706 *ppZStencilSurface = This->stencilBufferTarget;
5707 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5709 if(*ppZStencilSurface != NULL) {
5710 /* Note inc ref on returned surface */
5711 IWineD3DSurface_AddRef(*ppZStencilSurface);
5714 return WINED3DERR_NOTFOUND;
5718 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5719 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
5721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5722 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5723 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5724 const struct wined3d_gl_info *gl_info;
5725 struct wined3d_context *context;
5727 POINT offset = {0, 0};
5729 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5730 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5731 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5732 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5735 case WINED3DTEXF_LINEAR:
5736 gl_filter = GL_LINEAR;
5740 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5741 case WINED3DTEXF_NONE:
5742 case WINED3DTEXF_POINT:
5743 gl_filter = GL_NEAREST;
5747 /* Attach src surface to src fbo */
5748 src_swapchain = get_swapchain(src_surface);
5749 dst_swapchain = get_swapchain(dst_surface);
5751 if (src_swapchain) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
5752 else if (dst_swapchain) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5753 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5755 gl_info = context->gl_info;
5757 if (!surface_is_offscreen(src_surface))
5759 GLenum buffer = surface_get_gl_buffer(src_surface);
5761 TRACE("Source surface %p is onscreen\n", src_surface);
5762 /* Make sure the drawable is up to date. In the offscreen case
5763 * attach_surface_fbo() implicitly takes care of this. */
5764 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
5766 if(buffer == GL_FRONT) {
5769 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
5770 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
5771 h = windowsize.bottom - windowsize.top;
5772 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
5773 src_rect->y1 = offset.y + h - src_rect->y1;
5774 src_rect->y2 = offset.y + h - src_rect->y2;
5776 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5777 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5781 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5782 glReadBuffer(buffer);
5783 checkGLcall("glReadBuffer()");
5785 TRACE("Source surface %p is offscreen\n", src_surface);
5787 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5788 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
5789 glReadBuffer(GL_COLOR_ATTACHMENT0);
5790 checkGLcall("glReadBuffer()");
5791 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5795 /* Attach dst surface to dst fbo */
5796 if (!surface_is_offscreen(dst_surface))
5798 GLenum buffer = surface_get_gl_buffer(dst_surface);
5800 TRACE("Destination surface %p is onscreen\n", dst_surface);
5801 /* Make sure the drawable is up to date. In the offscreen case
5802 * attach_surface_fbo() implicitly takes care of this. */
5803 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
5805 if(buffer == GL_FRONT) {
5808 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
5809 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
5810 h = windowsize.bottom - windowsize.top;
5811 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
5812 dst_rect->y1 = offset.y + h - dst_rect->y1;
5813 dst_rect->y2 = offset.y + h - dst_rect->y2;
5815 /* Screen coords = window coords, surface height = window height */
5816 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5817 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5821 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5822 context_set_draw_buffer(context, buffer);
5826 TRACE("Destination surface %p is offscreen\n", dst_surface);
5829 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5830 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
5831 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5832 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5834 glDisable(GL_SCISSOR_TEST);
5835 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5838 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5839 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
5840 checkGLcall("glBlitFramebuffer()");
5842 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5843 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
5844 checkGLcall("glBlitFramebuffer()");
5848 context_release(context);
5850 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
5853 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5854 BOOL set_viewport) {
5855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5857 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5859 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5861 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5862 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5863 return WINED3DERR_INVALIDCALL;
5866 /* MSDN says that null disables the render target
5867 but a device must always be associated with a render target
5868 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5870 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5871 FIXME("Trying to set render target 0 to NULL\n");
5872 return WINED3DERR_INVALIDCALL;
5874 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5875 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);
5876 return WINED3DERR_INVALIDCALL;
5879 /* If we are trying to set what we already have, don't bother */
5880 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5881 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5884 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5885 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5886 This->render_targets[RenderTargetIndex] = pRenderTarget;
5888 /* Render target 0 is special */
5889 if(RenderTargetIndex == 0 && set_viewport) {
5890 /* Finally, reset the viewport and scissor rect as the MSDN states.
5891 * Tests show that stateblock recording is ignored, the change goes
5892 * directly into the primary stateblock.
5894 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5895 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5896 This->stateBlock->viewport.X = 0;
5897 This->stateBlock->viewport.Y = 0;
5898 This->stateBlock->viewport.MaxZ = 1.0f;
5899 This->stateBlock->viewport.MinZ = 0.0f;
5900 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5902 This->stateBlock->scissorRect.top = 0;
5903 This->stateBlock->scissorRect.left = 0;
5904 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5905 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5906 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5911 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5913 HRESULT hr = WINED3D_OK;
5914 IWineD3DSurface *tmp;
5916 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
5918 if (pNewZStencil == This->stencilBufferTarget) {
5919 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5921 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
5922 * depending on the renter target implementation being used.
5923 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5924 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5925 * stencil buffer and incur an extra memory overhead
5926 ******************************************************/
5928 if (This->stencilBufferTarget) {
5929 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5930 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
5931 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
5933 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5934 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
5935 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
5936 context_release(context);
5940 tmp = This->stencilBufferTarget;
5941 This->stencilBufferTarget = pNewZStencil;
5942 /* should we be calling the parent or the wined3d surface? */
5943 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5944 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5947 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5948 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5949 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5950 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5951 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5958 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5959 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5961 /* TODO: the use of Impl is deprecated. */
5962 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5963 WINED3DLOCKED_RECT lockedRect;
5965 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5967 /* some basic validation checks */
5968 if(This->cursorTexture) {
5969 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5971 glDeleteTextures(1, &This->cursorTexture);
5973 context_release(context);
5974 This->cursorTexture = 0;
5977 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5978 This->haveHardwareCursor = TRUE;
5980 This->haveHardwareCursor = FALSE;
5983 WINED3DLOCKED_RECT rect;
5985 /* MSDN: Cursor must be A8R8G8B8 */
5986 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
5988 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5989 return WINED3DERR_INVALIDCALL;
5992 /* MSDN: Cursor must be smaller than the display mode */
5993 if(pSur->currentDesc.Width > This->ddraw_width ||
5994 pSur->currentDesc.Height > This->ddraw_height) {
5995 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);
5996 return WINED3DERR_INVALIDCALL;
5999 if (!This->haveHardwareCursor) {
6000 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6002 /* Do not store the surface's pointer because the application may
6003 * release it after setting the cursor image. Windows doesn't
6004 * addref the set surface, so we can't do this either without
6005 * creating circular refcount dependencies. Copy out the gl texture
6008 This->cursorWidth = pSur->currentDesc.Width;
6009 This->cursorHeight = pSur->currentDesc.Height;
6010 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6012 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6013 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6014 struct wined3d_context *context;
6015 char *mem, *bits = rect.pBits;
6016 GLint intfmt = glDesc->glInternal;
6017 GLint format = glDesc->glFormat;
6018 GLint type = glDesc->glType;
6019 INT height = This->cursorHeight;
6020 INT width = This->cursorWidth;
6021 INT bpp = glDesc->byte_count;
6025 /* Reformat the texture memory (pitch and width can be
6027 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6028 for(i = 0; i < height; i++)
6029 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6030 IWineD3DSurface_UnlockRect(pCursorBitmap);
6032 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6036 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6038 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6039 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6042 /* Make sure that a proper texture unit is selected */
6043 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6044 checkGLcall("glActiveTextureARB");
6045 sampler = This->rev_tex_unit_map[0];
6046 if (sampler != WINED3D_UNMAPPED_STAGE)
6048 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6050 /* Create a new cursor texture */
6051 glGenTextures(1, &This->cursorTexture);
6052 checkGLcall("glGenTextures");
6053 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6054 checkGLcall("glBindTexture");
6055 /* Copy the bitmap memory into the cursor texture */
6056 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6057 HeapFree(GetProcessHeap(), 0, mem);
6058 checkGLcall("glTexImage2D");
6060 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6062 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6063 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6068 context_release(context);
6072 FIXME("A cursor texture was not returned.\n");
6073 This->cursorTexture = 0;
6078 /* Draw a hardware cursor */
6079 ICONINFO cursorInfo;
6081 /* Create and clear maskBits because it is not needed for
6082 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6084 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6085 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6086 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6087 WINED3DLOCK_NO_DIRTY_UPDATE |
6088 WINED3DLOCK_READONLY
6090 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6091 pSur->currentDesc.Height);
6093 cursorInfo.fIcon = FALSE;
6094 cursorInfo.xHotspot = XHotSpot;
6095 cursorInfo.yHotspot = YHotSpot;
6096 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6098 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6099 1, 32, lockedRect.pBits);
6100 IWineD3DSurface_UnlockRect(pCursorBitmap);
6101 /* Create our cursor and clean up. */
6102 cursor = CreateIconIndirect(&cursorInfo);
6104 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6105 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6106 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6107 This->hardwareCursor = cursor;
6108 HeapFree(GetProcessHeap(), 0, maskBits);
6112 This->xHotSpot = XHotSpot;
6113 This->yHotSpot = YHotSpot;
6117 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6119 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6121 This->xScreenSpace = XScreenSpace;
6122 This->yScreenSpace = YScreenSpace;
6128 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6130 BOOL oldVisible = This->bCursorVisible;
6133 TRACE("(%p) : visible(%d)\n", This, bShow);
6136 * When ShowCursor is first called it should make the cursor appear at the OS's last
6137 * known cursor position. Because of this, some applications just repetitively call
6138 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6141 This->xScreenSpace = pt.x;
6142 This->yScreenSpace = pt.y;
6144 if (This->haveHardwareCursor) {
6145 This->bCursorVisible = bShow;
6147 SetCursor(This->hardwareCursor);
6153 if (This->cursorTexture)
6154 This->bCursorVisible = bShow;
6160 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6161 TRACE("checking resource %p for eviction\n", resource);
6162 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6163 TRACE("Evicting %p\n", resource);
6164 IWineD3DResource_UnLoad(resource);
6166 IWineD3DResource_Release(resource);
6170 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6172 TRACE("iface %p.\n", iface);
6174 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6178 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6180 IWineD3DDeviceImpl *device = surface->resource.device;
6181 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6183 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6184 if(surface->Flags & SFLAG_DIBSECTION) {
6185 /* Release the DC */
6186 SelectObject(surface->hDC, surface->dib.holdbitmap);
6187 DeleteDC(surface->hDC);
6188 /* Release the DIB section */
6189 DeleteObject(surface->dib.DIBsection);
6190 surface->dib.bitmap_data = NULL;
6191 surface->resource.allocatedMemory = NULL;
6192 surface->Flags &= ~SFLAG_DIBSECTION;
6194 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6195 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6196 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6197 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6199 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6200 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6202 surface->pow2Width = surface->pow2Height = 1;
6203 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6204 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6206 surface->glRect.left = 0;
6207 surface->glRect.top = 0;
6208 surface->glRect.right = surface->pow2Width;
6209 surface->glRect.bottom = surface->pow2Height;
6211 if (surface->texture_name)
6213 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6215 glDeleteTextures(1, &surface->texture_name);
6217 context_release(context);
6218 surface->texture_name = 0;
6219 surface->Flags &= ~SFLAG_CLIENT;
6221 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6222 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6223 surface->Flags |= SFLAG_NONPOW2;
6225 surface->Flags &= ~SFLAG_NONPOW2;
6227 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6228 surface->resource.allocatedMemory = NULL;
6229 surface->resource.heapMemory = NULL;
6230 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6232 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6234 if(!surface_init_sysmem((IWineD3DSurface *) surface))
6236 return E_OUTOFMEMORY;
6241 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6242 TRACE("Unloading resource %p\n", resource);
6243 IWineD3DResource_UnLoad(resource);
6244 IWineD3DResource_Release(resource);
6248 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6251 WINED3DDISPLAYMODE m;
6254 /* All Windowed modes are supported, as is leaving the current mode */
6255 if(pp->Windowed) return TRUE;
6256 if(!pp->BackBufferWidth) return TRUE;
6257 if(!pp->BackBufferHeight) return TRUE;
6259 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6260 for(i = 0; i < count; i++) {
6261 memset(&m, 0, sizeof(m));
6262 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6264 ERR("EnumAdapterModes failed\n");
6266 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6267 /* Mode found, it is supported */
6271 /* Mode not found -> not supported */
6275 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6277 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6278 const struct wined3d_gl_info *gl_info;
6279 struct wined3d_context *context;
6280 IWineD3DBaseShaderImpl *shader;
6282 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6283 gl_info = context->gl_info;
6285 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6286 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6287 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6291 if(This->depth_blt_texture) {
6292 glDeleteTextures(1, &This->depth_blt_texture);
6293 This->depth_blt_texture = 0;
6295 if (This->depth_blt_rb) {
6296 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6297 This->depth_blt_rb = 0;
6298 This->depth_blt_rb_w = 0;
6299 This->depth_blt_rb_h = 0;
6303 This->blitter->free_private(iface);
6304 This->frag_pipe->free_private(iface);
6305 This->shader_backend->shader_free_private(iface);
6306 destroy_dummy_textures(This, gl_info);
6308 context_release(context);
6310 while (This->numContexts)
6312 context_destroy(This, This->contexts[0]);
6314 HeapFree(GetProcessHeap(), 0, swapchain->context);
6315 swapchain->context = NULL;
6316 swapchain->num_contexts = 0;
6319 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6321 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6322 struct wined3d_context *context;
6324 IWineD3DSurfaceImpl *target;
6326 /* Recreate the primary swapchain's context */
6327 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6328 if (!swapchain->context)
6330 ERR("Failed to allocate memory for swapchain context array.\n");
6331 return E_OUTOFMEMORY;
6334 target = (IWineD3DSurfaceImpl *)(swapchain->backBuffer ? swapchain->backBuffer[0] : swapchain->frontBuffer);
6335 context = context_create(This, target, swapchain->win_handle, FALSE, &swapchain->presentParms);
6338 WARN("Failed to create context.\n");
6339 HeapFree(GetProcessHeap(), 0, swapchain->context);
6343 swapchain->context[0] = context;
6344 swapchain->num_contexts = 1;
6345 create_dummy_textures(This);
6346 context_release(context);
6348 hr = This->shader_backend->shader_alloc_private(iface);
6351 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6355 hr = This->frag_pipe->alloc_private(iface);
6358 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6359 This->shader_backend->shader_free_private(iface);
6363 hr = This->blitter->alloc_private(iface);
6366 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6367 This->frag_pipe->free_private(iface);
6368 This->shader_backend->shader_free_private(iface);
6375 context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6376 destroy_dummy_textures(This, context->gl_info);
6377 context_release(context);
6378 context_destroy(This, context);
6379 HeapFree(GetProcessHeap(), 0, swapchain->context);
6380 swapchain->num_contexts = 0;
6384 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6386 IWineD3DSwapChainImpl *swapchain;
6388 BOOL DisplayModeChanged = FALSE;
6389 WINED3DDISPLAYMODE mode;
6390 TRACE("(%p)\n", This);
6392 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6394 ERR("Failed to get the first implicit swapchain\n");
6398 if(!is_display_mode_supported(This, pPresentationParameters)) {
6399 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6400 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6401 pPresentationParameters->BackBufferHeight);
6402 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6403 return WINED3DERR_INVALIDCALL;
6406 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6407 * on an existing gl context, so there's no real need for recreation.
6409 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6411 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6413 TRACE("New params:\n");
6414 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6415 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6416 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6417 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6418 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6419 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6420 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6421 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6422 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6423 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6424 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6425 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6426 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6428 /* No special treatment of these parameters. Just store them */
6429 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6430 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6431 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6432 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6434 /* What to do about these? */
6435 if(pPresentationParameters->BackBufferCount != 0 &&
6436 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6437 ERR("Cannot change the back buffer count yet\n");
6439 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6440 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6441 ERR("Cannot change the back buffer format yet\n");
6443 if(pPresentationParameters->hDeviceWindow != NULL &&
6444 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6445 ERR("Cannot change the device window yet\n");
6447 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6450 TRACE("Creating the depth stencil buffer\n");
6452 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6454 pPresentationParameters->BackBufferWidth,
6455 pPresentationParameters->BackBufferHeight,
6456 pPresentationParameters->AutoDepthStencilFormat,
6457 pPresentationParameters->MultiSampleType,
6458 pPresentationParameters->MultiSampleQuality,
6460 &This->auto_depth_stencil_buffer);
6463 ERR("Failed to create the depth stencil buffer\n");
6464 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6465 return WINED3DERR_INVALIDCALL;
6469 /* Reset the depth stencil */
6470 if (pPresentationParameters->EnableAutoDepthStencil)
6471 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6473 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6475 TRACE("Resetting stateblock\n");
6476 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6477 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6479 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6481 if(pPresentationParameters->Windowed) {
6482 mode.Width = swapchain->orig_width;
6483 mode.Height = swapchain->orig_height;
6484 mode.RefreshRate = 0;
6485 mode.Format = swapchain->presentParms.BackBufferFormat;
6487 mode.Width = pPresentationParameters->BackBufferWidth;
6488 mode.Height = pPresentationParameters->BackBufferHeight;
6489 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6490 mode.Format = swapchain->presentParms.BackBufferFormat;
6493 /* Should Width == 800 && Height == 0 set 800x600? */
6494 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6495 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6496 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6500 if(!pPresentationParameters->Windowed) {
6501 DisplayModeChanged = TRUE;
6503 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6504 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6506 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6509 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6513 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6514 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6517 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6521 if(This->auto_depth_stencil_buffer) {
6522 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6525 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6531 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6532 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6533 DisplayModeChanged) {
6535 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6537 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
6538 if(swapchain->presentParms.Windowed) {
6539 /* switch from windowed to fs */
6540 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6541 pPresentationParameters->BackBufferHeight);
6543 /* Fullscreen -> fullscreen mode change */
6544 MoveWindow(swapchain->win_handle, 0, 0,
6545 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6548 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
6549 /* Fullscreen -> windowed switch */
6550 swapchain_restore_fullscreen_window(swapchain);
6552 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6553 } else if(!pPresentationParameters->Windowed) {
6554 DWORD style = This->style, exStyle = This->exStyle;
6555 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6556 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6557 * Reset to clear up their mess. Guild Wars also loses the device during that.
6561 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6562 pPresentationParameters->BackBufferHeight);
6563 This->style = style;
6564 This->exStyle = exStyle;
6567 /* Note: No parent needed for initial internal stateblock */
6568 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6569 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6570 else TRACE("Created stateblock %p\n", This->stateBlock);
6571 This->updateStateBlock = This->stateBlock;
6572 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6574 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6576 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6579 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6582 GetClientRect(swapchain->win_handle, &client_rect);
6584 if(!swapchain->presentParms.BackBufferCount)
6586 TRACE("Single buffered rendering\n");
6587 swapchain->render_to_fbo = FALSE;
6589 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6590 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6592 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6593 swapchain->presentParms.BackBufferWidth,
6594 swapchain->presentParms.BackBufferHeight,
6595 client_rect.right, client_rect.bottom);
6596 swapchain->render_to_fbo = TRUE;
6600 TRACE("Rendering directly to GL_BACK\n");
6601 swapchain->render_to_fbo = FALSE;
6605 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6606 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6608 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6614 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6616 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6618 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6624 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6626 TRACE("(%p) : pParameters %p\n", This, pParameters);
6628 *pParameters = This->createParms;
6632 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6633 IWineD3DSwapChain *swapchain;
6635 TRACE("Relaying to swapchain\n");
6637 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6638 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6639 IWineD3DSwapChain_Release(swapchain);
6644 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6645 IWineD3DSwapChain *swapchain;
6647 TRACE("Relaying to swapchain\n");
6649 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6650 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6651 IWineD3DSwapChain_Release(swapchain);
6657 /** ********************************************************
6658 * Notification functions
6659 ** ********************************************************/
6660 /** This function must be called in the release of a resource when ref == 0,
6661 * the contents of resource must still be correct,
6662 * any handles to other resource held by the caller must be closed
6663 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6664 *****************************************************/
6665 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6667 TRACE("(%p) : Adding resource %p\n", This, resource);
6669 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6672 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6674 TRACE("(%p) : Removing resource %p\n", This, resource);
6676 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6679 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6681 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6684 TRACE("(%p) : resource %p\n", This, resource);
6686 context_resource_released((IWineD3DDevice *)This, resource, type);
6689 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6690 case WINED3DRTYPE_SURFACE: {
6693 if (This->d3d_initialized)
6695 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6697 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6698 This->render_targets[i] = NULL;
6701 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6702 This->stencilBufferTarget = NULL;
6708 case WINED3DRTYPE_TEXTURE:
6709 case WINED3DRTYPE_CUBETEXTURE:
6710 case WINED3DRTYPE_VOLUMETEXTURE:
6711 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6712 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6713 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6714 This->stateBlock->textures[counter] = NULL;
6716 if (This->updateStateBlock != This->stateBlock ){
6717 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6718 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6719 This->updateStateBlock->textures[counter] = NULL;
6724 case WINED3DRTYPE_VOLUME:
6725 /* TODO: nothing really? */
6727 case WINED3DRTYPE_BUFFER:
6730 TRACE("Cleaning up stream pointers\n");
6732 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6733 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6734 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6736 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6737 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6738 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6739 This->updateStateBlock->streamSource[streamNumber] = 0;
6740 /* Set changed flag? */
6743 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) */
6744 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6745 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6746 This->stateBlock->streamSource[streamNumber] = 0;
6751 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6752 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6753 This->updateStateBlock->pIndexData = NULL;
6756 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6757 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6758 This->stateBlock->pIndexData = NULL;
6765 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6770 /* Remove the resource from the resourceStore */
6771 device_resource_remove(This, resource);
6773 TRACE("Resource released\n");
6777 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6779 IWineD3DResourceImpl *resource, *cursor;
6781 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6783 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6784 TRACE("enumerating resource %p\n", resource);
6785 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6786 ret = pCallback((IWineD3DResource *) resource, pData);
6787 if(ret == S_FALSE) {
6788 TRACE("Canceling enumeration\n");
6795 /**********************************************************
6796 * IWineD3DDevice VTbl follows
6797 **********************************************************/
6799 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6801 /*** IUnknown methods ***/
6802 IWineD3DDeviceImpl_QueryInterface,
6803 IWineD3DDeviceImpl_AddRef,
6804 IWineD3DDeviceImpl_Release,
6805 /*** IWineD3DDevice methods ***/
6806 IWineD3DDeviceImpl_GetParent,
6807 /*** Creation methods**/
6808 IWineD3DDeviceImpl_CreateBuffer,
6809 IWineD3DDeviceImpl_CreateVertexBuffer,
6810 IWineD3DDeviceImpl_CreateIndexBuffer,
6811 IWineD3DDeviceImpl_CreateStateBlock,
6812 IWineD3DDeviceImpl_CreateSurface,
6813 IWineD3DDeviceImpl_CreateRendertargetView,
6814 IWineD3DDeviceImpl_CreateTexture,
6815 IWineD3DDeviceImpl_CreateVolumeTexture,
6816 IWineD3DDeviceImpl_CreateVolume,
6817 IWineD3DDeviceImpl_CreateCubeTexture,
6818 IWineD3DDeviceImpl_CreateQuery,
6819 IWineD3DDeviceImpl_CreateSwapChain,
6820 IWineD3DDeviceImpl_CreateVertexDeclaration,
6821 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6822 IWineD3DDeviceImpl_CreateVertexShader,
6823 IWineD3DDeviceImpl_CreatePixelShader,
6824 IWineD3DDeviceImpl_CreatePalette,
6825 /*** Odd functions **/
6826 IWineD3DDeviceImpl_Init3D,
6827 IWineD3DDeviceImpl_InitGDI,
6828 IWineD3DDeviceImpl_Uninit3D,
6829 IWineD3DDeviceImpl_UninitGDI,
6830 IWineD3DDeviceImpl_SetMultithreaded,
6831 IWineD3DDeviceImpl_EvictManagedResources,
6832 IWineD3DDeviceImpl_GetAvailableTextureMem,
6833 IWineD3DDeviceImpl_GetBackBuffer,
6834 IWineD3DDeviceImpl_GetCreationParameters,
6835 IWineD3DDeviceImpl_GetDeviceCaps,
6836 IWineD3DDeviceImpl_GetDirect3D,
6837 IWineD3DDeviceImpl_GetDisplayMode,
6838 IWineD3DDeviceImpl_SetDisplayMode,
6839 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6840 IWineD3DDeviceImpl_GetRasterStatus,
6841 IWineD3DDeviceImpl_GetSwapChain,
6842 IWineD3DDeviceImpl_Reset,
6843 IWineD3DDeviceImpl_SetDialogBoxMode,
6844 IWineD3DDeviceImpl_SetCursorProperties,
6845 IWineD3DDeviceImpl_SetCursorPosition,
6846 IWineD3DDeviceImpl_ShowCursor,
6847 /*** Getters and setters **/
6848 IWineD3DDeviceImpl_SetClipPlane,
6849 IWineD3DDeviceImpl_GetClipPlane,
6850 IWineD3DDeviceImpl_SetClipStatus,
6851 IWineD3DDeviceImpl_GetClipStatus,
6852 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6853 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6854 IWineD3DDeviceImpl_SetDepthStencilSurface,
6855 IWineD3DDeviceImpl_GetDepthStencilSurface,
6856 IWineD3DDeviceImpl_SetGammaRamp,
6857 IWineD3DDeviceImpl_GetGammaRamp,
6858 IWineD3DDeviceImpl_SetIndexBuffer,
6859 IWineD3DDeviceImpl_GetIndexBuffer,
6860 IWineD3DDeviceImpl_SetBaseVertexIndex,
6861 IWineD3DDeviceImpl_GetBaseVertexIndex,
6862 IWineD3DDeviceImpl_SetLight,
6863 IWineD3DDeviceImpl_GetLight,
6864 IWineD3DDeviceImpl_SetLightEnable,
6865 IWineD3DDeviceImpl_GetLightEnable,
6866 IWineD3DDeviceImpl_SetMaterial,
6867 IWineD3DDeviceImpl_GetMaterial,
6868 IWineD3DDeviceImpl_SetNPatchMode,
6869 IWineD3DDeviceImpl_GetNPatchMode,
6870 IWineD3DDeviceImpl_SetPaletteEntries,
6871 IWineD3DDeviceImpl_GetPaletteEntries,
6872 IWineD3DDeviceImpl_SetPixelShader,
6873 IWineD3DDeviceImpl_GetPixelShader,
6874 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6875 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6876 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6877 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6878 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6879 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6880 IWineD3DDeviceImpl_SetRenderState,
6881 IWineD3DDeviceImpl_GetRenderState,
6882 IWineD3DDeviceImpl_SetRenderTarget,
6883 IWineD3DDeviceImpl_GetRenderTarget,
6884 IWineD3DDeviceImpl_SetFrontBackBuffers,
6885 IWineD3DDeviceImpl_SetSamplerState,
6886 IWineD3DDeviceImpl_GetSamplerState,
6887 IWineD3DDeviceImpl_SetScissorRect,
6888 IWineD3DDeviceImpl_GetScissorRect,
6889 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6890 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6891 IWineD3DDeviceImpl_SetStreamSource,
6892 IWineD3DDeviceImpl_GetStreamSource,
6893 IWineD3DDeviceImpl_SetStreamSourceFreq,
6894 IWineD3DDeviceImpl_GetStreamSourceFreq,
6895 IWineD3DDeviceImpl_SetTexture,
6896 IWineD3DDeviceImpl_GetTexture,
6897 IWineD3DDeviceImpl_SetTextureStageState,
6898 IWineD3DDeviceImpl_GetTextureStageState,
6899 IWineD3DDeviceImpl_SetTransform,
6900 IWineD3DDeviceImpl_GetTransform,
6901 IWineD3DDeviceImpl_SetVertexDeclaration,
6902 IWineD3DDeviceImpl_GetVertexDeclaration,
6903 IWineD3DDeviceImpl_SetVertexShader,
6904 IWineD3DDeviceImpl_GetVertexShader,
6905 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6906 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6907 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6908 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6909 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6910 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6911 IWineD3DDeviceImpl_SetViewport,
6912 IWineD3DDeviceImpl_GetViewport,
6913 IWineD3DDeviceImpl_MultiplyTransform,
6914 IWineD3DDeviceImpl_ValidateDevice,
6915 IWineD3DDeviceImpl_ProcessVertices,
6916 /*** State block ***/
6917 IWineD3DDeviceImpl_BeginStateBlock,
6918 IWineD3DDeviceImpl_EndStateBlock,
6919 /*** Scene management ***/
6920 IWineD3DDeviceImpl_BeginScene,
6921 IWineD3DDeviceImpl_EndScene,
6922 IWineD3DDeviceImpl_Present,
6923 IWineD3DDeviceImpl_Clear,
6924 IWineD3DDeviceImpl_ClearRendertargetView,
6926 IWineD3DDeviceImpl_SetPrimitiveType,
6927 IWineD3DDeviceImpl_GetPrimitiveType,
6928 IWineD3DDeviceImpl_DrawPrimitive,
6929 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6930 IWineD3DDeviceImpl_DrawPrimitiveUP,
6931 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6932 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6933 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6934 IWineD3DDeviceImpl_DrawRectPatch,
6935 IWineD3DDeviceImpl_DrawTriPatch,
6936 IWineD3DDeviceImpl_DeletePatch,
6937 IWineD3DDeviceImpl_ColorFill,
6938 IWineD3DDeviceImpl_UpdateTexture,
6939 IWineD3DDeviceImpl_UpdateSurface,
6940 IWineD3DDeviceImpl_GetFrontBufferData,
6941 /*** object tracking ***/
6942 IWineD3DDeviceImpl_EnumResources
6945 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6946 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6947 IUnknown *parent, IWineD3DDeviceParent *device_parent)
6949 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6950 const struct fragment_pipeline *fragment_pipeline;
6951 struct shader_caps shader_caps;
6952 struct fragment_caps ffp_caps;
6953 WINED3DDISPLAYMODE mode;
6957 device->lpVtbl = &IWineD3DDevice_Vtbl;
6959 device->wined3d = (IWineD3D *)wined3d;
6960 IWineD3D_AddRef(device->wined3d);
6961 device->adapter = wined3d->adapter_count ? adapter : NULL;
6962 device->parent = parent;
6963 device->device_parent = device_parent;
6964 list_init(&device->resources);
6965 list_init(&device->shaders);
6967 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6968 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6970 /* Get the initial screen setup for ddraw. */
6971 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6974 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6975 IWineD3D_Release(device->wined3d);
6978 device->ddraw_width = mode.Width;
6979 device->ddraw_height = mode.Height;
6980 device->ddraw_format = mode.Format;
6982 /* Save the creation parameters. */
6983 device->createParms.AdapterOrdinal = adapter_idx;
6984 device->createParms.DeviceType = device_type;
6985 device->createParms.hFocusWindow = focus_window;
6986 device->createParms.BehaviorFlags = flags;
6988 device->devType = device_type;
6989 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6991 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6992 device->shader_backend = select_shader_backend(adapter, device_type);
6994 memset(&shader_caps, 0, sizeof(shader_caps));
6995 device->shader_backend->shader_get_caps(device_type, &adapter->gl_info, &shader_caps);
6996 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6997 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6998 device->vs_clipping = shader_caps.VSClipping;
7000 memset(&ffp_caps, 0, sizeof(ffp_caps));
7001 fragment_pipeline = select_fragment_implementation(adapter, device_type);
7002 device->frag_pipe = fragment_pipeline;
7003 fragment_pipeline->get_caps(device_type, &adapter->gl_info, &ffp_caps);
7004 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7005 device->max_ffp_texture_stages = ffp_caps.MaxTextureBlendStages;
7007 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7008 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7011 ERR("Failed to compile state table, hr %#x.\n", hr);
7012 IWineD3D_Release(device->wined3d);
7016 device->blitter = select_blit_implementation(adapter, device_type);
7022 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7023 DWORD rep = This->StateTable[state].representative;
7024 struct wined3d_context *context;
7029 for(i = 0; i < This->numContexts; i++) {
7030 context = This->contexts[i];
7031 if(isStateDirty(context, rep)) continue;
7033 context->dirtyArray[context->numDirtyEntries++] = rep;
7036 context->isStateDirty[idx] |= (1 << shift);
7040 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7042 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.device;
7043 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7044 *width = device->pbufferWidth;
7045 *height = device->pbufferHeight;
7048 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7050 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7051 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7052 *width = surface->pow2Width;
7053 *height = surface->pow2Height;
7056 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7058 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7059 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7060 * current context's drawable, which is the size of the back buffer of the swapchain
7061 * the active context belongs to. The back buffer of the swapchain is stored as the
7062 * surface the context belongs to. */
7063 *width = surface->currentDesc.Width;
7064 *height = surface->currentDesc.Height;
7067 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7068 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7070 if (device->filter_messages)
7072 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7073 window, message, wparam, lparam);
7074 return DefWindowProcW(window, message, wparam, lparam);
7077 if (message == WM_DESTROY)
7079 TRACE("unregister window %p.\n", window);
7080 wined3d_unregister_window(window);
7083 return CallWindowProcW(proc, window, message, wparam, lparam);