push 5c57339901c8d80068fee18365e7574a1e8d922a
[wine/hacks.git] / dlls / wined3d / device.c
blob90da2a0606058925ead14e0eb4b58ae78e8ca751
1 /*
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
29 #include "config.h"
30 #include <stdio.h>
31 #ifdef HAVE_FLOAT_H
32 # include <float.h>
33 #endif
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 */
48 0.0f, /* Range */
49 0.0f, /* Falloff */
50 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
51 0.0f, /* Theta */
52 0.0f /* Phi */
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:
73 return GL_POINTS;
75 case WINED3DPT_LINELIST:
76 return GL_LINES;
78 case WINED3DPT_LINESTRIP:
79 return GL_LINE_STRIP;
81 case WINED3DPT_TRIANGLELIST:
82 return GL_TRIANGLES;
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;
102 default:
103 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
104 return GL_NONE;
108 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
110 switch(primitive_type)
112 case GL_POINTS:
113 return WINED3DPT_POINTLIST;
115 case GL_LINES:
116 return WINED3DPT_LINELIST;
118 case GL_LINE_STRIP:
119 return WINED3DPT_LINESTRIP;
121 case GL_TRIANGLES:
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;
142 default:
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;
166 else
168 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
169 *regnum = ~0U;
170 return FALSE;
173 return TRUE;
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;
184 unsigned int i;
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;
199 BOOL stride_used;
200 unsigned int idx;
201 DWORD stride;
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]);
212 buffer_object = 0;
213 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
215 else
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);
228 buffer_object = 0;
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");
236 if (fixup)
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;
244 if (!warned)
246 /* This may be bad with the fixed function pipeline. */
247 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
248 warned = TRUE;
253 data += element->offset;
255 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
257 if (use_vshader)
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);
267 else
269 idx = element->output_slot;
270 stride_used = TRUE;
273 else
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));
279 stride_used = FALSE;
281 else
283 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
287 if (stride_used)
289 TRACE("Load %s array %u [usage %s, usage_idx %u, "
290 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
291 use_vshader ? "shader": "fixed function", idx,
292 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
293 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
295 stream_info->elements[idx].format_desc = element->format_desc;
296 stream_info->elements[idx].stride = stride;
297 stream_info->elements[idx].data = data;
298 stream_info->elements[idx].stream_idx = element->input_slot;
299 stream_info->elements[idx].buffer_object = buffer_object;
301 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
303 stream_info->swizzle_map |= 1 << idx;
305 stream_info->use_map |= 1 << idx;
309 /* Now call PreLoad on all the vertex buffers. In the very rare case
310 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
311 * The vertex buffer can now use the strided structure in the device instead of finding its
312 * own again.
314 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
315 * once in there. */
316 for (i = 0; i < stream_count; ++i)
318 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
319 if (vb) IWineD3DBuffer_PreLoad(vb);
323 static void stream_info_element_from_strided(IWineD3DDeviceImpl *This,
324 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
326 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, &This->adapter->gl_info);
327 e->format_desc = format_desc;
328 e->stride = strided->dwStride;
329 e->data = strided->lpData;
330 e->stream_idx = 0;
331 e->buffer_object = 0;
334 void device_stream_info_from_strided(IWineD3DDeviceImpl *This,
335 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
337 unsigned int i;
339 memset(stream_info, 0, sizeof(*stream_info));
341 if (strided->position.lpData)
342 stream_info_element_from_strided(This, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
343 if (strided->normal.lpData)
344 stream_info_element_from_strided(This, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
345 if (strided->diffuse.lpData)
346 stream_info_element_from_strided(This, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
347 if (strided->specular.lpData)
348 stream_info_element_from_strided(This, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
350 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
352 if (strided->texCoords[i].lpData)
353 stream_info_element_from_strided(This, &strided->texCoords[i],
354 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
357 stream_info->position_transformed = strided->position_transformed;
359 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
361 if (!stream_info->elements[i].format_desc) continue;
363 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA)
364 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
366 stream_info->swizzle_map |= 1 << i;
368 stream_info->use_map |= 1 << i;
372 /**********************************************************
373 * IUnknown parts follows
374 **********************************************************/
376 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
380 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
381 if (IsEqualGUID(riid, &IID_IUnknown)
382 || IsEqualGUID(riid, &IID_IWineD3DBase)
383 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
384 IUnknown_AddRef(iface);
385 *ppobj = This;
386 return S_OK;
388 *ppobj = NULL;
389 return E_NOINTERFACE;
392 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
394 ULONG refCount = InterlockedIncrement(&This->ref);
396 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
397 return refCount;
400 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
402 ULONG refCount = InterlockedDecrement(&This->ref);
404 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
406 if (!refCount) {
407 UINT i;
409 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
410 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
411 This->multistate_funcs[i] = NULL;
414 /* TODO: Clean up all the surfaces and textures! */
415 /* NOTE: You must release the parent if the object was created via a callback
416 ** ***************************/
418 if (!list_empty(&This->resources)) {
419 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
420 dumpResources(&This->resources);
423 if(This->contexts) ERR("Context array not freed!\n");
424 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
425 This->haveHardwareCursor = FALSE;
427 IWineD3D_Release(This->wineD3D);
428 This->wineD3D = NULL;
429 HeapFree(GetProcessHeap(), 0, This);
430 TRACE("Freed device %p\n", This);
431 This = NULL;
433 return refCount;
436 /**********************************************************
437 * IWineD3DDevice implementation follows
438 **********************************************************/
439 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
441 *pParent = This->parent;
442 IUnknown_AddRef(This->parent);
443 return WINED3D_OK;
446 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
447 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
449 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
450 struct wined3d_buffer *object;
451 HRESULT hr;
453 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
455 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
456 if (!object)
458 ERR("Failed to allocate memory\n");
459 return E_OUTOFMEMORY;
462 FIXME("Ignoring access flags (pool)\n");
464 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
465 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
466 if (FAILED(hr))
468 WARN("Failed to initialize buffer, hr %#x.\n", hr);
469 HeapFree(GetProcessHeap(), 0, object);
470 return hr;
472 object->desc = *desc;
474 TRACE("Created buffer %p.\n", object);
476 *buffer = (IWineD3DBuffer *)object;
478 return WINED3D_OK;
481 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size,
482 DWORD Usage, DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
483 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
486 struct wined3d_buffer *object;
487 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
488 HRESULT hr;
489 BOOL conv;
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));
502 if (!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);
511 if (FAILED(hr))
513 WARN("Failed to initialize buffer, hr %#x.\n", hr);
514 HeapFree(GetProcessHeap(), 0, object);
515 return hr;
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
533 * dx7 apps.
534 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
535 * more. In this call we can convert dx7 buffers too.
537 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
538 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
539 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
540 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
541 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
542 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
543 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
544 } else if(dxVersion <= 7 && conv) {
545 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
546 } else {
547 object->flags |= WINED3D_BUFFER_CREATEBO;
549 return WINED3D_OK;
552 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
553 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
554 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
557 struct wined3d_buffer *object;
558 HRESULT hr;
560 TRACE("(%p) Creating index buffer\n", This);
562 /* Allocate the storage for the device */
563 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
564 if (!object)
566 ERR("Out of memory\n");
567 *ppIndexBuffer = NULL;
568 return WINED3DERR_OUTOFVIDEOMEMORY;
571 hr = buffer_init(object, This, Length, Usage, WINED3DFMT_UNKNOWN,
572 Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
573 if (FAILED(hr))
575 WARN("Failed to initialize buffer, hr %#x\n", hr);
576 HeapFree(GetProcessHeap(), 0, object);
577 return hr;
580 TRACE("Created buffer %p.\n", object);
582 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
583 object->flags |= WINED3D_BUFFER_CREATEBO;
586 *ppIndexBuffer = (IWineD3DBuffer *) object;
588 return WINED3D_OK;
591 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
592 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
595 IWineD3DStateBlockImpl *object;
596 HRESULT hr;
598 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
599 if(!object)
601 ERR("Failed to allocate stateblock memory.\n");
602 return E_OUTOFMEMORY;
605 hr = stateblock_init(object, This, type, parent);
606 if (FAILED(hr))
608 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
609 HeapFree(GetProcessHeap(), 0, object);
610 return hr;
613 TRACE("Created stateblock %p.\n", object);
614 *stateblock = (IWineD3DStateBlock *)object;
616 return WINED3D_OK;
619 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
620 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
621 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
622 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
625 IWineD3DSurfaceImpl *object;
626 HRESULT hr;
628 TRACE("(%p) Create surface\n",This);
630 if (Impl == SURFACE_OPENGL && !This->adapter)
632 ERR("OpenGL surfaces are not available without OpenGL.\n");
633 return WINED3DERR_NOTAVAILABLE;
636 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
637 if (!object)
639 ERR("Failed to allocate surface memory.\n");
640 *ppSurface = NULL;
641 return WINED3DERR_OUTOFVIDEOMEMORY;
644 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
645 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
646 if (FAILED(hr))
648 WARN("Failed to initialize surface, returning %#x.\n", hr);
649 HeapFree(GetProcessHeap(), 0, object);
650 *ppSurface = NULL;
651 return hr;
654 TRACE("(%p) : Created surface %p\n", This, object);
656 *ppSurface = (IWineD3DSurface *)object;
658 return hr;
661 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
662 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
664 struct wined3d_rendertarget_view *object;
666 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
667 if (!object)
669 ERR("Failed to allocate memory\n");
670 return E_OUTOFMEMORY;
673 object->vtbl = &wined3d_rendertarget_view_vtbl;
674 object->refcount = 1;
675 IWineD3DResource_AddRef(resource);
676 object->resource = resource;
677 object->parent = parent;
679 *rendertarget_view = (IWineD3DRendertargetView *)object;
681 return WINED3D_OK;
684 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
685 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
686 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
689 IWineD3DTextureImpl *object;
690 HRESULT hr;
692 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
693 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
694 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
696 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
697 if (!object)
699 ERR("Out of memory\n");
700 *ppTexture = NULL;
701 return WINED3DERR_OUTOFVIDEOMEMORY;
704 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
705 if (FAILED(hr))
707 WARN("Failed to initialize texture, returning %#x\n", hr);
708 HeapFree(GetProcessHeap(), 0, object);
709 *ppTexture = NULL;
710 return hr;
713 *ppTexture = (IWineD3DTexture *)object;
715 TRACE("(%p) : Created texture %p\n", This, object);
717 return WINED3D_OK;
720 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
721 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
722 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
725 IWineD3DVolumeTextureImpl *object;
726 HRESULT hr;
728 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
729 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
731 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
732 if (!object)
734 ERR("Out of memory\n");
735 *ppVolumeTexture = NULL;
736 return WINED3DERR_OUTOFVIDEOMEMORY;
739 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
740 if (FAILED(hr))
742 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
743 HeapFree(GetProcessHeap(), 0, object);
744 *ppVolumeTexture = NULL;
745 return hr;
748 TRACE("(%p) : Created volume texture %p.\n", This, object);
749 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
751 return WINED3D_OK;
754 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
755 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
756 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
759 IWineD3DVolumeImpl *object;
760 HRESULT hr;
762 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
763 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
765 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
766 if (!object)
768 ERR("Out of memory\n");
769 *ppVolume = NULL;
770 return WINED3DERR_OUTOFVIDEOMEMORY;
773 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
774 if (FAILED(hr))
776 WARN("Failed to initialize volume, returning %#x.\n", hr);
777 HeapFree(GetProcessHeap(), 0, object);
778 return hr;
781 TRACE("(%p) : Created volume %p.\n", This, object);
782 *ppVolume = (IWineD3DVolume *)object;
784 return WINED3D_OK;
787 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
788 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
789 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
792 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
793 HRESULT hr;
795 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
796 if (!object)
798 ERR("Out of memory\n");
799 *ppCubeTexture = NULL;
800 return WINED3DERR_OUTOFVIDEOMEMORY;
803 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
804 if (FAILED(hr))
806 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
807 HeapFree(GetProcessHeap(), 0, object);
808 *ppCubeTexture = NULL;
809 return hr;
812 TRACE("(%p) : Created Cube Texture %p\n", This, object);
813 *ppCubeTexture = (IWineD3DCubeTexture *)object;
815 return WINED3D_OK;
818 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
820 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
821 HRESULT hr = WINED3DERR_NOTAVAILABLE;
822 const IWineD3DQueryVtbl *vtable;
824 /* Just a check to see if we support this type of query */
825 switch(Type) {
826 case WINED3DQUERYTYPE_OCCLUSION:
827 TRACE("(%p) occlusion query\n", This);
828 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
829 hr = WINED3D_OK;
830 else
831 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
833 vtable = &IWineD3DOcclusionQuery_Vtbl;
834 break;
836 case WINED3DQUERYTYPE_EVENT:
837 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
838 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
839 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
841 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
843 vtable = &IWineD3DEventQuery_Vtbl;
844 hr = WINED3D_OK;
845 break;
847 case WINED3DQUERYTYPE_VCACHE:
848 case WINED3DQUERYTYPE_RESOURCEMANAGER:
849 case WINED3DQUERYTYPE_VERTEXSTATS:
850 case WINED3DQUERYTYPE_TIMESTAMP:
851 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
852 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
853 case WINED3DQUERYTYPE_PIPELINETIMINGS:
854 case WINED3DQUERYTYPE_INTERFACETIMINGS:
855 case WINED3DQUERYTYPE_VERTEXTIMINGS:
856 case WINED3DQUERYTYPE_PIXELTIMINGS:
857 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
858 case WINED3DQUERYTYPE_CACHEUTILIZATION:
859 default:
860 /* Use the base Query vtable until we have a special one for each query */
861 vtable = &IWineD3DQuery_Vtbl;
862 FIXME("(%p) Unhandled query type %d\n", This, Type);
864 if(NULL == ppQuery || hr != WINED3D_OK) {
865 return hr;
868 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
869 if(!object)
871 ERR("Out of memory\n");
872 *ppQuery = NULL;
873 return WINED3DERR_OUTOFVIDEOMEMORY;
876 object->lpVtbl = vtable;
877 object->type = Type;
878 object->state = QUERY_CREATED;
879 object->wineD3DDevice = This;
880 object->parent = parent;
881 object->ref = 1;
883 *ppQuery = (IWineD3DQuery *)object;
885 /* allocated the 'extended' data based on the type of query requested */
886 switch(Type){
887 case WINED3DQUERYTYPE_OCCLUSION:
888 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
889 ((struct wined3d_occlusion_query *)object->extendedData)->context = NULL;
890 break;
892 case WINED3DQUERYTYPE_EVENT:
893 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query));
894 ((struct wined3d_event_query *)object->extendedData)->context = NULL;
895 break;
897 case WINED3DQUERYTYPE_VCACHE:
898 case WINED3DQUERYTYPE_RESOURCEMANAGER:
899 case WINED3DQUERYTYPE_VERTEXSTATS:
900 case WINED3DQUERYTYPE_TIMESTAMP:
901 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
902 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
903 case WINED3DQUERYTYPE_PIPELINETIMINGS:
904 case WINED3DQUERYTYPE_INTERFACETIMINGS:
905 case WINED3DQUERYTYPE_VERTEXTIMINGS:
906 case WINED3DQUERYTYPE_PIXELTIMINGS:
907 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
908 case WINED3DQUERYTYPE_CACHEUTILIZATION:
909 default:
910 object->extendedData = 0;
911 FIXME("(%p) Unhandled query type %d\n",This , Type);
913 TRACE("(%p) : Created Query %p\n", This, object);
914 return WINED3D_OK;
917 /*****************************************************************************
918 * IWineD3DDeviceImpl_SetupFullscreenWindow
920 * Helper function that modifies a HWND's Style and ExStyle for proper
921 * fullscreen use.
923 * Params:
924 * iface: Pointer to the IWineD3DDevice interface
925 * window: Window to setup
927 *****************************************************************************/
928 static LONG fullscreen_style(LONG orig_style) {
929 LONG style = orig_style;
930 style &= ~WS_CAPTION;
931 style &= ~WS_THICKFRAME;
933 /* Make sure the window is managed, otherwise we won't get keyboard input */
934 style |= WS_POPUP | WS_SYSMENU;
936 return style;
939 static LONG fullscreen_exStyle(LONG orig_exStyle) {
940 LONG exStyle = orig_exStyle;
942 /* Filter out window decorations */
943 exStyle &= ~WS_EX_WINDOWEDGE;
944 exStyle &= ~WS_EX_CLIENTEDGE;
946 return exStyle;
949 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
952 LONG style, exStyle;
953 /* Don't do anything if an original style is stored.
954 * That shouldn't happen
956 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
957 if (This->style || This->exStyle) {
958 ERR("(%p): Want to change the window parameters of HWND %p, but "
959 "another style is stored for restoration afterwards\n", This, window);
962 /* Get the parameters and save them */
963 style = GetWindowLongW(window, GWL_STYLE);
964 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
965 This->style = style;
966 This->exStyle = exStyle;
968 style = fullscreen_style(style);
969 exStyle = fullscreen_exStyle(exStyle);
971 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
972 This->style, This->exStyle, style, exStyle);
974 SetWindowLongW(window, GWL_STYLE, style);
975 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
977 /* Inform the window about the update. */
978 SetWindowPos(window, HWND_TOP, 0, 0,
979 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
982 /*****************************************************************************
983 * IWineD3DDeviceImpl_RestoreWindow
985 * Helper function that restores a windows' properties when taking it out
986 * of fullscreen mode
988 * Params:
989 * iface: Pointer to the IWineD3DDevice interface
990 * window: Window to setup
992 *****************************************************************************/
993 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
995 LONG style, exStyle;
997 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
998 * switch, do nothing
1000 if (!This->style && !This->exStyle) return;
1002 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1003 This, window, This->style, This->exStyle);
1005 style = GetWindowLongW(window, GWL_STYLE);
1006 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1008 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1009 * Some applications change it before calling Reset() when switching between windowed and
1010 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1012 if(style == fullscreen_style(This->style) &&
1013 exStyle == fullscreen_style(This->exStyle)) {
1014 SetWindowLongW(window, GWL_STYLE, This->style);
1015 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1018 /* Delete the old values */
1019 This->style = 0;
1020 This->exStyle = 0;
1022 /* Inform the window about the update */
1023 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1024 0, 0, 0, 0, /* Pos, Size, ignored */
1025 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1028 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1029 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1030 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1031 IUnknown *parent, WINED3DSURFTYPE surface_type)
1033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1035 HDC hDc;
1036 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1037 HRESULT hr;
1038 BOOL displaymode_set = FALSE;
1039 WINED3DDISPLAYMODE Mode;
1040 const struct GlPixelFormatDesc *format_desc;
1042 TRACE("(%p) : Created Additional Swap Chain\n", This);
1044 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1045 * does a device hold a reference to a swap chain giving them a lifetime of the device
1046 * or does the swap chain notify the device of its destruction.
1047 *******************************/
1049 /* Check the params */
1050 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1051 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1052 return WINED3DERR_INVALIDCALL;
1053 } else if (pPresentationParameters->BackBufferCount > 1) {
1054 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1057 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1058 if(!object)
1060 ERR("Out of memory\n");
1061 *ppSwapChain = NULL;
1062 return WINED3DERR_OUTOFVIDEOMEMORY;
1065 switch(surface_type) {
1066 case SURFACE_GDI:
1067 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1068 break;
1069 case SURFACE_OPENGL:
1070 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1071 break;
1072 case SURFACE_UNKNOWN:
1073 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1074 HeapFree(GetProcessHeap(), 0, object);
1075 return WINED3DERR_INVALIDCALL;
1077 object->wineD3DDevice = This;
1078 object->parent = parent;
1079 object->ref = 1;
1081 *ppSwapChain = (IWineD3DSwapChain *)object;
1083 /*********************
1084 * Lookup the window Handle and the relating X window handle
1085 ********************/
1087 /* Setup hwnd we are using, plus which display this equates to */
1088 object->win_handle = pPresentationParameters->hDeviceWindow;
1089 if (!object->win_handle) {
1090 object->win_handle = This->createParms.hFocusWindow;
1092 if(!pPresentationParameters->Windowed && object->win_handle) {
1093 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1094 pPresentationParameters->BackBufferWidth,
1095 pPresentationParameters->BackBufferHeight);
1098 hDc = GetDC(object->win_handle);
1099 TRACE("Using hDc %p\n", hDc);
1101 if (NULL == hDc) {
1102 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1103 return WINED3DERR_NOTAVAILABLE;
1106 /* Get info on the current display setup */
1107 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1108 object->orig_width = Mode.Width;
1109 object->orig_height = Mode.Height;
1110 object->orig_fmt = Mode.Format;
1111 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1113 if (pPresentationParameters->Windowed &&
1114 ((pPresentationParameters->BackBufferWidth == 0) ||
1115 (pPresentationParameters->BackBufferHeight == 0) ||
1116 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1118 RECT Rect;
1119 GetClientRect(object->win_handle, &Rect);
1121 if (pPresentationParameters->BackBufferWidth == 0) {
1122 pPresentationParameters->BackBufferWidth = Rect.right;
1123 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1125 if (pPresentationParameters->BackBufferHeight == 0) {
1126 pPresentationParameters->BackBufferHeight = Rect.bottom;
1127 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1129 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1130 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1131 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1135 /* Put the correct figures in the presentation parameters */
1136 TRACE("Copying across presentation parameters\n");
1137 object->presentParms = *pPresentationParameters;
1139 TRACE("calling rendertarget CB\n");
1140 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1141 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1142 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1143 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1144 if (SUCCEEDED(hr)) {
1145 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1146 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1147 if(surface_type == SURFACE_OPENGL) {
1148 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1150 } else {
1151 ERR("Failed to create the front buffer\n");
1152 goto error;
1155 /*********************
1156 * Windowed / Fullscreen
1157 *******************/
1160 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1161 * so we should really check to see if there is a fullscreen swapchain already
1162 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1163 **************************************/
1165 if (!pPresentationParameters->Windowed) {
1166 WINED3DDISPLAYMODE mode;
1169 /* Change the display settings */
1170 mode.Width = pPresentationParameters->BackBufferWidth;
1171 mode.Height = pPresentationParameters->BackBufferHeight;
1172 mode.Format = pPresentationParameters->BackBufferFormat;
1173 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1175 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1176 displaymode_set = TRUE;
1180 * Create an opengl context for the display visual
1181 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1182 * use different properties after that point in time. FIXME: How to handle when requested format
1183 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1184 * it chooses is identical to the one already being used!
1185 **********************************/
1186 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1188 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1189 if(!object->context) {
1190 ERR("Failed to create the context array\n");
1191 hr = E_OUTOFMEMORY;
1192 goto error;
1194 object->num_contexts = 1;
1196 if(surface_type == SURFACE_OPENGL) {
1197 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1198 if (!object->context[0]) {
1199 ERR("Failed to create a new context\n");
1200 hr = WINED3DERR_NOTAVAILABLE;
1201 goto error;
1202 } else {
1203 TRACE("Context created (HWND=%p, glContext=%p)\n",
1204 object->win_handle, object->context[0]->glCtx);
1208 /*********************
1209 * Create the back, front and stencil buffers
1210 *******************/
1211 if(object->presentParms.BackBufferCount > 0) {
1212 UINT i;
1214 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1215 if(!object->backBuffer) {
1216 ERR("Out of memory\n");
1217 hr = E_OUTOFMEMORY;
1218 goto error;
1221 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1222 TRACE("calling rendertarget CB\n");
1223 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1224 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1225 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1226 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1227 if(SUCCEEDED(hr)) {
1228 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1229 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1230 } else {
1231 ERR("Cannot create new back buffer\n");
1232 goto error;
1234 if(surface_type == SURFACE_OPENGL) {
1235 ENTER_GL();
1236 glDrawBuffer(GL_BACK);
1237 checkGLcall("glDrawBuffer(GL_BACK)");
1238 LEAVE_GL();
1241 } else {
1242 object->backBuffer = NULL;
1244 /* Single buffering - draw to front buffer */
1245 if(surface_type == SURFACE_OPENGL) {
1246 ENTER_GL();
1247 glDrawBuffer(GL_FRONT);
1248 checkGLcall("glDrawBuffer(GL_FRONT)");
1249 LEAVE_GL();
1253 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1254 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1255 TRACE("Creating depth stencil buffer\n");
1256 if (This->auto_depth_stencil_buffer == NULL ) {
1257 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1258 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1259 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1260 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1261 &This->auto_depth_stencil_buffer);
1262 if (SUCCEEDED(hr)) {
1263 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1264 } else {
1265 ERR("Failed to create the auto depth stencil\n");
1266 goto error;
1271 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1273 TRACE("Created swapchain %p\n", object);
1274 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1275 return WINED3D_OK;
1277 error:
1278 if (displaymode_set) {
1279 DEVMODEW devmode;
1280 RECT clip_rc;
1282 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1283 ClipCursor(NULL);
1285 /* Change the display settings */
1286 memset(&devmode, 0, sizeof(devmode));
1287 devmode.dmSize = sizeof(devmode);
1288 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1289 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1290 devmode.dmPelsWidth = object->orig_width;
1291 devmode.dmPelsHeight = object->orig_height;
1292 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1295 if (object->backBuffer) {
1296 UINT i;
1297 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1298 if (object->backBuffer[i]) IWineD3DSurface_Release(object->backBuffer[i]);
1300 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1301 object->backBuffer = NULL;
1303 if(object->context && object->context[0])
1304 DestroyContext(This, object->context[0]);
1305 if (object->frontBuffer) IWineD3DSurface_Release(object->frontBuffer);
1306 HeapFree(GetProcessHeap(), 0, object);
1307 return hr;
1310 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1311 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1313 TRACE("(%p)\n", This);
1315 return This->NumberOfSwapChains;
1318 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1320 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1322 if(iSwapChain < This->NumberOfSwapChains) {
1323 *pSwapChain = This->swapchains[iSwapChain];
1324 IWineD3DSwapChain_AddRef(*pSwapChain);
1325 TRACE("(%p) returning %p\n", This, *pSwapChain);
1326 return WINED3D_OK;
1327 } else {
1328 TRACE("Swapchain out of range\n");
1329 *pSwapChain = NULL;
1330 return WINED3DERR_INVALIDCALL;
1334 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1335 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1336 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1339 IWineD3DVertexDeclarationImpl *object = NULL;
1340 HRESULT hr;
1342 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1343 iface, declaration, parent, elements, element_count);
1345 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1346 if(!object)
1348 ERR("Failed to allocate vertex declaration memory.\n");
1349 return E_OUTOFMEMORY;
1352 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1353 if (FAILED(hr))
1355 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1356 HeapFree(GetProcessHeap(), 0, object);
1357 return hr;
1360 TRACE("Created verrtex declaration %p.\n", object);
1361 *declaration = (IWineD3DVertexDeclaration *)object;
1363 return WINED3D_OK;
1366 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1367 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1369 unsigned int idx, idx2;
1370 unsigned int offset;
1371 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1372 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1373 BOOL has_blend_idx = has_blend &&
1374 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1375 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1376 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1377 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1378 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1379 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1380 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1382 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1383 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1384 WINED3DVERTEXELEMENT *elements = NULL;
1386 unsigned int size;
1387 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1388 if (has_blend_idx) num_blends--;
1390 /* Compute declaration size */
1391 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1392 has_psize + has_diffuse + has_specular + num_textures;
1394 /* convert the declaration */
1395 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1396 if (!elements) return ~0U;
1398 idx = 0;
1399 if (has_pos) {
1400 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1401 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1402 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1404 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1405 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1406 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1408 else {
1409 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1410 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1412 elements[idx].usage_idx = 0;
1413 idx++;
1415 if (has_blend && (num_blends > 0)) {
1416 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1417 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1418 else {
1419 switch(num_blends) {
1420 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1421 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1422 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1423 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1424 default:
1425 ERR("Unexpected amount of blend values: %u\n", num_blends);
1428 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1429 elements[idx].usage_idx = 0;
1430 idx++;
1432 if (has_blend_idx) {
1433 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1434 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1435 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1436 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1437 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1438 else
1439 elements[idx].format = WINED3DFMT_R32_FLOAT;
1440 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1441 elements[idx].usage_idx = 0;
1442 idx++;
1444 if (has_normal) {
1445 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1446 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1447 elements[idx].usage_idx = 0;
1448 idx++;
1450 if (has_psize) {
1451 elements[idx].format = WINED3DFMT_R32_FLOAT;
1452 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1453 elements[idx].usage_idx = 0;
1454 idx++;
1456 if (has_diffuse) {
1457 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1458 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1459 elements[idx].usage_idx = 0;
1460 idx++;
1462 if (has_specular) {
1463 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1464 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1465 elements[idx].usage_idx = 1;
1466 idx++;
1468 for (idx2 = 0; idx2 < num_textures; idx2++) {
1469 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1470 switch (numcoords) {
1471 case WINED3DFVF_TEXTUREFORMAT1:
1472 elements[idx].format = WINED3DFMT_R32_FLOAT;
1473 break;
1474 case WINED3DFVF_TEXTUREFORMAT2:
1475 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1476 break;
1477 case WINED3DFVF_TEXTUREFORMAT3:
1478 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1479 break;
1480 case WINED3DFVF_TEXTUREFORMAT4:
1481 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1482 break;
1484 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1485 elements[idx].usage_idx = idx2;
1486 idx++;
1489 /* Now compute offsets, and initialize the rest of the fields */
1490 for (idx = 0, offset = 0; idx < size; ++idx)
1492 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1493 elements[idx].input_slot = 0;
1494 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1495 elements[idx].offset = offset;
1496 offset += format_desc->component_count * format_desc->component_size;
1499 *ppVertexElements = elements;
1500 return size;
1503 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1504 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1505 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1507 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1508 WINED3DVERTEXELEMENT *elements;
1509 unsigned int size;
1510 DWORD hr;
1512 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1514 size = ConvertFvfToDeclaration(This, fvf, &elements);
1515 if (size == ~0U) return E_OUTOFMEMORY;
1517 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1518 HeapFree(GetProcessHeap(), 0, elements);
1519 return hr;
1522 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1523 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1524 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1525 const struct wined3d_parent_ops *parent_ops)
1527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1528 IWineD3DVertexShaderImpl *object;
1529 HRESULT hr;
1531 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1532 if (!object)
1534 ERR("Failed to allocate shader memory.\n");
1535 return E_OUTOFMEMORY;
1538 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1539 if (FAILED(hr))
1541 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1542 HeapFree(GetProcessHeap(), 0, object);
1543 return hr;
1546 TRACE("Created vertex shader %p.\n", object);
1547 *ppVertexShader = (IWineD3DVertexShader *)object;
1549 return WINED3D_OK;
1552 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1553 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1554 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1555 const struct wined3d_parent_ops *parent_ops)
1557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1558 IWineD3DPixelShaderImpl *object;
1559 HRESULT hr;
1561 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1562 if (!object)
1564 ERR("Failed to allocate shader memory.\n");
1565 return E_OUTOFMEMORY;
1568 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1569 if (FAILED(hr))
1571 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1572 HeapFree(GetProcessHeap(), 0, object);
1573 return hr;
1576 TRACE("Created pixel shader %p.\n", object);
1577 *ppPixelShader = (IWineD3DPixelShader *)object;
1579 return WINED3D_OK;
1582 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1583 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1586 IWineD3DPaletteImpl *object;
1587 HRESULT hr;
1588 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1590 /* Create the new object */
1591 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1592 if(!object) {
1593 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1594 return E_OUTOFMEMORY;
1597 object->lpVtbl = &IWineD3DPalette_Vtbl;
1598 object->ref = 1;
1599 object->Flags = Flags;
1600 object->parent = Parent;
1601 object->wineD3DDevice = This;
1602 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1603 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1605 if(!object->hpal) {
1606 HeapFree( GetProcessHeap(), 0, object);
1607 return E_OUTOFMEMORY;
1610 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1611 if(FAILED(hr)) {
1612 IWineD3DPalette_Release((IWineD3DPalette *) object);
1613 return hr;
1616 *Palette = (IWineD3DPalette *) object;
1618 return WINED3D_OK;
1621 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1622 HBITMAP hbm;
1623 BITMAP bm;
1624 HRESULT hr;
1625 HDC dcb = NULL, dcs = NULL;
1626 WINEDDCOLORKEY colorkey;
1628 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1629 if(hbm)
1631 GetObjectA(hbm, sizeof(BITMAP), &bm);
1632 dcb = CreateCompatibleDC(NULL);
1633 if(!dcb) goto out;
1634 SelectObject(dcb, hbm);
1636 else
1638 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1639 * couldn't be loaded
1641 memset(&bm, 0, sizeof(bm));
1642 bm.bmWidth = 32;
1643 bm.bmHeight = 32;
1646 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1647 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1648 NULL, &wined3d_null_parent_ops);
1649 if(FAILED(hr)) {
1650 ERR("Wine logo requested, but failed to create surface\n");
1651 goto out;
1654 if(dcb) {
1655 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1656 if(FAILED(hr)) goto out;
1657 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1658 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1660 colorkey.dwColorSpaceLowValue = 0;
1661 colorkey.dwColorSpaceHighValue = 0;
1662 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1663 } else {
1664 /* Fill the surface with a white color to show that wined3d is there */
1665 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1668 out:
1669 if(dcb) {
1670 DeleteDC(dcb);
1672 if(hbm) {
1673 DeleteObject(hbm);
1675 return;
1678 /* Context activation is done by the caller. */
1679 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1680 unsigned int i;
1681 /* Under DirectX you can have texture stage operations even if no texture is
1682 bound, whereas opengl will only do texture operations when a valid texture is
1683 bound. We emulate this by creating dummy textures and binding them to each
1684 texture stage, but disable all stages by default. Hence if a stage is enabled
1685 then the default texture will kick in until replaced by a SetTexture call */
1686 ENTER_GL();
1688 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1689 /* The dummy texture does not have client storage backing */
1690 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1691 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1693 for (i = 0; i < GL_LIMITS(textures); i++) {
1694 GLubyte white = 255;
1696 /* Make appropriate texture active */
1697 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1698 checkGLcall("glActiveTextureARB");
1700 /* Generate an opengl texture name */
1701 glGenTextures(1, &This->dummyTextureName[i]);
1702 checkGLcall("glGenTextures");
1703 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1705 /* Generate a dummy 2d texture (not using 1d because they cause many
1706 * DRI drivers fall back to sw) */
1707 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1708 checkGLcall("glBindTexture");
1710 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1711 checkGLcall("glTexImage2D");
1713 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1714 /* Reenable because if supported it is enabled by default */
1715 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1716 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1719 LEAVE_GL();
1722 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1723 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1726 IWineD3DSwapChainImpl *swapchain = NULL;
1727 HRESULT hr;
1728 DWORD state;
1729 unsigned int i;
1731 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1733 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1734 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1736 /* TODO: Test if OpenGL is compiled in and loaded */
1738 TRACE("(%p) : Creating stateblock\n", This);
1739 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1740 hr = IWineD3DDevice_CreateStateBlock(iface,
1741 WINED3DSBT_INIT,
1742 (IWineD3DStateBlock **)&This->stateBlock,
1743 NULL);
1744 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1745 WARN("Failed to create stateblock\n");
1746 goto err_out;
1748 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1749 This->updateStateBlock = This->stateBlock;
1750 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1752 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1753 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1755 This->NumberOfPalettes = 1;
1756 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1757 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1758 ERR("Out of memory!\n");
1759 goto err_out;
1761 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1762 if(!This->palettes[0]) {
1763 ERR("Out of memory!\n");
1764 goto err_out;
1766 for (i = 0; i < 256; ++i) {
1767 This->palettes[0][i].peRed = 0xFF;
1768 This->palettes[0][i].peGreen = 0xFF;
1769 This->palettes[0][i].peBlue = 0xFF;
1770 This->palettes[0][i].peFlags = 0xFF;
1772 This->currentPalette = 0;
1774 /* Initialize the texture unit mapping to a 1:1 mapping */
1775 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1776 if (state < GL_LIMITS(fragment_samplers)) {
1777 This->texUnitMap[state] = state;
1778 This->rev_tex_unit_map[state] = state;
1779 } else {
1780 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1781 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1785 /* Setup the implicit swapchain. This also initializes a context. */
1786 TRACE("Creating implicit swapchain\n");
1787 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1788 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1789 if (FAILED(hr))
1791 WARN("Failed to create implicit swapchain\n");
1792 goto err_out;
1795 This->NumberOfSwapChains = 1;
1796 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1797 if(!This->swapchains) {
1798 ERR("Out of memory!\n");
1799 goto err_out;
1801 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1803 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1804 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1805 This->render_targets[0] = swapchain->backBuffer[0];
1807 else {
1808 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1809 This->render_targets[0] = swapchain->frontBuffer;
1811 IWineD3DSurface_AddRef(This->render_targets[0]);
1813 /* Depth Stencil support */
1814 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1815 if (NULL != This->stencilBufferTarget) {
1816 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1819 hr = This->shader_backend->shader_alloc_private(iface);
1820 if(FAILED(hr)) {
1821 TRACE("Shader private data couldn't be allocated\n");
1822 goto err_out;
1824 hr = This->frag_pipe->alloc_private(iface);
1825 if(FAILED(hr)) {
1826 TRACE("Fragment pipeline private data couldn't be allocated\n");
1827 goto err_out;
1829 hr = This->blitter->alloc_private(iface);
1830 if(FAILED(hr)) {
1831 TRACE("Blitter private data couldn't be allocated\n");
1832 goto err_out;
1835 /* Set up some starting GL setup */
1837 /* Setup all the devices defaults */
1838 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1839 create_dummy_textures(This);
1841 ENTER_GL();
1843 /* Initialize the current view state */
1844 This->view_ident = 1;
1845 This->contexts[0]->last_was_rhw = 0;
1846 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1847 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1849 switch(wined3d_settings.offscreen_rendering_mode) {
1850 case ORM_FBO:
1851 case ORM_PBUFFER:
1852 This->offscreenBuffer = GL_BACK;
1853 break;
1855 case ORM_BACKBUFFER:
1857 if (context_get_current()->aux_buffers > 0)
1859 TRACE("Using auxilliary buffer for offscreen rendering\n");
1860 This->offscreenBuffer = GL_AUX0;
1861 } else {
1862 TRACE("Using back buffer for offscreen rendering\n");
1863 This->offscreenBuffer = GL_BACK;
1868 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1869 LEAVE_GL();
1871 /* Clear the screen */
1872 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1873 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1874 0x00, 1.0f, 0);
1876 This->d3d_initialized = TRUE;
1878 if(wined3d_settings.logo) {
1879 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1881 This->highest_dirty_ps_const = 0;
1882 This->highest_dirty_vs_const = 0;
1883 return WINED3D_OK;
1885 err_out:
1886 HeapFree(GetProcessHeap(), 0, This->render_targets);
1887 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1888 HeapFree(GetProcessHeap(), 0, This->swapchains);
1889 This->NumberOfSwapChains = 0;
1890 if(This->palettes) {
1891 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1892 HeapFree(GetProcessHeap(), 0, This->palettes);
1894 This->NumberOfPalettes = 0;
1895 if(swapchain) {
1896 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1898 if(This->stateBlock) {
1899 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1900 This->stateBlock = NULL;
1902 if (This->blit_priv) {
1903 This->blitter->free_private(iface);
1905 if (This->fragment_priv) {
1906 This->frag_pipe->free_private(iface);
1908 if (This->shader_priv) {
1909 This->shader_backend->shader_free_private(iface);
1911 return hr;
1914 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1915 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1918 IWineD3DSwapChainImpl *swapchain = NULL;
1919 HRESULT hr;
1921 /* Setup the implicit swapchain */
1922 TRACE("Creating implicit swapchain\n");
1923 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1924 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1925 if (FAILED(hr))
1927 WARN("Failed to create implicit swapchain\n");
1928 goto err_out;
1931 This->NumberOfSwapChains = 1;
1932 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1933 if(!This->swapchains) {
1934 ERR("Out of memory!\n");
1935 goto err_out;
1937 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1938 return WINED3D_OK;
1940 err_out:
1941 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1942 return hr;
1945 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1947 IWineD3DResource_UnLoad(resource);
1948 IWineD3DResource_Release(resource);
1949 return WINED3D_OK;
1952 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1953 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1956 const struct wined3d_context *context;
1957 const struct wined3d_gl_info *gl_info;
1958 int sampler;
1959 UINT i;
1960 TRACE("(%p)\n", This);
1962 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1964 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1965 * it was created. Thus make sure a context is active for the glDelete* calls
1967 context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
1968 gl_info = context->gl_info;
1970 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1972 /* Unload resources */
1973 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1975 TRACE("Deleting high order patches\n");
1976 for(i = 0; i < PATCHMAP_SIZE; i++) {
1977 struct list *e1, *e2;
1978 struct WineD3DRectPatch *patch;
1979 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1980 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1981 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1985 /* Delete the palette conversion shader if it is around */
1986 if(This->paletteConversionShader) {
1987 ENTER_GL();
1988 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
1989 LEAVE_GL();
1990 This->paletteConversionShader = 0;
1993 /* Delete the pbuffer context if there is any */
1994 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1996 /* Delete the mouse cursor texture */
1997 if(This->cursorTexture) {
1998 ENTER_GL();
1999 glDeleteTextures(1, &This->cursorTexture);
2000 LEAVE_GL();
2001 This->cursorTexture = 0;
2004 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2005 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2007 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2008 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2011 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2012 * private data, it might contain opengl pointers
2014 if(This->depth_blt_texture) {
2015 ENTER_GL();
2016 glDeleteTextures(1, &This->depth_blt_texture);
2017 LEAVE_GL();
2018 This->depth_blt_texture = 0;
2020 if (This->depth_blt_rb) {
2021 ENTER_GL();
2022 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2023 LEAVE_GL();
2024 This->depth_blt_rb = 0;
2025 This->depth_blt_rb_w = 0;
2026 This->depth_blt_rb_h = 0;
2029 /* Release the update stateblock */
2030 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2031 if(This->updateStateBlock != This->stateBlock)
2032 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2034 This->updateStateBlock = NULL;
2036 { /* because were not doing proper internal refcounts releasing the primary state block
2037 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2038 to set this->stateBlock = NULL; first */
2039 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2040 This->stateBlock = NULL;
2042 /* Release the stateblock */
2043 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2044 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2048 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2049 This->blitter->free_private(iface);
2050 This->frag_pipe->free_private(iface);
2051 This->shader_backend->shader_free_private(iface);
2053 /* Release the buffers (with sanity checks)*/
2054 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2055 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2056 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2057 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2059 This->stencilBufferTarget = NULL;
2061 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2062 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2063 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2065 TRACE("Setting rendertarget to NULL\n");
2066 This->render_targets[0] = NULL;
2068 if (This->auto_depth_stencil_buffer) {
2069 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
2071 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2073 This->auto_depth_stencil_buffer = NULL;
2076 for(i=0; i < This->NumberOfSwapChains; i++) {
2077 TRACE("Releasing the implicit swapchain %d\n", i);
2078 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2079 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2083 HeapFree(GetProcessHeap(), 0, This->swapchains);
2084 This->swapchains = NULL;
2085 This->NumberOfSwapChains = 0;
2087 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2088 HeapFree(GetProcessHeap(), 0, This->palettes);
2089 This->palettes = NULL;
2090 This->NumberOfPalettes = 0;
2092 HeapFree(GetProcessHeap(), 0, This->render_targets);
2093 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2094 This->render_targets = NULL;
2095 This->draw_buffers = NULL;
2097 This->d3d_initialized = FALSE;
2098 return WINED3D_OK;
2101 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2103 unsigned int i;
2105 for(i=0; i < This->NumberOfSwapChains; i++) {
2106 TRACE("Releasing the implicit swapchain %d\n", i);
2107 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2108 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2112 HeapFree(GetProcessHeap(), 0, This->swapchains);
2113 This->swapchains = NULL;
2114 This->NumberOfSwapChains = 0;
2115 return WINED3D_OK;
2118 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2119 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2120 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2122 * There is no way to deactivate thread safety once it is enabled.
2124 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2127 /*For now just store the flag(needed in case of ddraw) */
2128 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2130 return;
2133 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2134 const WINED3DDISPLAYMODE* pMode) {
2135 DEVMODEW devmode;
2136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2137 LONG ret;
2138 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2139 RECT clip_rc;
2141 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2143 /* Resize the screen even without a window:
2144 * The app could have unset it with SetCooperativeLevel, but not called
2145 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2146 * but we don't have any hwnd
2149 memset(&devmode, 0, sizeof(devmode));
2150 devmode.dmSize = sizeof(devmode);
2151 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2152 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2153 devmode.dmPelsWidth = pMode->Width;
2154 devmode.dmPelsHeight = pMode->Height;
2156 devmode.dmDisplayFrequency = pMode->RefreshRate;
2157 if (pMode->RefreshRate != 0) {
2158 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2161 /* Only change the mode if necessary */
2162 if( (This->ddraw_width == pMode->Width) &&
2163 (This->ddraw_height == pMode->Height) &&
2164 (This->ddraw_format == pMode->Format) &&
2165 (pMode->RefreshRate == 0) ) {
2166 return WINED3D_OK;
2169 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2170 if (ret != DISP_CHANGE_SUCCESSFUL) {
2171 if(devmode.dmDisplayFrequency != 0) {
2172 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2173 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2174 devmode.dmDisplayFrequency = 0;
2175 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2177 if(ret != DISP_CHANGE_SUCCESSFUL) {
2178 return WINED3DERR_NOTAVAILABLE;
2182 /* Store the new values */
2183 This->ddraw_width = pMode->Width;
2184 This->ddraw_height = pMode->Height;
2185 This->ddraw_format = pMode->Format;
2187 /* And finally clip mouse to our screen */
2188 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2189 ClipCursor(&clip_rc);
2191 return WINED3D_OK;
2194 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2195 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2196 *ppD3D= This->wineD3D;
2197 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2198 IWineD3D_AddRef(*ppD3D);
2199 return WINED3D_OK;
2202 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2205 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2206 (This->adapter->TextureRam/(1024*1024)),
2207 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2208 /* return simulated texture memory left */
2209 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2212 /*****
2213 * Get / Set Stream Source
2214 *****/
2215 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2216 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2218 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2219 IWineD3DBuffer *oldSrc;
2221 if (StreamNumber >= MAX_STREAMS) {
2222 WARN("Stream out of range %d\n", StreamNumber);
2223 return WINED3DERR_INVALIDCALL;
2224 } else if(OffsetInBytes & 0x3) {
2225 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2226 return WINED3DERR_INVALIDCALL;
2229 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2230 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2232 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2234 if(oldSrc == pStreamData &&
2235 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2236 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2237 TRACE("Application is setting the old values over, nothing to do\n");
2238 return WINED3D_OK;
2241 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2242 if (pStreamData) {
2243 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2244 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2247 /* Handle recording of state blocks */
2248 if (This->isRecordingState) {
2249 TRACE("Recording... not performing anything\n");
2250 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2251 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2252 return WINED3D_OK;
2255 if (pStreamData != NULL) {
2256 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2257 IWineD3DBuffer_AddRef(pStreamData);
2259 if (oldSrc != NULL) {
2260 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2261 IWineD3DBuffer_Release(oldSrc);
2264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2266 return WINED3D_OK;
2269 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2270 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2274 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2275 This->stateBlock->streamSource[StreamNumber],
2276 This->stateBlock->streamOffset[StreamNumber],
2277 This->stateBlock->streamStride[StreamNumber]);
2279 if (StreamNumber >= MAX_STREAMS) {
2280 WARN("Stream out of range %d\n", StreamNumber);
2281 return WINED3DERR_INVALIDCALL;
2283 *pStream = This->stateBlock->streamSource[StreamNumber];
2284 *pStride = This->stateBlock->streamStride[StreamNumber];
2285 if (pOffset) {
2286 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2289 if (*pStream != NULL) {
2290 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2292 return WINED3D_OK;
2295 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2297 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2298 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2300 /* Verify input at least in d3d9 this is invalid*/
2301 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2302 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2303 return WINED3DERR_INVALIDCALL;
2305 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2306 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2307 return WINED3DERR_INVALIDCALL;
2309 if( Divider == 0 ){
2310 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2311 return WINED3DERR_INVALIDCALL;
2314 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2315 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2317 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2318 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2320 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2321 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2322 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2325 return WINED3D_OK;
2328 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2331 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2332 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2334 TRACE("(%p) : returning %d\n", This, *Divider);
2336 return WINED3D_OK;
2339 /*****
2340 * Get / Set & Multiply Transform
2341 *****/
2342 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2345 /* Most of this routine, comments included copied from ddraw tree initially: */
2346 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2348 /* Handle recording of state blocks */
2349 if (This->isRecordingState) {
2350 TRACE("Recording... not performing anything\n");
2351 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2352 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2353 return WINED3D_OK;
2357 * If the new matrix is the same as the current one,
2358 * we cut off any further processing. this seems to be a reasonable
2359 * optimization because as was noticed, some apps (warcraft3 for example)
2360 * tend towards setting the same matrix repeatedly for some reason.
2362 * From here on we assume that the new matrix is different, wherever it matters.
2364 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2365 TRACE("The app is setting the same matrix over again\n");
2366 return WINED3D_OK;
2367 } else {
2368 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2372 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2373 where ViewMat = Camera space, WorldMat = world space.
2375 In OpenGL, camera and world space is combined into GL_MODELVIEW
2376 matrix. The Projection matrix stay projection matrix.
2379 /* Capture the times we can just ignore the change for now */
2380 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2381 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2382 /* Handled by the state manager */
2385 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2386 return WINED3D_OK;
2389 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2391 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2392 *pMatrix = This->stateBlock->transforms[State];
2393 return WINED3D_OK;
2396 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2397 const WINED3DMATRIX *mat = NULL;
2398 WINED3DMATRIX temp;
2400 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2401 * below means it will be recorded in a state block change, but it
2402 * works regardless where it is recorded.
2403 * If this is found to be wrong, change to StateBlock.
2405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2406 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2408 if (State <= HIGHEST_TRANSFORMSTATE)
2410 mat = &This->updateStateBlock->transforms[State];
2411 } else {
2412 FIXME("Unhandled transform state!!\n");
2415 multiply_matrix(&temp, mat, pMatrix);
2417 /* Apply change via set transform - will reapply to eg. lights this way */
2418 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2421 /*****
2422 * Get / Set Light
2423 *****/
2424 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2425 you can reference any indexes you want as long as that number max are enabled at any
2426 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2427 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2428 but when recording, just build a chain pretty much of commands to be replayed. */
2430 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2431 float rho;
2432 PLIGHTINFOEL *object = NULL;
2433 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2434 struct list *e;
2436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2437 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2439 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2440 * the gl driver.
2442 if(!pLight) {
2443 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2444 return WINED3DERR_INVALIDCALL;
2447 switch(pLight->Type) {
2448 case WINED3DLIGHT_POINT:
2449 case WINED3DLIGHT_SPOT:
2450 case WINED3DLIGHT_PARALLELPOINT:
2451 case WINED3DLIGHT_GLSPOT:
2452 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2453 * most wanted
2455 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2457 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2458 return WINED3DERR_INVALIDCALL;
2460 break;
2462 case WINED3DLIGHT_DIRECTIONAL:
2463 /* Ignores attenuation */
2464 break;
2466 default:
2467 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2468 return WINED3DERR_INVALIDCALL;
2471 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2472 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2473 if(object->OriginalIndex == Index) break;
2474 object = NULL;
2477 if(!object) {
2478 TRACE("Adding new light\n");
2479 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2480 if(!object) {
2481 ERR("Out of memory error when allocating a light\n");
2482 return E_OUTOFMEMORY;
2484 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2485 object->glIndex = -1;
2486 object->OriginalIndex = Index;
2487 object->changed = TRUE;
2490 /* Initialize the object */
2491 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,
2492 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2493 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2494 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2495 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2496 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2497 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2499 /* Save away the information */
2500 object->OriginalParms = *pLight;
2502 switch (pLight->Type) {
2503 case WINED3DLIGHT_POINT:
2504 /* Position */
2505 object->lightPosn[0] = pLight->Position.x;
2506 object->lightPosn[1] = pLight->Position.y;
2507 object->lightPosn[2] = pLight->Position.z;
2508 object->lightPosn[3] = 1.0f;
2509 object->cutoff = 180.0f;
2510 /* FIXME: Range */
2511 break;
2513 case WINED3DLIGHT_DIRECTIONAL:
2514 /* Direction */
2515 object->lightPosn[0] = -pLight->Direction.x;
2516 object->lightPosn[1] = -pLight->Direction.y;
2517 object->lightPosn[2] = -pLight->Direction.z;
2518 object->lightPosn[3] = 0.0f;
2519 object->exponent = 0.0f;
2520 object->cutoff = 180.0f;
2521 break;
2523 case WINED3DLIGHT_SPOT:
2524 /* Position */
2525 object->lightPosn[0] = pLight->Position.x;
2526 object->lightPosn[1] = pLight->Position.y;
2527 object->lightPosn[2] = pLight->Position.z;
2528 object->lightPosn[3] = 1.0f;
2530 /* Direction */
2531 object->lightDirn[0] = pLight->Direction.x;
2532 object->lightDirn[1] = pLight->Direction.y;
2533 object->lightDirn[2] = pLight->Direction.z;
2534 object->lightDirn[3] = 1.0f;
2537 * opengl-ish and d3d-ish spot lights use too different models for the
2538 * light "intensity" as a function of the angle towards the main light direction,
2539 * so we only can approximate very roughly.
2540 * however spot lights are rather rarely used in games (if ever used at all).
2541 * furthermore if still used, probably nobody pays attention to such details.
2543 if (pLight->Falloff == 0) {
2544 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2545 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2546 * will always be 1.0 for both of them, and we don't have to care for the
2547 * rest of the rather complex calculation
2549 object->exponent = 0.0f;
2550 } else {
2551 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2552 if (rho < 0.0001f) rho = 0.0001f;
2553 object->exponent = -0.3f/logf(cosf(rho/2));
2555 if (object->exponent > 128.0f)
2557 object->exponent = 128.0f;
2559 object->cutoff = pLight->Phi*90/M_PI;
2561 /* FIXME: Range */
2562 break;
2564 default:
2565 FIXME("Unrecognized light type %d\n", pLight->Type);
2568 /* Update the live definitions if the light is currently assigned a glIndex */
2569 if (object->glIndex != -1 && !This->isRecordingState) {
2570 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2572 return WINED3D_OK;
2575 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2576 PLIGHTINFOEL *lightInfo = NULL;
2577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2578 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2579 struct list *e;
2580 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2582 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2583 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2584 if(lightInfo->OriginalIndex == Index) break;
2585 lightInfo = NULL;
2588 if (lightInfo == NULL) {
2589 TRACE("Light information requested but light not defined\n");
2590 return WINED3DERR_INVALIDCALL;
2593 *pLight = lightInfo->OriginalParms;
2594 return WINED3D_OK;
2597 /*****
2598 * Get / Set Light Enable
2599 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2600 *****/
2601 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2602 PLIGHTINFOEL *lightInfo = NULL;
2603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2604 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2605 struct list *e;
2606 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2608 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2609 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2610 if(lightInfo->OriginalIndex == Index) break;
2611 lightInfo = NULL;
2613 TRACE("Found light: %p\n", lightInfo);
2615 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2616 if (lightInfo == NULL) {
2618 TRACE("Light enabled requested but light not defined, so defining one!\n");
2619 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2621 /* Search for it again! Should be fairly quick as near head of list */
2622 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2623 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2624 if(lightInfo->OriginalIndex == Index) break;
2625 lightInfo = NULL;
2627 if (lightInfo == NULL) {
2628 FIXME("Adding default lights has failed dismally\n");
2629 return WINED3DERR_INVALIDCALL;
2633 lightInfo->enabledChanged = TRUE;
2634 if(!Enable) {
2635 if(lightInfo->glIndex != -1) {
2636 if(!This->isRecordingState) {
2637 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2640 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2641 lightInfo->glIndex = -1;
2642 } else {
2643 TRACE("Light already disabled, nothing to do\n");
2645 lightInfo->enabled = FALSE;
2646 } else {
2647 lightInfo->enabled = TRUE;
2648 if (lightInfo->glIndex != -1) {
2649 /* nop */
2650 TRACE("Nothing to do as light was enabled\n");
2651 } else {
2652 int i;
2653 /* Find a free gl light */
2654 for(i = 0; i < This->maxConcurrentLights; i++) {
2655 if(This->updateStateBlock->activeLights[i] == NULL) {
2656 This->updateStateBlock->activeLights[i] = lightInfo;
2657 lightInfo->glIndex = i;
2658 break;
2661 if(lightInfo->glIndex == -1) {
2662 /* Our tests show that Windows returns D3D_OK in this situation, even with
2663 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2664 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2665 * as well for those lights.
2667 * TODO: Test how this affects rendering
2669 WARN("Too many concurrently active lights\n");
2670 return WINED3D_OK;
2673 /* i == lightInfo->glIndex */
2674 if(!This->isRecordingState) {
2675 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2680 return WINED3D_OK;
2683 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2685 PLIGHTINFOEL *lightInfo = NULL;
2686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2687 struct list *e;
2688 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2689 TRACE("(%p) : for idx(%d)\n", This, Index);
2691 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2692 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2693 if(lightInfo->OriginalIndex == Index) break;
2694 lightInfo = NULL;
2697 if (lightInfo == NULL) {
2698 TRACE("Light enabled state requested but light not defined\n");
2699 return WINED3DERR_INVALIDCALL;
2701 /* true is 128 according to SetLightEnable */
2702 *pEnable = lightInfo->enabled ? 128 : 0;
2703 return WINED3D_OK;
2706 /*****
2707 * Get / Set Clip Planes
2708 *****/
2709 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2711 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2713 /* Validate Index */
2714 if (Index >= GL_LIMITS(clipplanes)) {
2715 TRACE("Application has requested clipplane this device doesn't support\n");
2716 return WINED3DERR_INVALIDCALL;
2719 This->updateStateBlock->changed.clipplane |= 1 << Index;
2721 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2722 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2723 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2724 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2725 TRACE("Application is setting old values over, nothing to do\n");
2726 return WINED3D_OK;
2729 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2730 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2731 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2732 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2734 /* Handle recording of state blocks */
2735 if (This->isRecordingState) {
2736 TRACE("Recording... not performing anything\n");
2737 return WINED3D_OK;
2740 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2742 return WINED3D_OK;
2745 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2747 TRACE("(%p) : for idx %d\n", This, Index);
2749 /* Validate Index */
2750 if (Index >= GL_LIMITS(clipplanes)) {
2751 TRACE("Application has requested clipplane this device doesn't support\n");
2752 return WINED3DERR_INVALIDCALL;
2755 pPlane[0] = This->stateBlock->clipplane[Index][0];
2756 pPlane[1] = This->stateBlock->clipplane[Index][1];
2757 pPlane[2] = This->stateBlock->clipplane[Index][2];
2758 pPlane[3] = This->stateBlock->clipplane[Index][3];
2759 return WINED3D_OK;
2762 /*****
2763 * Get / Set Clip Plane Status
2764 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2765 *****/
2766 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2768 FIXME("(%p) : stub\n", This);
2769 if (NULL == pClipStatus) {
2770 return WINED3DERR_INVALIDCALL;
2772 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2773 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2774 return WINED3D_OK;
2777 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2779 FIXME("(%p) : stub\n", This);
2780 if (NULL == pClipStatus) {
2781 return WINED3DERR_INVALIDCALL;
2783 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2784 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2785 return WINED3D_OK;
2788 /*****
2789 * Get / Set Material
2790 *****/
2791 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2794 This->updateStateBlock->changed.material = TRUE;
2795 This->updateStateBlock->material = *pMaterial;
2797 /* Handle recording of state blocks */
2798 if (This->isRecordingState) {
2799 TRACE("Recording... not performing anything\n");
2800 return WINED3D_OK;
2803 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2804 return WINED3D_OK;
2807 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2809 *pMaterial = This->updateStateBlock->material;
2810 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2811 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2812 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2813 pMaterial->Ambient.b, pMaterial->Ambient.a);
2814 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2815 pMaterial->Specular.b, pMaterial->Specular.a);
2816 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2817 pMaterial->Emissive.b, pMaterial->Emissive.a);
2818 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2820 return WINED3D_OK;
2823 /*****
2824 * Get / Set Indices
2825 *****/
2826 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2827 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2830 IWineD3DBuffer *oldIdxs;
2832 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2833 oldIdxs = This->updateStateBlock->pIndexData;
2835 This->updateStateBlock->changed.indices = TRUE;
2836 This->updateStateBlock->pIndexData = pIndexData;
2837 This->updateStateBlock->IndexFmt = fmt;
2839 /* Handle recording of state blocks */
2840 if (This->isRecordingState) {
2841 TRACE("Recording... not performing anything\n");
2842 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2843 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2844 return WINED3D_OK;
2847 if(oldIdxs != pIndexData) {
2848 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2849 if(pIndexData) {
2850 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2851 IWineD3DBuffer_AddRef(pIndexData);
2853 if(oldIdxs) {
2854 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2855 IWineD3DBuffer_Release(oldIdxs);
2859 return WINED3D_OK;
2862 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2866 *ppIndexData = This->stateBlock->pIndexData;
2868 /* up ref count on ppindexdata */
2869 if (*ppIndexData) {
2870 IWineD3DBuffer_AddRef(*ppIndexData);
2871 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2872 }else{
2873 TRACE("(%p) No index data set\n", This);
2875 TRACE("Returning %p\n", *ppIndexData);
2877 return WINED3D_OK;
2880 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2881 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2883 TRACE("(%p)->(%d)\n", This, BaseIndex);
2885 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2886 TRACE("Application is setting the old value over, nothing to do\n");
2887 return WINED3D_OK;
2890 This->updateStateBlock->baseVertexIndex = BaseIndex;
2892 if (This->isRecordingState) {
2893 TRACE("Recording... not performing anything\n");
2894 return WINED3D_OK;
2896 /* The base vertex index affects the stream sources */
2897 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2898 return WINED3D_OK;
2901 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2903 TRACE("(%p) : base_index %p\n", This, base_index);
2905 *base_index = This->stateBlock->baseVertexIndex;
2907 TRACE("Returning %u\n", *base_index);
2909 return WINED3D_OK;
2912 /*****
2913 * Get / Set Viewports
2914 *****/
2915 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2918 TRACE("(%p)\n", This);
2919 This->updateStateBlock->changed.viewport = TRUE;
2920 This->updateStateBlock->viewport = *pViewport;
2922 /* Handle recording of state blocks */
2923 if (This->isRecordingState) {
2924 TRACE("Recording... not performing anything\n");
2925 return WINED3D_OK;
2928 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2929 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2931 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2932 return WINED3D_OK;
2936 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2938 TRACE("(%p)\n", This);
2939 *pViewport = This->stateBlock->viewport;
2940 return WINED3D_OK;
2943 /*****
2944 * Get / Set Render States
2945 * TODO: Verify against dx9 definitions
2946 *****/
2947 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2950 DWORD oldValue = This->stateBlock->renderState[State];
2952 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2954 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2955 This->updateStateBlock->renderState[State] = Value;
2957 /* Handle recording of state blocks */
2958 if (This->isRecordingState) {
2959 TRACE("Recording... not performing anything\n");
2960 return WINED3D_OK;
2963 /* Compared here and not before the assignment to allow proper stateblock recording */
2964 if(Value == oldValue) {
2965 TRACE("Application is setting the old value over, nothing to do\n");
2966 } else {
2967 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2970 return WINED3D_OK;
2973 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2975 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2976 *pValue = This->stateBlock->renderState[State];
2977 return WINED3D_OK;
2980 /*****
2981 * Get / Set Sampler States
2982 * TODO: Verify against dx9 definitions
2983 *****/
2985 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2987 DWORD oldValue;
2989 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2990 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2992 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2993 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2996 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2997 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2998 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3001 * SetSampler is designed to allow for more than the standard up to 8 textures
3002 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3003 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3005 * http://developer.nvidia.com/object/General_FAQ.html#t6
3007 * There are two new settings for GForce
3008 * the sampler one:
3009 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3010 * and the texture one:
3011 * GL_MAX_TEXTURE_COORDS_ARB.
3012 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3013 ******************/
3015 oldValue = This->stateBlock->samplerState[Sampler][Type];
3016 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3017 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3019 /* Handle recording of state blocks */
3020 if (This->isRecordingState) {
3021 TRACE("Recording... not performing anything\n");
3022 return WINED3D_OK;
3025 if(oldValue == Value) {
3026 TRACE("Application is setting the old value over, nothing to do\n");
3027 return WINED3D_OK;
3030 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3032 return WINED3D_OK;
3035 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3038 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3039 This, Sampler, debug_d3dsamplerstate(Type), Type);
3041 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3042 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3045 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3046 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3047 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3049 *Value = This->stateBlock->samplerState[Sampler][Type];
3050 TRACE("(%p) : Returning %#x\n", This, *Value);
3052 return WINED3D_OK;
3055 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3058 This->updateStateBlock->changed.scissorRect = TRUE;
3059 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3060 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3061 return WINED3D_OK;
3063 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3065 if(This->isRecordingState) {
3066 TRACE("Recording... not performing anything\n");
3067 return WINED3D_OK;
3070 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3072 return WINED3D_OK;
3075 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3078 *pRect = This->updateStateBlock->scissorRect;
3079 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3080 return WINED3D_OK;
3083 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3085 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3087 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3089 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3090 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3092 This->updateStateBlock->vertexDecl = pDecl;
3093 This->updateStateBlock->changed.vertexDecl = TRUE;
3095 if (This->isRecordingState) {
3096 TRACE("Recording... not performing anything\n");
3097 return WINED3D_OK;
3098 } else if(pDecl == oldDecl) {
3099 /* Checked after the assignment to allow proper stateblock recording */
3100 TRACE("Application is setting the old declaration over, nothing to do\n");
3101 return WINED3D_OK;
3104 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3105 return WINED3D_OK;
3108 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3111 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3113 *ppDecl = This->stateBlock->vertexDecl;
3114 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3115 return WINED3D_OK;
3118 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3120 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3122 This->updateStateBlock->vertexShader = pShader;
3123 This->updateStateBlock->changed.vertexShader = TRUE;
3125 if (This->isRecordingState) {
3126 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3127 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3128 TRACE("Recording... not performing anything\n");
3129 return WINED3D_OK;
3130 } else if(oldShader == pShader) {
3131 /* Checked here to allow proper stateblock recording */
3132 TRACE("App is setting the old shader over, nothing to do\n");
3133 return WINED3D_OK;
3136 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3137 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3138 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3140 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3142 return WINED3D_OK;
3145 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3148 if (NULL == ppShader) {
3149 return WINED3DERR_INVALIDCALL;
3151 *ppShader = This->stateBlock->vertexShader;
3152 if( NULL != *ppShader)
3153 IWineD3DVertexShader_AddRef(*ppShader);
3155 TRACE("(%p) : returning %p\n", This, *ppShader);
3156 return WINED3D_OK;
3159 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3160 IWineD3DDevice *iface,
3161 UINT start,
3162 CONST BOOL *srcData,
3163 UINT count) {
3165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3166 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3168 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3169 iface, srcData, start, count);
3171 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3173 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3174 for (i = 0; i < cnt; i++)
3175 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3177 for (i = start; i < cnt + start; ++i) {
3178 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3181 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3183 return WINED3D_OK;
3186 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3187 IWineD3DDevice *iface,
3188 UINT start,
3189 BOOL *dstData,
3190 UINT count) {
3192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3193 int cnt = min(count, MAX_CONST_B - start);
3195 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3196 iface, dstData, start, count);
3198 if (dstData == NULL || cnt < 0)
3199 return WINED3DERR_INVALIDCALL;
3201 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3202 return WINED3D_OK;
3205 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3206 IWineD3DDevice *iface,
3207 UINT start,
3208 CONST int *srcData,
3209 UINT count) {
3211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3212 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3214 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3215 iface, srcData, start, count);
3217 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3219 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3220 for (i = 0; i < cnt; i++)
3221 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3222 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3224 for (i = start; i < cnt + start; ++i) {
3225 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3228 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3230 return WINED3D_OK;
3233 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3234 IWineD3DDevice *iface,
3235 UINT start,
3236 int *dstData,
3237 UINT count) {
3239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3240 int cnt = min(count, MAX_CONST_I - start);
3242 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3243 iface, dstData, start, count);
3245 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3246 return WINED3DERR_INVALIDCALL;
3248 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3249 return WINED3D_OK;
3252 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3253 IWineD3DDevice *iface,
3254 UINT start,
3255 CONST float *srcData,
3256 UINT count) {
3258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3259 UINT i;
3261 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3262 iface, srcData, start, count);
3264 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3265 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3266 return WINED3DERR_INVALIDCALL;
3268 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3269 if(TRACE_ON(d3d)) {
3270 for (i = 0; i < count; i++)
3271 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3272 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3275 if (!This->isRecordingState)
3277 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3278 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3281 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3282 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3284 return WINED3D_OK;
3287 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3288 IWineD3DDevice *iface,
3289 UINT start,
3290 float *dstData,
3291 UINT count) {
3293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3294 int cnt = min(count, This->d3d_vshader_constantF - start);
3296 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3297 iface, dstData, start, count);
3299 if (dstData == NULL || cnt < 0)
3300 return WINED3DERR_INVALIDCALL;
3302 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3303 return WINED3D_OK;
3306 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3307 DWORD i;
3308 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3310 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3314 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3316 DWORD i = This->rev_tex_unit_map[unit];
3317 DWORD j = This->texUnitMap[stage];
3319 This->texUnitMap[stage] = unit;
3320 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3322 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3325 This->rev_tex_unit_map[unit] = stage;
3326 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3328 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3332 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3333 int i;
3335 This->fixed_function_usage_map = 0;
3336 for (i = 0; i < MAX_TEXTURES; ++i) {
3337 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3338 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3339 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3340 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3341 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3342 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3343 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3344 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3346 if (color_op == WINED3DTOP_DISABLE) {
3347 /* Not used, and disable higher stages */
3348 break;
3351 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3352 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3353 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3354 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3355 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3356 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3357 This->fixed_function_usage_map |= (1 << i);
3360 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3361 This->fixed_function_usage_map |= (1 << (i + 1));
3366 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3367 unsigned int i, tex;
3368 WORD ffu_map;
3370 device_update_fixed_function_usage_map(This);
3371 ffu_map = This->fixed_function_usage_map;
3373 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3374 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3375 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3377 if (!(ffu_map & 1)) continue;
3379 if (This->texUnitMap[i] != i) {
3380 device_map_stage(This, i, i);
3381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3382 markTextureStagesDirty(This, i);
3385 return;
3388 /* Now work out the mapping */
3389 tex = 0;
3390 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3392 if (!(ffu_map & 1)) continue;
3394 if (This->texUnitMap[i] != tex) {
3395 device_map_stage(This, i, tex);
3396 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3397 markTextureStagesDirty(This, i);
3400 ++tex;
3404 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3405 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3406 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3407 unsigned int i;
3409 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3410 if (sampler_type[i] && This->texUnitMap[i] != i)
3412 device_map_stage(This, i, i);
3413 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3414 if (i < MAX_TEXTURES) {
3415 markTextureStagesDirty(This, i);
3421 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3422 const DWORD *vshader_sampler_tokens, DWORD unit)
3424 DWORD current_mapping = This->rev_tex_unit_map[unit];
3426 /* Not currently used */
3427 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3429 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3430 /* Used by a fragment sampler */
3432 if (!pshader_sampler_tokens) {
3433 /* No pixel shader, check fixed function */
3434 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3437 /* Pixel shader, check the shader's sampler map */
3438 return !pshader_sampler_tokens[current_mapping];
3441 /* Used by a vertex sampler */
3442 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3445 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3446 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3447 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3448 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3449 int start = min(MAX_COMBINED_SAMPLERS, GL_LIMITS(combined_samplers)) - 1;
3450 int i;
3452 if (ps) {
3453 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3455 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3456 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3457 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3460 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3461 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3462 if (vshader_sampler_type[i])
3464 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3466 /* Already mapped somewhere */
3467 continue;
3470 while (start >= 0) {
3471 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3473 device_map_stage(This, vsampler_idx, start);
3474 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3476 --start;
3477 break;
3480 --start;
3486 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3487 BOOL vs = use_vs(This->stateBlock);
3488 BOOL ps = use_ps(This->stateBlock);
3490 * Rules are:
3491 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3492 * that would be really messy and require shader recompilation
3493 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3494 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3496 if (ps) {
3497 device_map_psamplers(This);
3498 } else {
3499 device_map_fixed_function_samplers(This);
3502 if (vs) {
3503 device_map_vsamplers(This, ps);
3507 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3509 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3510 This->updateStateBlock->pixelShader = pShader;
3511 This->updateStateBlock->changed.pixelShader = TRUE;
3513 /* Handle recording of state blocks */
3514 if (This->isRecordingState) {
3515 TRACE("Recording... not performing anything\n");
3518 if (This->isRecordingState) {
3519 TRACE("Recording... not performing anything\n");
3520 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3521 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3522 return WINED3D_OK;
3525 if(pShader == oldShader) {
3526 TRACE("App is setting the old pixel shader over, nothing to do\n");
3527 return WINED3D_OK;
3530 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3531 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3533 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3534 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3536 return WINED3D_OK;
3539 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3540 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3542 if (NULL == ppShader) {
3543 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3544 return WINED3DERR_INVALIDCALL;
3547 *ppShader = This->stateBlock->pixelShader;
3548 if (NULL != *ppShader) {
3549 IWineD3DPixelShader_AddRef(*ppShader);
3551 TRACE("(%p) : returning %p\n", This, *ppShader);
3552 return WINED3D_OK;
3555 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3556 IWineD3DDevice *iface,
3557 UINT start,
3558 CONST BOOL *srcData,
3559 UINT count) {
3561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3562 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3564 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3565 iface, srcData, start, count);
3567 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3569 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3570 for (i = 0; i < cnt; i++)
3571 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3573 for (i = start; i < cnt + start; ++i) {
3574 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3577 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3579 return WINED3D_OK;
3582 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3583 IWineD3DDevice *iface,
3584 UINT start,
3585 BOOL *dstData,
3586 UINT count) {
3588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3589 int cnt = min(count, MAX_CONST_B - start);
3591 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3592 iface, dstData, start, count);
3594 if (dstData == NULL || cnt < 0)
3595 return WINED3DERR_INVALIDCALL;
3597 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3598 return WINED3D_OK;
3601 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3602 IWineD3DDevice *iface,
3603 UINT start,
3604 CONST int *srcData,
3605 UINT count) {
3607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3608 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3610 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3611 iface, srcData, start, count);
3613 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3615 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3616 for (i = 0; i < cnt; i++)
3617 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3618 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3620 for (i = start; i < cnt + start; ++i) {
3621 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3624 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3626 return WINED3D_OK;
3629 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3630 IWineD3DDevice *iface,
3631 UINT start,
3632 int *dstData,
3633 UINT count) {
3635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3636 int cnt = min(count, MAX_CONST_I - start);
3638 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3639 iface, dstData, start, count);
3641 if (dstData == NULL || cnt < 0)
3642 return WINED3DERR_INVALIDCALL;
3644 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3645 return WINED3D_OK;
3648 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3649 IWineD3DDevice *iface,
3650 UINT start,
3651 CONST float *srcData,
3652 UINT count) {
3654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3655 UINT i;
3657 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3658 iface, srcData, start, count);
3660 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3661 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3662 return WINED3DERR_INVALIDCALL;
3664 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3665 if(TRACE_ON(d3d)) {
3666 for (i = 0; i < count; i++)
3667 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3668 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3671 if (!This->isRecordingState)
3673 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3674 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3677 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3678 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3680 return WINED3D_OK;
3683 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3684 IWineD3DDevice *iface,
3685 UINT start,
3686 float *dstData,
3687 UINT count) {
3689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3690 int cnt = min(count, This->d3d_pshader_constantF - start);
3692 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3693 iface, dstData, start, count);
3695 if (dstData == NULL || cnt < 0)
3696 return WINED3DERR_INVALIDCALL;
3698 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3699 return WINED3D_OK;
3702 /* Context activation is done by the caller. */
3703 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3704 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3705 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3706 DWORD DestFVF)
3708 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3709 unsigned int i;
3710 WINED3DVIEWPORT vp;
3711 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3712 BOOL doClip;
3713 DWORD numTextures;
3715 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3717 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3720 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3722 ERR("Source has no position mask\n");
3723 return WINED3DERR_INVALIDCALL;
3726 /* We might access VBOs from this code, so hold the lock */
3727 ENTER_GL();
3729 if (dest->resource.allocatedMemory == NULL) {
3730 buffer_get_sysmem(dest);
3733 /* Get a pointer into the destination vbo(create one if none exists) and
3734 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3736 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
3738 dest->flags |= WINED3D_BUFFER_CREATEBO;
3739 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3742 if (dest->buffer_object)
3744 unsigned char extrabytes = 0;
3745 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3746 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3747 * this may write 4 extra bytes beyond the area that should be written
3749 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3750 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3751 if(!dest_conv_addr) {
3752 ERR("Out of memory\n");
3753 /* Continue without storing converted vertices */
3755 dest_conv = dest_conv_addr;
3758 /* Should I clip?
3759 * a) WINED3DRS_CLIPPING is enabled
3760 * b) WINED3DVOP_CLIP is passed
3762 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3763 static BOOL warned = FALSE;
3765 * The clipping code is not quite correct. Some things need
3766 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3767 * so disable clipping for now.
3768 * (The graphics in Half-Life are broken, and my processvertices
3769 * test crashes with IDirect3DDevice3)
3770 doClip = TRUE;
3772 doClip = FALSE;
3773 if(!warned) {
3774 warned = TRUE;
3775 FIXME("Clipping is broken and disabled for now\n");
3777 } else doClip = FALSE;
3778 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3780 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3781 WINED3DTS_VIEW,
3782 &view_mat);
3783 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3784 WINED3DTS_PROJECTION,
3785 &proj_mat);
3786 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3787 WINED3DTS_WORLDMATRIX(0),
3788 &world_mat);
3790 TRACE("View mat:\n");
3791 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);
3792 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);
3793 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);
3794 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);
3796 TRACE("Proj mat:\n");
3797 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);
3798 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);
3799 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);
3800 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);
3802 TRACE("World mat:\n");
3803 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);
3804 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);
3805 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);
3806 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);
3808 /* Get the viewport */
3809 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3810 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3811 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3813 multiply_matrix(&mat,&view_mat,&world_mat);
3814 multiply_matrix(&mat,&proj_mat,&mat);
3816 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3818 for (i = 0; i < dwCount; i+= 1) {
3819 unsigned int tex_index;
3821 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3822 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3823 /* The position first */
3824 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3825 const float *p = (const float *)(element->data + i * element->stride);
3826 float x, y, z, rhw;
3827 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3829 /* Multiplication with world, view and projection matrix */
3830 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);
3831 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);
3832 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);
3833 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);
3835 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3837 /* WARNING: The following things are taken from d3d7 and were not yet checked
3838 * against d3d8 or d3d9!
3841 /* Clipping conditions: From msdn
3843 * A vertex is clipped if it does not match the following requirements
3844 * -rhw < x <= rhw
3845 * -rhw < y <= rhw
3846 * 0 < z <= rhw
3847 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3849 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3850 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3854 if( !doClip ||
3855 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3856 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3857 ( rhw > eps ) ) ) {
3859 /* "Normal" viewport transformation (not clipped)
3860 * 1) The values are divided by rhw
3861 * 2) The y axis is negative, so multiply it with -1
3862 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3863 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3864 * 4) Multiply x with Width/2 and add Width/2
3865 * 5) The same for the height
3866 * 6) Add the viewpoint X and Y to the 2D coordinates and
3867 * The minimum Z value to z
3868 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3870 * Well, basically it's simply a linear transformation into viewport
3871 * coordinates
3874 x /= rhw;
3875 y /= rhw;
3876 z /= rhw;
3878 y *= -1;
3880 x *= vp.Width / 2;
3881 y *= vp.Height / 2;
3882 z *= vp.MaxZ - vp.MinZ;
3884 x += vp.Width / 2 + vp.X;
3885 y += vp.Height / 2 + vp.Y;
3886 z += vp.MinZ;
3888 rhw = 1 / rhw;
3889 } else {
3890 /* That vertex got clipped
3891 * Contrary to OpenGL it is not dropped completely, it just
3892 * undergoes a different calculation.
3894 TRACE("Vertex got clipped\n");
3895 x += rhw;
3896 y += rhw;
3898 x /= 2;
3899 y /= 2;
3901 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3902 * outside of the main vertex buffer memory. That needs some more
3903 * investigation...
3907 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3910 ( (float *) dest_ptr)[0] = x;
3911 ( (float *) dest_ptr)[1] = y;
3912 ( (float *) dest_ptr)[2] = z;
3913 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3915 dest_ptr += 3 * sizeof(float);
3917 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3918 dest_ptr += sizeof(float);
3921 if(dest_conv) {
3922 float w = 1 / rhw;
3923 ( (float *) dest_conv)[0] = x * w;
3924 ( (float *) dest_conv)[1] = y * w;
3925 ( (float *) dest_conv)[2] = z * w;
3926 ( (float *) dest_conv)[3] = w;
3928 dest_conv += 3 * sizeof(float);
3930 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3931 dest_conv += sizeof(float);
3935 if (DestFVF & WINED3DFVF_PSIZE) {
3936 dest_ptr += sizeof(DWORD);
3937 if(dest_conv) dest_conv += sizeof(DWORD);
3939 if (DestFVF & WINED3DFVF_NORMAL) {
3940 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3941 const float *normal = (const float *)(element->data + i * element->stride);
3942 /* AFAIK this should go into the lighting information */
3943 FIXME("Didn't expect the destination to have a normal\n");
3944 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3945 if(dest_conv) {
3946 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3950 if (DestFVF & WINED3DFVF_DIFFUSE) {
3951 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3952 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3953 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3955 static BOOL warned = FALSE;
3957 if(!warned) {
3958 ERR("No diffuse color in source, but destination has one\n");
3959 warned = TRUE;
3962 *( (DWORD *) dest_ptr) = 0xffffffff;
3963 dest_ptr += sizeof(DWORD);
3965 if(dest_conv) {
3966 *( (DWORD *) dest_conv) = 0xffffffff;
3967 dest_conv += sizeof(DWORD);
3970 else {
3971 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3972 if(dest_conv) {
3973 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3974 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3975 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3976 dest_conv += sizeof(DWORD);
3981 if (DestFVF & WINED3DFVF_SPECULAR)
3983 /* What's the color value in the feedback buffer? */
3984 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3985 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3986 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3988 static BOOL warned = FALSE;
3990 if(!warned) {
3991 ERR("No specular color in source, but destination has one\n");
3992 warned = TRUE;
3995 *( (DWORD *) dest_ptr) = 0xFF000000;
3996 dest_ptr += sizeof(DWORD);
3998 if(dest_conv) {
3999 *( (DWORD *) dest_conv) = 0xFF000000;
4000 dest_conv += sizeof(DWORD);
4003 else {
4004 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4005 if(dest_conv) {
4006 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4007 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4008 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4009 dest_conv += sizeof(DWORD);
4014 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4015 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4016 const float *tex_coord = (const float *)(element->data + i * element->stride);
4017 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4019 ERR("No source texture, but destination requests one\n");
4020 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4021 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4023 else {
4024 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4025 if(dest_conv) {
4026 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4032 if(dest_conv) {
4033 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4034 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4035 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4036 dwCount * get_flexible_vertex_size(DestFVF),
4037 dest_conv_addr));
4038 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4039 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4042 LEAVE_GL();
4044 return WINED3D_OK;
4046 #undef copy_and_next
4048 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4049 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4050 DWORD DestFVF)
4052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4053 struct wined3d_stream_info stream_info;
4054 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4055 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4057 if(pVertexDecl) {
4058 ERR("Output vertex declaration not implemented yet\n");
4061 /* Need any context to write to the vbo. */
4062 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4064 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4065 * control the streamIsUP flag, thus restore it afterwards.
4067 This->stateBlock->streamIsUP = FALSE;
4068 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4069 This->stateBlock->streamIsUP = streamWasUP;
4071 if(vbo || SrcStartIndex) {
4072 unsigned int i;
4073 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4074 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4076 * Also get the start index in, but only loop over all elements if there's something to add at all.
4078 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4080 struct wined3d_stream_info_element *e;
4082 if (!(stream_info.use_map & (1 << i))) continue;
4084 e = &stream_info.elements[i];
4085 if (e->buffer_object)
4087 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4088 e->buffer_object = 0;
4089 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4090 ENTER_GL();
4091 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4092 vb->buffer_object = 0;
4093 LEAVE_GL();
4095 if (e->data) e->data += e->stride * SrcStartIndex;
4099 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4100 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4103 /*****
4104 * Get / Set Texture Stage States
4105 * TODO: Verify against dx9 definitions
4106 *****/
4107 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4109 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4111 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4113 if (Stage >= MAX_TEXTURES) {
4114 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4115 return WINED3D_OK;
4118 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4119 This->updateStateBlock->textureState[Stage][Type] = Value;
4121 if (This->isRecordingState) {
4122 TRACE("Recording... not performing anything\n");
4123 return WINED3D_OK;
4126 /* Checked after the assignments to allow proper stateblock recording */
4127 if(oldValue == Value) {
4128 TRACE("App is setting the old value over, nothing to do\n");
4129 return WINED3D_OK;
4132 if(Stage > This->stateBlock->lowest_disabled_stage &&
4133 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4134 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4135 * Changes in other states are important on disabled stages too
4137 return WINED3D_OK;
4140 if(Type == WINED3DTSS_COLOROP) {
4141 unsigned int i;
4143 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4144 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4145 * they have to be disabled
4147 * The current stage is dirtified below.
4149 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4150 TRACE("Additionally dirtifying stage %u\n", i);
4151 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4153 This->stateBlock->lowest_disabled_stage = Stage;
4154 TRACE("New lowest disabled: %u\n", Stage);
4155 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4156 /* Previously disabled stage enabled. Stages above it may need enabling
4157 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4158 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4160 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4163 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4164 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4165 break;
4167 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4168 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4170 This->stateBlock->lowest_disabled_stage = i;
4171 TRACE("New lowest disabled: %u\n", i);
4175 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4177 return WINED3D_OK;
4180 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4182 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4183 *pValue = This->updateStateBlock->textureState[Stage][Type];
4184 return WINED3D_OK;
4187 /*****
4188 * Get / Set Texture
4189 *****/
4190 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4191 DWORD stage, IWineD3DBaseTexture *texture)
4193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4194 IWineD3DBaseTexture *prev;
4196 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4198 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4199 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4201 /* Windows accepts overflowing this array... we do not. */
4202 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4204 WARN("Ignoring invalid stage %u.\n", stage);
4205 return WINED3D_OK;
4208 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4209 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4211 WARN("Rejecting attempt to set scratch texture.\n");
4212 return WINED3DERR_INVALIDCALL;
4215 This->updateStateBlock->changed.textures |= 1 << stage;
4217 prev = This->updateStateBlock->textures[stage];
4218 TRACE("Previous texture %p.\n", prev);
4220 if (texture == prev)
4222 TRACE("App is setting the same texture again, nothing to do.\n");
4223 return WINED3D_OK;
4226 TRACE("Setting new texture to %p.\n", texture);
4227 This->updateStateBlock->textures[stage] = texture;
4229 if (This->isRecordingState)
4231 TRACE("Recording... not performing anything\n");
4233 if (texture) IWineD3DBaseTexture_AddRef(texture);
4234 if (prev) IWineD3DBaseTexture_Release(prev);
4236 return WINED3D_OK;
4239 if (texture)
4241 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4242 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4243 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4245 IWineD3DBaseTexture_AddRef(texture);
4247 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4249 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4252 if (!prev && stage < MAX_TEXTURES)
4254 /* The source arguments for color and alpha ops have different
4255 * meanings when a NULL texture is bound, so the COLOROP and
4256 * ALPHAOP have to be dirtified. */
4257 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4258 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4261 if (bind_count == 1) t->baseTexture.sampler = stage;
4264 if (prev)
4266 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4267 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4269 IWineD3DBaseTexture_Release(prev);
4271 if (!texture && stage < MAX_TEXTURES)
4273 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4277 if (bind_count && t->baseTexture.sampler == stage)
4279 unsigned int i;
4281 /* Search for other stages the texture is bound to. Shouldn't
4282 * happen if applications bind textures to a single stage only. */
4283 TRACE("Searching for other stages the texture is bound to.\n");
4284 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4286 if (This->updateStateBlock->textures[i] == prev)
4288 TRACE("Texture is also bound to stage %u.\n", i);
4289 t->baseTexture.sampler = i;
4290 break;
4296 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4298 return WINED3D_OK;
4301 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4304 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4306 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4307 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4310 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4311 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4312 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4315 *ppTexture=This->stateBlock->textures[Stage];
4316 if (*ppTexture)
4317 IWineD3DBaseTexture_AddRef(*ppTexture);
4319 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4321 return WINED3D_OK;
4324 /*****
4325 * Get Back Buffer
4326 *****/
4327 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4328 IWineD3DSurface **ppBackBuffer) {
4329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4330 IWineD3DSwapChain *swapChain;
4331 HRESULT hr;
4333 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4335 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4336 if (hr == WINED3D_OK) {
4337 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4338 IWineD3DSwapChain_Release(swapChain);
4339 } else {
4340 *ppBackBuffer = NULL;
4342 return hr;
4345 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4347 WARN("(%p) : stub, calling idirect3d for now\n", This);
4348 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4351 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4353 IWineD3DSwapChain *swapChain;
4354 HRESULT hr;
4356 if(iSwapChain > 0) {
4357 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4358 if (hr == WINED3D_OK) {
4359 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4360 IWineD3DSwapChain_Release(swapChain);
4361 } else {
4362 FIXME("(%p) Error getting display mode\n", This);
4364 } else {
4365 /* Don't read the real display mode,
4366 but return the stored mode instead. X11 can't change the color
4367 depth, and some apps are pretty angry if they SetDisplayMode from
4368 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4370 Also don't relay to the swapchain because with ddraw it's possible
4371 that there isn't a swapchain at all */
4372 pMode->Width = This->ddraw_width;
4373 pMode->Height = This->ddraw_height;
4374 pMode->Format = This->ddraw_format;
4375 pMode->RefreshRate = 0;
4376 hr = WINED3D_OK;
4379 return hr;
4382 /*****
4383 * Stateblock related functions
4384 *****/
4386 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4388 IWineD3DStateBlock *stateblock;
4389 HRESULT hr;
4391 TRACE("(%p)\n", This);
4393 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4395 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4396 if (FAILED(hr)) return hr;
4398 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4399 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4400 This->isRecordingState = TRUE;
4402 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4404 return WINED3D_OK;
4407 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4409 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4411 if (!This->isRecordingState) {
4412 WARN("(%p) not recording! returning error\n", This);
4413 *ppStateBlock = NULL;
4414 return WINED3DERR_INVALIDCALL;
4417 stateblock_init_contained_states(object);
4419 *ppStateBlock = (IWineD3DStateBlock*) object;
4420 This->isRecordingState = FALSE;
4421 This->updateStateBlock = This->stateBlock;
4422 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4423 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4424 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4425 return WINED3D_OK;
4428 /*****
4429 * Scene related functions
4430 *****/
4431 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4432 /* At the moment we have no need for any functionality at the beginning
4433 of a scene */
4434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4435 TRACE("(%p)\n", This);
4437 if(This->inScene) {
4438 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4439 return WINED3DERR_INVALIDCALL;
4441 This->inScene = TRUE;
4442 return WINED3D_OK;
4445 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4446 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4447 TRACE("(%p)\n", This);
4449 if(!This->inScene) {
4450 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4451 return WINED3DERR_INVALIDCALL;
4454 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4455 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4456 wglFlush();
4457 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4458 * fails
4461 This->inScene = FALSE;
4462 return WINED3D_OK;
4465 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4466 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4467 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4469 IWineD3DSwapChain *swapChain = NULL;
4470 int i;
4471 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4473 TRACE("(%p) Presenting the frame\n", This);
4475 for(i = 0 ; i < swapchains ; i ++) {
4477 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4478 TRACE("presentinng chain %d, %p\n", i, swapChain);
4479 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4480 IWineD3DSwapChain_Release(swapChain);
4483 return WINED3D_OK;
4486 /* Not called from the VTable (internal subroutine) */
4487 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4488 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4489 float Z, DWORD Stencil) {
4490 GLbitfield glMask = 0;
4491 unsigned int i;
4492 WINED3DRECT curRect;
4493 RECT vp_rect;
4494 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4495 UINT drawable_width, drawable_height;
4496 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4497 IWineD3DSwapChainImpl *swapchain = NULL;
4498 struct wined3d_context *context;
4500 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4501 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4502 * for the cleared parts, and the untouched parts.
4504 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4505 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4506 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4507 * checking all this if the dest surface is in the drawable anyway.
4509 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4510 while(1) {
4511 if(vp->X != 0 || vp->Y != 0 ||
4512 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4513 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4514 break;
4516 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4517 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4518 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4519 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4520 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4521 break;
4523 if(Count > 0 && pRects && (
4524 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4525 pRects[0].x2 < target->currentDesc.Width ||
4526 pRects[0].y2 < target->currentDesc.Height)) {
4527 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4528 break;
4530 break;
4534 context = ActivateContext(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4536 target->get_drawable_size(context, &drawable_width, &drawable_height);
4538 ENTER_GL();
4540 /* Only set the values up once, as they are not changing */
4541 if (Flags & WINED3DCLEAR_STENCIL) {
4542 glClearStencil(Stencil);
4543 checkGLcall("glClearStencil");
4544 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4545 glStencilMask(0xFFFFFFFF);
4548 if (Flags & WINED3DCLEAR_ZBUFFER) {
4549 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4550 glDepthMask(GL_TRUE);
4551 glClearDepth(Z);
4552 checkGLcall("glClearDepth");
4553 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4554 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4556 if (vp->X != 0 || vp->Y != 0 ||
4557 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4558 surface_load_ds_location(This->stencilBufferTarget, context, location);
4560 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4561 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4562 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4563 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4564 surface_load_ds_location(This->stencilBufferTarget, context, location);
4566 else if (Count > 0 && pRects && (
4567 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4568 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4569 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4570 surface_load_ds_location(This->stencilBufferTarget, context, location);
4574 if (Flags & WINED3DCLEAR_TARGET) {
4575 TRACE("Clearing screen with glClear to color %x\n", Color);
4576 glClearColor(D3DCOLOR_R(Color),
4577 D3DCOLOR_G(Color),
4578 D3DCOLOR_B(Color),
4579 D3DCOLOR_A(Color));
4580 checkGLcall("glClearColor");
4582 /* Clear ALL colors! */
4583 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4584 glMask = glMask | GL_COLOR_BUFFER_BIT;
4587 vp_rect.left = vp->X;
4588 vp_rect.top = vp->Y;
4589 vp_rect.right = vp->X + vp->Width;
4590 vp_rect.bottom = vp->Y + vp->Height;
4591 if (!(Count > 0 && pRects)) {
4592 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4593 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4595 if (context->render_offscreen)
4597 glScissor(vp_rect.left, vp_rect.top,
4598 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4599 } else {
4600 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4601 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4603 checkGLcall("glScissor");
4604 glClear(glMask);
4605 checkGLcall("glClear");
4606 } else {
4607 /* Now process each rect in turn */
4608 for (i = 0; i < Count; i++) {
4609 /* Note gl uses lower left, width/height */
4610 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4611 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4612 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4614 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4615 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4616 curRect.x1, (target->currentDesc.Height - curRect.y2),
4617 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4619 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4620 * The rectangle is not cleared, no error is returned, but further rectanlges are
4621 * still cleared if they are valid
4623 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4624 TRACE("Rectangle with negative dimensions, ignoring\n");
4625 continue;
4628 if (context->render_offscreen)
4630 glScissor(curRect.x1, curRect.y1,
4631 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4632 } else {
4633 glScissor(curRect.x1, drawable_height - curRect.y2,
4634 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4636 checkGLcall("glScissor");
4638 glClear(glMask);
4639 checkGLcall("glClear");
4643 /* Restore the old values (why..?) */
4644 if (Flags & WINED3DCLEAR_STENCIL) {
4645 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4647 if (Flags & WINED3DCLEAR_TARGET) {
4648 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4649 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4650 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4651 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4652 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4654 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4655 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4657 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4659 if (Flags & WINED3DCLEAR_ZBUFFER) {
4660 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4661 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4662 surface_modify_ds_location(This->stencilBufferTarget, location);
4665 LEAVE_GL();
4667 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
4668 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
4669 wglFlush();
4671 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
4674 return WINED3D_OK;
4677 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4678 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4680 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4682 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4683 Count, pRects, Flags, Color, Z, Stencil);
4685 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4686 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4687 /* TODO: What about depth stencil buffers without stencil bits? */
4688 return WINED3DERR_INVALIDCALL;
4691 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4694 /*****
4695 * Drawing functions
4696 *****/
4698 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4699 WINED3DPRIMITIVETYPE primitive_type)
4701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4703 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4705 This->updateStateBlock->changed.primitive_type = TRUE;
4706 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4709 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4710 WINED3DPRIMITIVETYPE *primitive_type)
4712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4714 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4716 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4718 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4721 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4725 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4727 if(!This->stateBlock->vertexDecl) {
4728 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4729 return WINED3DERR_INVALIDCALL;
4732 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4733 if(This->stateBlock->streamIsUP) {
4734 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4735 This->stateBlock->streamIsUP = FALSE;
4738 if(This->stateBlock->loadBaseVertexIndex != 0) {
4739 This->stateBlock->loadBaseVertexIndex = 0;
4740 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4742 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4743 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4744 return WINED3D_OK;
4747 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4749 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4750 UINT idxStride = 2;
4751 IWineD3DBuffer *pIB;
4752 GLuint vbo;
4754 pIB = This->stateBlock->pIndexData;
4755 if (!pIB) {
4756 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4757 * without an index buffer set. (The first time at least...)
4758 * D3D8 simply dies, but I doubt it can do much harm to return
4759 * D3DERR_INVALIDCALL there as well. */
4760 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4761 return WINED3DERR_INVALIDCALL;
4764 if(!This->stateBlock->vertexDecl) {
4765 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4766 return WINED3DERR_INVALIDCALL;
4769 if(This->stateBlock->streamIsUP) {
4770 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4771 This->stateBlock->streamIsUP = FALSE;
4773 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4775 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4777 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4778 idxStride = 2;
4779 } else {
4780 idxStride = 4;
4783 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4784 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4785 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4788 drawPrimitive(iface, index_count, startIndex, idxStride,
4789 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4791 return WINED3D_OK;
4794 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4795 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4798 IWineD3DBuffer *vb;
4800 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4801 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4803 if(!This->stateBlock->vertexDecl) {
4804 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4805 return WINED3DERR_INVALIDCALL;
4808 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4809 vb = This->stateBlock->streamSource[0];
4810 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4811 if (vb) IWineD3DBuffer_Release(vb);
4812 This->stateBlock->streamOffset[0] = 0;
4813 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4814 This->stateBlock->streamIsUP = TRUE;
4815 This->stateBlock->loadBaseVertexIndex = 0;
4817 /* TODO: Only mark dirty if drawing from a different UP address */
4818 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4820 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4822 /* MSDN specifies stream zero settings must be set to NULL */
4823 This->stateBlock->streamStride[0] = 0;
4824 This->stateBlock->streamSource[0] = NULL;
4826 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4827 * the new stream sources or use UP drawing again
4829 return WINED3D_OK;
4832 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4833 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4834 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4836 int idxStride;
4837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4838 IWineD3DBuffer *vb;
4839 IWineD3DBuffer *ib;
4841 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4842 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4844 if(!This->stateBlock->vertexDecl) {
4845 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4846 return WINED3DERR_INVALIDCALL;
4849 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4850 idxStride = 2;
4851 } else {
4852 idxStride = 4;
4855 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4856 vb = This->stateBlock->streamSource[0];
4857 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4858 if (vb) IWineD3DBuffer_Release(vb);
4859 This->stateBlock->streamIsUP = TRUE;
4860 This->stateBlock->streamOffset[0] = 0;
4861 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4863 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4864 This->stateBlock->baseVertexIndex = 0;
4865 This->stateBlock->loadBaseVertexIndex = 0;
4866 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4867 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4868 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4870 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4872 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4873 This->stateBlock->streamSource[0] = NULL;
4874 This->stateBlock->streamStride[0] = 0;
4875 ib = This->stateBlock->pIndexData;
4876 if(ib) {
4877 IWineD3DBuffer_Release(ib);
4878 This->stateBlock->pIndexData = NULL;
4880 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4881 * SetStreamSource to specify a vertex buffer
4884 return WINED3D_OK;
4887 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4888 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4892 /* Mark the state dirty until we have nicer tracking
4893 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4894 * that value.
4896 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4897 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4898 This->stateBlock->baseVertexIndex = 0;
4899 This->up_strided = DrawPrimStrideData;
4900 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4901 This->up_strided = NULL;
4902 return WINED3D_OK;
4905 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4906 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4907 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4910 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4912 /* Mark the state dirty until we have nicer tracking
4913 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4914 * that value.
4916 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4917 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4918 This->stateBlock->streamIsUP = TRUE;
4919 This->stateBlock->baseVertexIndex = 0;
4920 This->up_strided = DrawPrimStrideData;
4921 drawPrimitive(iface, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData);
4922 This->up_strided = NULL;
4923 return WINED3D_OK;
4926 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
4927 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
4928 * not callable by the app directly no parameter validation checks are needed here.
4930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4931 WINED3DLOCKED_BOX src;
4932 WINED3DLOCKED_BOX dst;
4933 HRESULT hr;
4934 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
4936 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4937 * dirtification to improve loading performance.
4939 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4940 if(FAILED(hr)) return hr;
4941 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4942 if(FAILED(hr)) {
4943 IWineD3DVolume_UnlockBox(pSourceVolume);
4944 return hr;
4947 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4949 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4950 if(FAILED(hr)) {
4951 IWineD3DVolume_UnlockBox(pSourceVolume);
4952 } else {
4953 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4955 return hr;
4958 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4959 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4961 HRESULT hr = WINED3D_OK;
4962 WINED3DRESOURCETYPE sourceType;
4963 WINED3DRESOURCETYPE destinationType;
4964 int i ,levels;
4966 /* TODO: think about moving the code into IWineD3DBaseTexture */
4968 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4970 /* verify that the source and destination textures aren't NULL */
4971 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4972 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4973 This, pSourceTexture, pDestinationTexture);
4974 hr = WINED3DERR_INVALIDCALL;
4977 if (pSourceTexture == pDestinationTexture) {
4978 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4979 This, pSourceTexture, pDestinationTexture);
4980 hr = WINED3DERR_INVALIDCALL;
4982 /* Verify that the source and destination textures are the same type */
4983 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4984 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4986 if (sourceType != destinationType) {
4987 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4988 This);
4989 hr = WINED3DERR_INVALIDCALL;
4992 /* check that both textures have the identical numbers of levels */
4993 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4994 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4995 hr = WINED3DERR_INVALIDCALL;
4998 if (WINED3D_OK == hr) {
4999 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5001 /* Make sure that the destination texture is loaded */
5002 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5004 /* Update every surface level of the texture */
5005 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5007 switch (sourceType) {
5008 case WINED3DRTYPE_TEXTURE:
5010 IWineD3DSurface *srcSurface;
5011 IWineD3DSurface *destSurface;
5013 for (i = 0 ; i < levels ; ++i) {
5014 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5015 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5016 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5017 IWineD3DSurface_Release(srcSurface);
5018 IWineD3DSurface_Release(destSurface);
5019 if (WINED3D_OK != hr) {
5020 WARN("(%p) : Call to update surface failed\n", This);
5021 return hr;
5025 break;
5026 case WINED3DRTYPE_CUBETEXTURE:
5028 IWineD3DSurface *srcSurface;
5029 IWineD3DSurface *destSurface;
5030 WINED3DCUBEMAP_FACES faceType;
5032 for (i = 0 ; i < levels ; ++i) {
5033 /* Update each cube face */
5034 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5035 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5036 if (WINED3D_OK != hr) {
5037 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5038 } else {
5039 TRACE("Got srcSurface %p\n", srcSurface);
5041 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5042 if (WINED3D_OK != hr) {
5043 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5044 } else {
5045 TRACE("Got desrSurface %p\n", destSurface);
5047 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5048 IWineD3DSurface_Release(srcSurface);
5049 IWineD3DSurface_Release(destSurface);
5050 if (WINED3D_OK != hr) {
5051 WARN("(%p) : Call to update surface failed\n", This);
5052 return hr;
5057 break;
5059 case WINED3DRTYPE_VOLUMETEXTURE:
5061 IWineD3DVolume *srcVolume = NULL;
5062 IWineD3DVolume *destVolume = NULL;
5064 for (i = 0 ; i < levels ; ++i) {
5065 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5066 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5067 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5068 IWineD3DVolume_Release(srcVolume);
5069 IWineD3DVolume_Release(destVolume);
5070 if (WINED3D_OK != hr) {
5071 WARN("(%p) : Call to update volume failed\n", This);
5072 return hr;
5076 break;
5078 default:
5079 FIXME("(%p) : Unsupported source and destination type\n", This);
5080 hr = WINED3DERR_INVALIDCALL;
5084 return hr;
5087 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5088 IWineD3DSwapChain *swapChain;
5089 HRESULT hr;
5090 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5091 if(hr == WINED3D_OK) {
5092 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5093 IWineD3DSwapChain_Release(swapChain);
5095 return hr;
5098 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5100 IWineD3DBaseTextureImpl *texture;
5101 DWORD i;
5103 TRACE("(%p) : %p\n", This, pNumPasses);
5105 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5106 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5107 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5108 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5110 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5111 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5112 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5115 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5116 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5118 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5119 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5120 return E_FAIL;
5122 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5123 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5124 return E_FAIL;
5126 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5127 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5128 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5129 return E_FAIL;
5133 /* return a sensible default */
5134 *pNumPasses = 1;
5136 TRACE("returning D3D_OK\n");
5137 return WINED3D_OK;
5140 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5142 int i;
5144 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5146 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5147 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
5148 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
5150 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5155 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5157 int j;
5158 UINT NewSize;
5159 PALETTEENTRY **palettes;
5161 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5163 if (PaletteNumber >= MAX_PALETTES) {
5164 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5165 return WINED3DERR_INVALIDCALL;
5168 if (PaletteNumber >= This->NumberOfPalettes) {
5169 NewSize = This->NumberOfPalettes;
5170 do {
5171 NewSize *= 2;
5172 } while(PaletteNumber >= NewSize);
5173 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5174 if (!palettes) {
5175 ERR("Out of memory!\n");
5176 return E_OUTOFMEMORY;
5178 This->palettes = palettes;
5179 This->NumberOfPalettes = NewSize;
5182 if (!This->palettes[PaletteNumber]) {
5183 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5184 if (!This->palettes[PaletteNumber]) {
5185 ERR("Out of memory!\n");
5186 return E_OUTOFMEMORY;
5190 for (j = 0; j < 256; ++j) {
5191 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5192 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5193 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5194 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5196 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5197 TRACE("(%p) : returning\n", This);
5198 return WINED3D_OK;
5201 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5203 int j;
5204 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5205 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5206 /* What happens in such situation isn't documented; Native seems to silently abort
5207 on such conditions. Return Invalid Call. */
5208 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5209 return WINED3DERR_INVALIDCALL;
5211 for (j = 0; j < 256; ++j) {
5212 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5213 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5214 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5215 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5217 TRACE("(%p) : returning\n", This);
5218 return WINED3D_OK;
5221 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5223 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5224 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5225 (tested with reference rasterizer). Return Invalid Call. */
5226 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5227 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5228 return WINED3DERR_INVALIDCALL;
5230 /*TODO: stateblocks */
5231 if (This->currentPalette != PaletteNumber) {
5232 This->currentPalette = PaletteNumber;
5233 dirtify_p8_texture_samplers(This);
5235 TRACE("(%p) : returning\n", This);
5236 return WINED3D_OK;
5239 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5241 if (PaletteNumber == NULL) {
5242 WARN("(%p) : returning Invalid Call\n", This);
5243 return WINED3DERR_INVALIDCALL;
5245 /*TODO: stateblocks */
5246 *PaletteNumber = This->currentPalette;
5247 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5248 return WINED3D_OK;
5251 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5253 static BOOL warned;
5254 if (!warned)
5256 FIXME("(%p) : stub\n", This);
5257 warned = TRUE;
5260 This->softwareVertexProcessing = bSoftware;
5261 return WINED3D_OK;
5265 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5267 static BOOL warned;
5268 if (!warned)
5270 FIXME("(%p) : stub\n", This);
5271 warned = TRUE;
5273 return This->softwareVertexProcessing;
5277 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5279 IWineD3DSwapChain *swapChain;
5280 HRESULT hr;
5282 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5284 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5285 if(hr == WINED3D_OK){
5286 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5287 IWineD3DSwapChain_Release(swapChain);
5288 }else{
5289 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5291 return hr;
5295 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5297 static BOOL warned;
5298 if(nSegments != 0.0f) {
5299 if (!warned)
5301 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5302 warned = TRUE;
5305 return WINED3D_OK;
5308 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5310 static BOOL warned;
5311 if (!warned)
5313 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5314 warned = TRUE;
5316 return 0.0f;
5319 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5321 /** TODO: remove casts to IWineD3DSurfaceImpl
5322 * NOTE: move code to surface to accomplish this
5323 ****************************************/
5324 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5325 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5326 int srcWidth, srcHeight;
5327 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5328 WINED3DFORMAT destFormat, srcFormat;
5329 UINT destSize;
5330 int srcLeft, destLeft, destTop;
5331 WINED3DPOOL srcPool, destPool;
5332 int offset = 0;
5333 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5334 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5335 GLenum dummy;
5336 DWORD sampler;
5337 int bpp;
5338 CONVERT_TYPES convert = NO_CONVERSION;
5340 WINED3DSURFACE_DESC winedesc;
5342 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5344 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5345 srcSurfaceWidth = winedesc.width;
5346 srcSurfaceHeight = winedesc.height;
5347 srcPool = winedesc.pool;
5348 srcFormat = winedesc.format;
5350 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5351 destSurfaceWidth = winedesc.width;
5352 destSurfaceHeight = winedesc.height;
5353 destPool = winedesc.pool;
5354 destFormat = winedesc.format;
5355 destSize = winedesc.size;
5357 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5358 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5359 return WINED3DERR_INVALIDCALL;
5362 /* This call loads the opengl surface directly, instead of copying the surface to the
5363 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5364 * copy in sysmem and use regular surface loading.
5366 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5367 if(convert != NO_CONVERSION) {
5368 return IWineD3DSurface_BltFast(pDestinationSurface,
5369 pDestPoint ? pDestPoint->x : 0,
5370 pDestPoint ? pDestPoint->y : 0,
5371 pSourceSurface, pSourceRect, 0);
5374 if (destFormat == WINED3DFMT_UNKNOWN) {
5375 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5376 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5378 /* Get the update surface description */
5379 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5382 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
5384 ENTER_GL();
5385 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5386 checkGLcall("glActiveTextureARB");
5387 LEAVE_GL();
5389 /* Make sure the surface is loaded and up to date */
5390 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5391 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5393 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5394 dst_format_desc = dst_impl->resource.format_desc;
5396 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5397 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5398 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5399 srcLeft = pSourceRect ? pSourceRect->left : 0;
5400 destLeft = pDestPoint ? pDestPoint->x : 0;
5401 destTop = pDestPoint ? pDestPoint->y : 0;
5404 /* This function doesn't support compressed textures
5405 the pitch is just bytesPerPixel * width */
5406 if(srcWidth != srcSurfaceWidth || srcLeft ){
5407 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5408 offset += srcLeft * src_format_desc->byte_count;
5409 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5411 /* TODO DXT formats */
5413 if(pSourceRect != NULL && pSourceRect->top != 0){
5414 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5416 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5417 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5418 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5420 /* Sanity check */
5421 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5423 /* need to lock the surface to get the data */
5424 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5427 ENTER_GL();
5429 /* TODO: Cube and volume support */
5430 if(rowoffset != 0){
5431 /* not a whole row so we have to do it a line at a time */
5432 int j;
5434 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5435 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5437 for (j = destTop; j < (srcHeight + destTop); ++j)
5439 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5440 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5441 data += rowoffset;
5444 } else { /* Full width, so just write out the whole texture */
5445 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5447 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5449 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5451 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5452 FIXME("Updating part of a compressed texture is not supported.\n");
5454 if (destFormat != srcFormat)
5456 FIXME("Updating mixed format compressed textures is not supported.\n");
5458 else
5460 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5461 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5464 else
5466 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5467 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5470 checkGLcall("glTexSubImage2D");
5472 LEAVE_GL();
5474 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5475 sampler = This->rev_tex_unit_map[0];
5476 if (sampler != WINED3D_UNMAPPED_STAGE)
5478 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5481 return WINED3D_OK;
5484 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5486 struct WineD3DRectPatch *patch;
5487 GLenum old_primitive_type;
5488 unsigned int i;
5489 struct list *e;
5490 BOOL found;
5491 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5493 if(!(Handle || pRectPatchInfo)) {
5494 /* TODO: Write a test for the return value, thus the FIXME */
5495 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5496 return WINED3DERR_INVALIDCALL;
5499 if(Handle) {
5500 i = PATCHMAP_HASHFUNC(Handle);
5501 found = FALSE;
5502 LIST_FOR_EACH(e, &This->patches[i]) {
5503 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5504 if(patch->Handle == Handle) {
5505 found = TRUE;
5506 break;
5510 if(!found) {
5511 TRACE("Patch does not exist. Creating a new one\n");
5512 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5513 patch->Handle = Handle;
5514 list_add_head(&This->patches[i], &patch->entry);
5515 } else {
5516 TRACE("Found existing patch %p\n", patch);
5518 } else {
5519 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5520 * attributes we have to tesselate, read back, and draw. This needs a patch
5521 * management structure instance. Create one.
5523 * A possible improvement is to check if a vertex shader is used, and if not directly
5524 * draw the patch.
5526 FIXME("Drawing an uncached patch. This is slow\n");
5527 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5530 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5531 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5532 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5533 HRESULT hr;
5534 TRACE("Tesselation density or patch info changed, retesselating\n");
5536 if(pRectPatchInfo) {
5537 patch->RectPatchInfo = *pRectPatchInfo;
5539 patch->numSegs[0] = pNumSegs[0];
5540 patch->numSegs[1] = pNumSegs[1];
5541 patch->numSegs[2] = pNumSegs[2];
5542 patch->numSegs[3] = pNumSegs[3];
5544 hr = tesselate_rectpatch(This, patch);
5545 if(FAILED(hr)) {
5546 WARN("Patch tesselation failed\n");
5548 /* Do not release the handle to store the params of the patch */
5549 if(!Handle) {
5550 HeapFree(GetProcessHeap(), 0, patch);
5552 return hr;
5556 This->currentPatch = patch;
5557 old_primitive_type = This->stateBlock->gl_primitive_type;
5558 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5559 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5560 This->stateBlock->gl_primitive_type = old_primitive_type;
5561 This->currentPatch = NULL;
5563 /* Destroy uncached patches */
5564 if(!Handle) {
5565 HeapFree(GetProcessHeap(), 0, patch->mem);
5566 HeapFree(GetProcessHeap(), 0, patch);
5568 return WINED3D_OK;
5571 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5573 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5574 FIXME("(%p) : Stub\n", This);
5575 return WINED3D_OK;
5578 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5580 int i;
5581 struct WineD3DRectPatch *patch;
5582 struct list *e;
5583 TRACE("(%p) Handle(%d)\n", This, Handle);
5585 i = PATCHMAP_HASHFUNC(Handle);
5586 LIST_FOR_EACH(e, &This->patches[i]) {
5587 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5588 if(patch->Handle == Handle) {
5589 TRACE("Deleting patch %p\n", patch);
5590 list_remove(&patch->entry);
5591 HeapFree(GetProcessHeap(), 0, patch->mem);
5592 HeapFree(GetProcessHeap(), 0, patch);
5593 return WINED3D_OK;
5597 /* TODO: Write a test for the return value */
5598 FIXME("Attempt to destroy nonexistent patch\n");
5599 return WINED3DERR_INVALIDCALL;
5602 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5603 HRESULT hr;
5604 IWineD3DSwapChain *swapchain;
5606 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5607 if (SUCCEEDED(hr)) {
5608 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5609 return swapchain;
5612 return NULL;
5615 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5616 const WINED3DRECT *rect, const float color[4])
5618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5619 struct wined3d_context *context;
5620 IWineD3DSwapChain *swapchain;
5622 swapchain = get_swapchain(surface);
5623 if (swapchain) {
5624 GLenum buffer;
5626 TRACE("Surface %p is onscreen\n", surface);
5628 context = ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
5629 ENTER_GL();
5630 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5631 buffer = surface_get_gl_buffer(surface, swapchain);
5632 glDrawBuffer(buffer);
5633 checkGLcall("glDrawBuffer()");
5634 } else {
5635 TRACE("Surface %p is offscreen\n", surface);
5637 context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
5638 ENTER_GL();
5639 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5640 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5641 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5644 if (rect) {
5645 glEnable(GL_SCISSOR_TEST);
5646 if(!swapchain) {
5647 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5648 } else {
5649 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5650 rect->x2 - rect->x1, rect->y2 - rect->y1);
5652 checkGLcall("glScissor");
5653 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5654 } else {
5655 glDisable(GL_SCISSOR_TEST);
5657 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5659 glDisable(GL_BLEND);
5660 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5662 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5663 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5665 glClearColor(color[0], color[1], color[2], color[3]);
5666 glClear(GL_COLOR_BUFFER_BIT);
5667 checkGLcall("glClear");
5669 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5670 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5671 glDrawBuffer(GL_BACK);
5672 checkGLcall("glDrawBuffer()");
5675 LEAVE_GL();
5678 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5679 unsigned int r, g, b, a;
5680 DWORD ret;
5682 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5683 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5684 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5685 return color;
5687 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5689 a = (color & 0xff000000) >> 24;
5690 r = (color & 0x00ff0000) >> 16;
5691 g = (color & 0x0000ff00) >> 8;
5692 b = (color & 0x000000ff) >> 0;
5694 switch(destfmt)
5696 case WINED3DFMT_B5G6R5_UNORM:
5697 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5698 r = (r * 32) / 256;
5699 g = (g * 64) / 256;
5700 b = (b * 32) / 256;
5701 ret = r << 11;
5702 ret |= g << 5;
5703 ret |= b;
5704 TRACE("Returning %08x\n", ret);
5705 return ret;
5707 case WINED3DFMT_B5G5R5X1_UNORM:
5708 case WINED3DFMT_B5G5R5A1_UNORM:
5709 a = (a * 2) / 256;
5710 r = (r * 32) / 256;
5711 g = (g * 32) / 256;
5712 b = (b * 32) / 256;
5713 ret = a << 15;
5714 ret |= r << 10;
5715 ret |= g << 5;
5716 ret |= b << 0;
5717 TRACE("Returning %08x\n", ret);
5718 return ret;
5720 case WINED3DFMT_A8_UNORM:
5721 TRACE("Returning %08x\n", a);
5722 return a;
5724 case WINED3DFMT_B4G4R4X4_UNORM:
5725 case WINED3DFMT_B4G4R4A4_UNORM:
5726 a = (a * 16) / 256;
5727 r = (r * 16) / 256;
5728 g = (g * 16) / 256;
5729 b = (b * 16) / 256;
5730 ret = a << 12;
5731 ret |= r << 8;
5732 ret |= g << 4;
5733 ret |= b << 0;
5734 TRACE("Returning %08x\n", ret);
5735 return ret;
5737 case WINED3DFMT_B2G3R3_UNORM:
5738 r = (r * 8) / 256;
5739 g = (g * 8) / 256;
5740 b = (b * 4) / 256;
5741 ret = r << 5;
5742 ret |= g << 2;
5743 ret |= b << 0;
5744 TRACE("Returning %08x\n", ret);
5745 return ret;
5747 case WINED3DFMT_R8G8B8X8_UNORM:
5748 case WINED3DFMT_R8G8B8A8_UNORM:
5749 ret = a << 24;
5750 ret |= b << 16;
5751 ret |= g << 8;
5752 ret |= r << 0;
5753 TRACE("Returning %08x\n", ret);
5754 return ret;
5756 case WINED3DFMT_B10G10R10A2_UNORM:
5757 a = (a * 4) / 256;
5758 r = (r * 1024) / 256;
5759 g = (g * 1024) / 256;
5760 b = (b * 1024) / 256;
5761 ret = a << 30;
5762 ret |= r << 20;
5763 ret |= g << 10;
5764 ret |= b << 0;
5765 TRACE("Returning %08x\n", ret);
5766 return ret;
5768 case WINED3DFMT_R10G10B10A2_UNORM:
5769 a = (a * 4) / 256;
5770 r = (r * 1024) / 256;
5771 g = (g * 1024) / 256;
5772 b = (b * 1024) / 256;
5773 ret = a << 30;
5774 ret |= b << 20;
5775 ret |= g << 10;
5776 ret |= r << 0;
5777 TRACE("Returning %08x\n", ret);
5778 return ret;
5780 default:
5781 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5782 return 0;
5786 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5788 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5789 WINEDDBLTFX BltFx;
5790 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5792 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5793 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5794 return WINED3DERR_INVALIDCALL;
5797 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5798 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5799 color_fill_fbo(iface, pSurface, pRect, c);
5800 return WINED3D_OK;
5801 } else {
5802 /* Just forward this to the DirectDraw blitting engine */
5803 memset(&BltFx, 0, sizeof(BltFx));
5804 BltFx.dwSize = sizeof(BltFx);
5805 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5806 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5807 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5811 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5812 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5814 IWineD3DResource *resource;
5815 IWineD3DSurface *surface;
5816 HRESULT hr;
5818 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5819 if (FAILED(hr))
5821 ERR("Failed to get resource, hr %#x\n", hr);
5822 return;
5825 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5827 FIXME("Only supported on surface resources\n");
5828 IWineD3DResource_Release(resource);
5829 return;
5832 surface = (IWineD3DSurface *)resource;
5834 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5836 color_fill_fbo(iface, surface, NULL, color);
5838 else
5840 WINEDDBLTFX BltFx;
5841 WINED3DCOLOR c;
5843 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5845 c = ((DWORD)(color[2] * 255.0f));
5846 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5847 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5848 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5850 /* Just forward this to the DirectDraw blitting engine */
5851 memset(&BltFx, 0, sizeof(BltFx));
5852 BltFx.dwSize = sizeof(BltFx);
5853 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5854 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5855 if (FAILED(hr))
5857 ERR("Blt failed, hr %#x\n", hr);
5861 IWineD3DResource_Release(resource);
5864 /* rendertarget and depth stencil functions */
5865 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5868 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5869 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5870 return WINED3DERR_INVALIDCALL;
5873 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5874 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5875 /* Note inc ref on returned surface */
5876 if(*ppRenderTarget != NULL)
5877 IWineD3DSurface_AddRef(*ppRenderTarget);
5878 return WINED3D_OK;
5881 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5883 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5884 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5885 IWineD3DSwapChainImpl *Swapchain;
5886 HRESULT hr;
5888 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5890 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5891 if(hr != WINED3D_OK) {
5892 ERR("Can't get the swapchain\n");
5893 return hr;
5896 /* Make sure to release the swapchain */
5897 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5899 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5900 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5901 return WINED3DERR_INVALIDCALL;
5903 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5904 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5905 return WINED3DERR_INVALIDCALL;
5908 if(Swapchain->frontBuffer != Front) {
5909 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5911 if(Swapchain->frontBuffer)
5913 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5914 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5916 Swapchain->frontBuffer = Front;
5918 if(Swapchain->frontBuffer) {
5919 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5920 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5924 if(Back && !Swapchain->backBuffer) {
5925 /* We need memory for the back buffer array - only one back buffer this way */
5926 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5927 if(!Swapchain->backBuffer) {
5928 ERR("Out of memory\n");
5929 return E_OUTOFMEMORY;
5933 if(Swapchain->backBuffer[0] != Back) {
5934 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5936 /* What to do about the context here in the case of multithreading? Not sure.
5937 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5939 WARN("No active context?\n");
5941 ENTER_GL();
5942 if(!Swapchain->backBuffer[0]) {
5943 /* GL was told to draw to the front buffer at creation,
5944 * undo that
5946 glDrawBuffer(GL_BACK);
5947 checkGLcall("glDrawBuffer(GL_BACK)");
5948 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5949 Swapchain->presentParms.BackBufferCount = 1;
5950 } else if (!Back) {
5951 /* That makes problems - disable for now */
5952 /* glDrawBuffer(GL_FRONT); */
5953 checkGLcall("glDrawBuffer(GL_FRONT)");
5954 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5955 Swapchain->presentParms.BackBufferCount = 0;
5957 LEAVE_GL();
5959 if(Swapchain->backBuffer[0])
5961 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5962 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5964 Swapchain->backBuffer[0] = Back;
5966 if(Swapchain->backBuffer[0]) {
5967 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5968 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
5969 } else {
5970 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5971 Swapchain->backBuffer = NULL;
5976 return WINED3D_OK;
5979 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5981 *ppZStencilSurface = This->stencilBufferTarget;
5982 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5984 if(*ppZStencilSurface != NULL) {
5985 /* Note inc ref on returned surface */
5986 IWineD3DSurface_AddRef(*ppZStencilSurface);
5987 return WINED3D_OK;
5988 } else {
5989 return WINED3DERR_NOTFOUND;
5993 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5994 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
5996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5997 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5998 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5999 const struct wined3d_gl_info *gl_info;
6000 struct wined3d_context *context;
6001 GLenum gl_filter;
6002 POINT offset = {0, 0};
6004 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6005 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6006 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6007 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6009 switch (filter) {
6010 case WINED3DTEXF_LINEAR:
6011 gl_filter = GL_LINEAR;
6012 break;
6014 default:
6015 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6016 case WINED3DTEXF_NONE:
6017 case WINED3DTEXF_POINT:
6018 gl_filter = GL_NEAREST;
6019 break;
6022 /* Attach src surface to src fbo */
6023 src_swapchain = get_swapchain(src_surface);
6024 dst_swapchain = get_swapchain(dst_surface);
6026 if (src_swapchain) context = ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6027 else if (dst_swapchain) context = ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6028 else context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6030 gl_info = context->gl_info;
6032 if (src_swapchain) {
6033 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6035 TRACE("Source surface %p is onscreen\n", src_surface);
6036 /* Make sure the drawable is up to date. In the offscreen case
6037 * attach_surface_fbo() implicitly takes care of this. */
6038 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6040 if(buffer == GL_FRONT) {
6041 RECT windowsize;
6042 UINT h;
6043 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6044 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6045 h = windowsize.bottom - windowsize.top;
6046 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6047 src_rect->y1 = offset.y + h - src_rect->y1;
6048 src_rect->y2 = offset.y + h - src_rect->y2;
6049 } else {
6050 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6051 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6054 ENTER_GL();
6055 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
6056 glReadBuffer(buffer);
6057 checkGLcall("glReadBuffer()");
6058 } else {
6059 TRACE("Source surface %p is offscreen\n", src_surface);
6060 ENTER_GL();
6061 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
6062 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
6063 glReadBuffer(GL_COLOR_ATTACHMENT0);
6064 checkGLcall("glReadBuffer()");
6065 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
6067 LEAVE_GL();
6069 /* Attach dst surface to dst fbo */
6070 if (dst_swapchain) {
6071 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6073 TRACE("Destination surface %p is onscreen\n", dst_surface);
6074 /* Make sure the drawable is up to date. In the offscreen case
6075 * attach_surface_fbo() implicitly takes care of this. */
6076 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6078 if(buffer == GL_FRONT) {
6079 RECT windowsize;
6080 UINT h;
6081 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6082 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6083 h = windowsize.bottom - windowsize.top;
6084 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6085 dst_rect->y1 = offset.y + h - dst_rect->y1;
6086 dst_rect->y2 = offset.y + h - dst_rect->y2;
6087 } else {
6088 /* Screen coords = window coords, surface height = window height */
6089 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6090 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6093 ENTER_GL();
6094 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
6095 glDrawBuffer(buffer);
6096 checkGLcall("glDrawBuffer()");
6097 } else {
6098 TRACE("Destination surface %p is offscreen\n", dst_surface);
6100 ENTER_GL();
6101 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
6102 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
6103 glDrawBuffer(GL_COLOR_ATTACHMENT0);
6104 checkGLcall("glDrawBuffer()");
6105 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
6107 glDisable(GL_SCISSOR_TEST);
6108 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6110 if (flip) {
6111 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6112 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
6113 checkGLcall("glBlitFramebuffer()");
6114 } else {
6115 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6116 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
6117 checkGLcall("glBlitFramebuffer()");
6120 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6122 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6123 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6124 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6125 glDrawBuffer(GL_BACK);
6126 checkGLcall("glDrawBuffer()");
6128 LEAVE_GL();
6131 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6133 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
6135 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6137 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6138 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6139 This, RenderTargetIndex, GL_LIMITS(buffers));
6140 return WINED3DERR_INVALIDCALL;
6143 /* MSDN says that null disables the render target
6144 but a device must always be associated with a render target
6145 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6147 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6148 FIXME("Trying to set render target 0 to NULL\n");
6149 return WINED3DERR_INVALIDCALL;
6151 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6152 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);
6153 return WINED3DERR_INVALIDCALL;
6156 /* If we are trying to set what we already have, don't bother */
6157 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6158 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6159 return WINED3D_OK;
6161 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6162 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6163 This->render_targets[RenderTargetIndex] = pRenderTarget;
6165 /* Render target 0 is special */
6166 if(RenderTargetIndex == 0 && dxVersion > 7) {
6167 /* Finally, reset the viewport and scissor rect as the MSDN states.
6168 * Tests show that stateblock recording is ignored, the change goes
6169 * directly into the primary stateblock.
6171 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6172 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6173 This->stateBlock->viewport.X = 0;
6174 This->stateBlock->viewport.Y = 0;
6175 This->stateBlock->viewport.MaxZ = 1.0f;
6176 This->stateBlock->viewport.MinZ = 0.0f;
6177 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6179 This->stateBlock->scissorRect.top = 0;
6180 This->stateBlock->scissorRect.left = 0;
6181 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
6182 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
6183 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6185 return WINED3D_OK;
6188 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6190 HRESULT hr = WINED3D_OK;
6191 IWineD3DSurface *tmp;
6193 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6195 if (pNewZStencil == This->stencilBufferTarget) {
6196 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6197 } else {
6198 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6199 * depending on the renter target implementation being used.
6200 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6201 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6202 * stencil buffer and incur an extra memory overhead
6203 ******************************************************/
6205 if (This->stencilBufferTarget) {
6206 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6207 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6208 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6209 } else {
6210 struct wined3d_context *context = ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6211 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
6212 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6216 tmp = This->stencilBufferTarget;
6217 This->stencilBufferTarget = pNewZStencil;
6218 /* should we be calling the parent or the wined3d surface? */
6219 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6220 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6221 hr = WINED3D_OK;
6223 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6224 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6225 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6226 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6227 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6231 return hr;
6234 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6235 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6237 /* TODO: the use of Impl is deprecated. */
6238 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6239 WINED3DLOCKED_RECT lockedRect;
6241 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6243 /* some basic validation checks */
6244 if(This->cursorTexture) {
6245 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6246 ENTER_GL();
6247 glDeleteTextures(1, &This->cursorTexture);
6248 LEAVE_GL();
6249 This->cursorTexture = 0;
6252 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6253 This->haveHardwareCursor = TRUE;
6254 else
6255 This->haveHardwareCursor = FALSE;
6257 if(pCursorBitmap) {
6258 WINED3DLOCKED_RECT rect;
6260 /* MSDN: Cursor must be A8R8G8B8 */
6261 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6263 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6264 return WINED3DERR_INVALIDCALL;
6267 /* MSDN: Cursor must be smaller than the display mode */
6268 if(pSur->currentDesc.Width > This->ddraw_width ||
6269 pSur->currentDesc.Height > This->ddraw_height) {
6270 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);
6271 return WINED3DERR_INVALIDCALL;
6274 if (!This->haveHardwareCursor) {
6275 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6277 /* Do not store the surface's pointer because the application may
6278 * release it after setting the cursor image. Windows doesn't
6279 * addref the set surface, so we can't do this either without
6280 * creating circular refcount dependencies. Copy out the gl texture
6281 * instead.
6283 This->cursorWidth = pSur->currentDesc.Width;
6284 This->cursorHeight = pSur->currentDesc.Height;
6285 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6287 const struct GlPixelFormatDesc *glDesc =
6288 getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, &GLINFO_LOCATION);
6289 char *mem, *bits = rect.pBits;
6290 GLint intfmt = glDesc->glInternal;
6291 GLint format = glDesc->glFormat;
6292 GLint type = glDesc->glType;
6293 INT height = This->cursorHeight;
6294 INT width = This->cursorWidth;
6295 INT bpp = glDesc->byte_count;
6296 DWORD sampler;
6297 INT i;
6299 /* Reformat the texture memory (pitch and width can be
6300 * different) */
6301 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6302 for(i = 0; i < height; i++)
6303 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6304 IWineD3DSurface_UnlockRect(pCursorBitmap);
6306 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6308 ENTER_GL();
6310 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6311 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6312 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6315 /* Make sure that a proper texture unit is selected */
6316 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6317 checkGLcall("glActiveTextureARB");
6318 sampler = This->rev_tex_unit_map[0];
6319 if (sampler != WINED3D_UNMAPPED_STAGE)
6321 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6323 /* Create a new cursor texture */
6324 glGenTextures(1, &This->cursorTexture);
6325 checkGLcall("glGenTextures");
6326 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6327 checkGLcall("glBindTexture");
6328 /* Copy the bitmap memory into the cursor texture */
6329 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6330 HeapFree(GetProcessHeap(), 0, mem);
6331 checkGLcall("glTexImage2D");
6333 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6334 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6335 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6338 LEAVE_GL();
6340 else
6342 FIXME("A cursor texture was not returned.\n");
6343 This->cursorTexture = 0;
6346 else
6348 /* Draw a hardware cursor */
6349 ICONINFO cursorInfo;
6350 HCURSOR cursor;
6351 /* Create and clear maskBits because it is not needed for
6352 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6353 * chunks. */
6354 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6355 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6356 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6357 WINED3DLOCK_NO_DIRTY_UPDATE |
6358 WINED3DLOCK_READONLY
6360 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6361 pSur->currentDesc.Height);
6363 cursorInfo.fIcon = FALSE;
6364 cursorInfo.xHotspot = XHotSpot;
6365 cursorInfo.yHotspot = YHotSpot;
6366 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6367 pSur->currentDesc.Height, 1,
6368 1, &maskBits);
6369 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6370 pSur->currentDesc.Height, 1,
6371 32, lockedRect.pBits);
6372 IWineD3DSurface_UnlockRect(pCursorBitmap);
6373 /* Create our cursor and clean up. */
6374 cursor = CreateIconIndirect(&cursorInfo);
6375 SetCursor(cursor);
6376 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6377 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6378 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6379 This->hardwareCursor = cursor;
6380 HeapFree(GetProcessHeap(), 0, maskBits);
6384 This->xHotSpot = XHotSpot;
6385 This->yHotSpot = YHotSpot;
6386 return WINED3D_OK;
6389 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6391 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6393 This->xScreenSpace = XScreenSpace;
6394 This->yScreenSpace = YScreenSpace;
6396 return;
6400 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6402 BOOL oldVisible = This->bCursorVisible;
6403 POINT pt;
6405 TRACE("(%p) : visible(%d)\n", This, bShow);
6408 * When ShowCursor is first called it should make the cursor appear at the OS's last
6409 * known cursor position. Because of this, some applications just repetitively call
6410 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6412 GetCursorPos(&pt);
6413 This->xScreenSpace = pt.x;
6414 This->yScreenSpace = pt.y;
6416 if (This->haveHardwareCursor) {
6417 This->bCursorVisible = bShow;
6418 if (bShow)
6419 SetCursor(This->hardwareCursor);
6420 else
6421 SetCursor(NULL);
6423 else
6425 if (This->cursorTexture)
6426 This->bCursorVisible = bShow;
6429 return oldVisible;
6432 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6434 IWineD3DResourceImpl *resource;
6435 TRACE("(%p) : state (%u)\n", This, This->state);
6437 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6438 switch (This->state) {
6439 case WINED3D_OK:
6440 return WINED3D_OK;
6441 case WINED3DERR_DEVICELOST:
6443 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6444 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6445 return WINED3DERR_DEVICENOTRESET;
6447 return WINED3DERR_DEVICELOST;
6449 case WINED3DERR_DRIVERINTERNALERROR:
6450 return WINED3DERR_DRIVERINTERNALERROR;
6453 /* Unknown state */
6454 return WINED3DERR_DRIVERINTERNALERROR;
6457 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6458 TRACE("checking resource %p for eviction\n", resource);
6459 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6460 TRACE("Evicting %p\n", resource);
6461 IWineD3DResource_UnLoad(resource);
6463 IWineD3DResource_Release(resource);
6464 return S_OK;
6467 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6469 TRACE("(%p)\n", This);
6471 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6472 return WINED3D_OK;
6475 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6477 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6479 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6480 if(surface->Flags & SFLAG_DIBSECTION) {
6481 /* Release the DC */
6482 SelectObject(surface->hDC, surface->dib.holdbitmap);
6483 DeleteDC(surface->hDC);
6484 /* Release the DIB section */
6485 DeleteObject(surface->dib.DIBsection);
6486 surface->dib.bitmap_data = NULL;
6487 surface->resource.allocatedMemory = NULL;
6488 surface->Flags &= ~SFLAG_DIBSECTION;
6490 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6491 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6492 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6493 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6494 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6495 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6496 } else {
6497 surface->pow2Width = surface->pow2Height = 1;
6498 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6499 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6501 surface->glRect.left = 0;
6502 surface->glRect.top = 0;
6503 surface->glRect.right = surface->pow2Width;
6504 surface->glRect.bottom = surface->pow2Height;
6506 if (surface->texture_name)
6508 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6509 ENTER_GL();
6510 glDeleteTextures(1, &surface->texture_name);
6511 LEAVE_GL();
6512 surface->texture_name = 0;
6513 surface->Flags &= ~SFLAG_CLIENT;
6515 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6516 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6517 surface->Flags |= SFLAG_NONPOW2;
6518 } else {
6519 surface->Flags &= ~SFLAG_NONPOW2;
6521 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6522 surface->resource.allocatedMemory = NULL;
6523 surface->resource.heapMemory = NULL;
6524 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6525 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6526 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6527 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6528 } else {
6529 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6533 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6534 TRACE("Unloading resource %p\n", resource);
6535 IWineD3DResource_UnLoad(resource);
6536 IWineD3DResource_Release(resource);
6537 return S_OK;
6540 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6542 UINT i, count;
6543 WINED3DDISPLAYMODE m;
6544 HRESULT hr;
6546 /* All Windowed modes are supported, as is leaving the current mode */
6547 if(pp->Windowed) return TRUE;
6548 if(!pp->BackBufferWidth) return TRUE;
6549 if(!pp->BackBufferHeight) return TRUE;
6551 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6552 for(i = 0; i < count; i++) {
6553 memset(&m, 0, sizeof(m));
6554 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6555 if(FAILED(hr)) {
6556 ERR("EnumAdapterModes failed\n");
6558 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6559 /* Mode found, it is supported */
6560 return TRUE;
6563 /* Mode not found -> not supported */
6564 return FALSE;
6567 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6569 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6570 const struct wined3d_context *context;
6571 const struct wined3d_gl_info *gl_info;
6572 UINT i;
6573 IWineD3DBaseShaderImpl *shader;
6575 context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6576 gl_info = context->gl_info;
6578 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6579 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6580 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6583 ENTER_GL();
6584 if(This->depth_blt_texture) {
6585 glDeleteTextures(1, &This->depth_blt_texture);
6586 This->depth_blt_texture = 0;
6588 if (This->depth_blt_rb) {
6589 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6590 This->depth_blt_rb = 0;
6591 This->depth_blt_rb_w = 0;
6592 This->depth_blt_rb_h = 0;
6594 LEAVE_GL();
6596 This->blitter->free_private(iface);
6597 This->frag_pipe->free_private(iface);
6598 This->shader_backend->shader_free_private(iface);
6600 ENTER_GL();
6601 for (i = 0; i < GL_LIMITS(textures); i++) {
6602 /* Textures are recreated below */
6603 glDeleteTextures(1, &This->dummyTextureName[i]);
6604 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6605 This->dummyTextureName[i] = 0;
6607 LEAVE_GL();
6609 while(This->numContexts) {
6610 DestroyContext(This, This->contexts[0]);
6612 HeapFree(GetProcessHeap(), 0, swapchain->context);
6613 swapchain->context = NULL;
6614 swapchain->num_contexts = 0;
6617 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6619 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6620 HRESULT hr;
6621 IWineD3DSurfaceImpl *target;
6623 /* Recreate the primary swapchain's context */
6624 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6625 if(swapchain->backBuffer) {
6626 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6627 } else {
6628 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6630 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
6631 &swapchain->presentParms);
6632 swapchain->num_contexts = 1;
6634 create_dummy_textures(This);
6636 hr = This->shader_backend->shader_alloc_private(iface);
6637 if(FAILED(hr)) {
6638 ERR("Failed to recreate shader private data\n");
6639 goto err_out;
6641 hr = This->frag_pipe->alloc_private(iface);
6642 if(FAILED(hr)) {
6643 TRACE("Fragment pipeline private data couldn't be allocated\n");
6644 goto err_out;
6646 hr = This->blitter->alloc_private(iface);
6647 if(FAILED(hr)) {
6648 TRACE("Blitter private data couldn't be allocated\n");
6649 goto err_out;
6652 return WINED3D_OK;
6654 err_out:
6655 This->blitter->free_private(iface);
6656 This->frag_pipe->free_private(iface);
6657 This->shader_backend->shader_free_private(iface);
6658 return hr;
6661 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6663 IWineD3DSwapChainImpl *swapchain;
6664 HRESULT hr;
6665 BOOL DisplayModeChanged = FALSE;
6666 WINED3DDISPLAYMODE mode;
6667 TRACE("(%p)\n", This);
6669 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6670 if(FAILED(hr)) {
6671 ERR("Failed to get the first implicit swapchain\n");
6672 return hr;
6675 if(!is_display_mode_supported(This, pPresentationParameters)) {
6676 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6677 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6678 pPresentationParameters->BackBufferHeight);
6679 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6680 return WINED3DERR_INVALIDCALL;
6683 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6684 * on an existing gl context, so there's no real need for recreation.
6686 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6688 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6690 TRACE("New params:\n");
6691 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6692 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6693 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6694 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6695 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6696 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6697 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6698 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6699 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6700 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6701 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6702 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6703 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6705 /* No special treatment of these parameters. Just store them */
6706 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6707 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6708 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6709 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6711 /* What to do about these? */
6712 if(pPresentationParameters->BackBufferCount != 0 &&
6713 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6714 ERR("Cannot change the back buffer count yet\n");
6716 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6717 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6718 ERR("Cannot change the back buffer format yet\n");
6720 if(pPresentationParameters->hDeviceWindow != NULL &&
6721 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6722 ERR("Cannot change the device window yet\n");
6724 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6725 HRESULT hrc;
6727 TRACE("Creating the depth stencil buffer\n");
6729 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6730 This->parent,
6731 pPresentationParameters->BackBufferWidth,
6732 pPresentationParameters->BackBufferHeight,
6733 pPresentationParameters->AutoDepthStencilFormat,
6734 pPresentationParameters->MultiSampleType,
6735 pPresentationParameters->MultiSampleQuality,
6736 FALSE,
6737 &This->auto_depth_stencil_buffer);
6739 if (FAILED(hrc)) {
6740 ERR("Failed to create the depth stencil buffer\n");
6741 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6742 return WINED3DERR_INVALIDCALL;
6746 /* Reset the depth stencil */
6747 if (pPresentationParameters->EnableAutoDepthStencil)
6748 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6749 else
6750 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6752 TRACE("Resetting stateblock\n");
6753 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6754 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6756 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6758 if(pPresentationParameters->Windowed) {
6759 mode.Width = swapchain->orig_width;
6760 mode.Height = swapchain->orig_height;
6761 mode.RefreshRate = 0;
6762 mode.Format = swapchain->presentParms.BackBufferFormat;
6763 } else {
6764 mode.Width = pPresentationParameters->BackBufferWidth;
6765 mode.Height = pPresentationParameters->BackBufferHeight;
6766 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6767 mode.Format = swapchain->presentParms.BackBufferFormat;
6770 /* Should Width == 800 && Height == 0 set 800x600? */
6771 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6772 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6773 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6775 UINT i;
6777 if(!pPresentationParameters->Windowed) {
6778 DisplayModeChanged = TRUE;
6780 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6781 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6783 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6784 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6785 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6787 if(This->auto_depth_stencil_buffer) {
6788 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6792 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6793 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6794 DisplayModeChanged) {
6796 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6798 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
6799 if(swapchain->presentParms.Windowed) {
6800 /* switch from windowed to fs */
6801 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
6802 pPresentationParameters->BackBufferWidth,
6803 pPresentationParameters->BackBufferHeight);
6804 } else {
6805 /* Fullscreen -> fullscreen mode change */
6806 MoveWindow(swapchain->win_handle, 0, 0,
6807 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6808 TRUE);
6810 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
6811 /* Fullscreen -> windowed switch */
6812 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
6814 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6815 } else if(!pPresentationParameters->Windowed) {
6816 DWORD style = This->style, exStyle = This->exStyle;
6817 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6818 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6819 * Reset to clear up their mess. Guild Wars also loses the device during that.
6821 This->style = 0;
6822 This->exStyle = 0;
6823 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
6824 pPresentationParameters->BackBufferWidth,
6825 pPresentationParameters->BackBufferHeight);
6826 This->style = style;
6827 This->exStyle = exStyle;
6830 /* Note: No parent needed for initial internal stateblock */
6831 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6832 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6833 else TRACE("Created stateblock %p\n", This->stateBlock);
6834 This->updateStateBlock = This->stateBlock;
6835 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6837 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6838 if(FAILED(hr)) {
6839 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6842 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6843 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6845 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6846 * first use
6848 return hr;
6851 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6853 /** FIXME: always true at the moment **/
6854 if(!bEnableDialogs) {
6855 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6857 return WINED3D_OK;
6861 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6863 TRACE("(%p) : pParameters %p\n", This, pParameters);
6865 *pParameters = This->createParms;
6866 return WINED3D_OK;
6869 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6870 IWineD3DSwapChain *swapchain;
6872 TRACE("Relaying to swapchain\n");
6874 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6875 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6876 IWineD3DSwapChain_Release(swapchain);
6878 return;
6881 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6882 IWineD3DSwapChain *swapchain;
6884 TRACE("Relaying to swapchain\n");
6886 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6887 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6888 IWineD3DSwapChain_Release(swapchain);
6890 return;
6894 /** ********************************************************
6895 * Notification functions
6896 ** ********************************************************/
6897 /** This function must be called in the release of a resource when ref == 0,
6898 * the contents of resource must still be correct,
6899 * any handles to other resource held by the caller must be closed
6900 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6901 *****************************************************/
6902 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6904 TRACE("(%p) : Adding resource %p\n", This, resource);
6906 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6909 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6911 TRACE("(%p) : Removing resource %p\n", This, resource);
6913 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6916 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6918 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6919 int counter;
6921 TRACE("(%p) : resource %p\n", This, resource);
6923 context_resource_released((IWineD3DDevice *)This, resource, type);
6925 switch (type) {
6926 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6927 case WINED3DRTYPE_SURFACE: {
6928 unsigned int i;
6930 if (This->d3d_initialized)
6932 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6933 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6934 This->render_targets[i] = NULL;
6937 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6938 This->stencilBufferTarget = NULL;
6942 break;
6944 case WINED3DRTYPE_TEXTURE:
6945 case WINED3DRTYPE_CUBETEXTURE:
6946 case WINED3DRTYPE_VOLUMETEXTURE:
6947 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6948 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6949 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6950 This->stateBlock->textures[counter] = NULL;
6952 if (This->updateStateBlock != This->stateBlock ){
6953 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6954 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6955 This->updateStateBlock->textures[counter] = NULL;
6959 break;
6960 case WINED3DRTYPE_VOLUME:
6961 /* TODO: nothing really? */
6962 break;
6963 case WINED3DRTYPE_BUFFER:
6965 int streamNumber;
6966 TRACE("Cleaning up stream pointers\n");
6968 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6969 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6970 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6972 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6973 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6974 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6975 This->updateStateBlock->streamSource[streamNumber] = 0;
6976 /* Set changed flag? */
6979 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) */
6980 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6981 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6982 This->stateBlock->streamSource[streamNumber] = 0;
6987 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6988 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6989 This->updateStateBlock->pIndexData = NULL;
6992 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6993 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6994 This->stateBlock->pIndexData = NULL;
6998 break;
7000 default:
7001 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7002 break;
7006 /* Remove the resource from the resourceStore */
7007 device_resource_remove(This, resource);
7009 TRACE("Resource released\n");
7013 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7015 IWineD3DResourceImpl *resource, *cursor;
7016 HRESULT ret;
7017 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7019 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7020 TRACE("enumerating resource %p\n", resource);
7021 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7022 ret = pCallback((IWineD3DResource *) resource, pData);
7023 if(ret == S_FALSE) {
7024 TRACE("Canceling enumeration\n");
7025 break;
7028 return WINED3D_OK;
7031 /**********************************************************
7032 * IWineD3DDevice VTbl follows
7033 **********************************************************/
7035 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7037 /*** IUnknown methods ***/
7038 IWineD3DDeviceImpl_QueryInterface,
7039 IWineD3DDeviceImpl_AddRef,
7040 IWineD3DDeviceImpl_Release,
7041 /*** IWineD3DDevice methods ***/
7042 IWineD3DDeviceImpl_GetParent,
7043 /*** Creation methods**/
7044 IWineD3DDeviceImpl_CreateBuffer,
7045 IWineD3DDeviceImpl_CreateVertexBuffer,
7046 IWineD3DDeviceImpl_CreateIndexBuffer,
7047 IWineD3DDeviceImpl_CreateStateBlock,
7048 IWineD3DDeviceImpl_CreateSurface,
7049 IWineD3DDeviceImpl_CreateRendertargetView,
7050 IWineD3DDeviceImpl_CreateTexture,
7051 IWineD3DDeviceImpl_CreateVolumeTexture,
7052 IWineD3DDeviceImpl_CreateVolume,
7053 IWineD3DDeviceImpl_CreateCubeTexture,
7054 IWineD3DDeviceImpl_CreateQuery,
7055 IWineD3DDeviceImpl_CreateSwapChain,
7056 IWineD3DDeviceImpl_CreateVertexDeclaration,
7057 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7058 IWineD3DDeviceImpl_CreateVertexShader,
7059 IWineD3DDeviceImpl_CreatePixelShader,
7060 IWineD3DDeviceImpl_CreatePalette,
7061 /*** Odd functions **/
7062 IWineD3DDeviceImpl_Init3D,
7063 IWineD3DDeviceImpl_InitGDI,
7064 IWineD3DDeviceImpl_Uninit3D,
7065 IWineD3DDeviceImpl_UninitGDI,
7066 IWineD3DDeviceImpl_SetMultithreaded,
7067 IWineD3DDeviceImpl_EvictManagedResources,
7068 IWineD3DDeviceImpl_GetAvailableTextureMem,
7069 IWineD3DDeviceImpl_GetBackBuffer,
7070 IWineD3DDeviceImpl_GetCreationParameters,
7071 IWineD3DDeviceImpl_GetDeviceCaps,
7072 IWineD3DDeviceImpl_GetDirect3D,
7073 IWineD3DDeviceImpl_GetDisplayMode,
7074 IWineD3DDeviceImpl_SetDisplayMode,
7075 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7076 IWineD3DDeviceImpl_GetRasterStatus,
7077 IWineD3DDeviceImpl_GetSwapChain,
7078 IWineD3DDeviceImpl_Reset,
7079 IWineD3DDeviceImpl_SetDialogBoxMode,
7080 IWineD3DDeviceImpl_SetCursorProperties,
7081 IWineD3DDeviceImpl_SetCursorPosition,
7082 IWineD3DDeviceImpl_ShowCursor,
7083 IWineD3DDeviceImpl_TestCooperativeLevel,
7084 /*** Getters and setters **/
7085 IWineD3DDeviceImpl_SetClipPlane,
7086 IWineD3DDeviceImpl_GetClipPlane,
7087 IWineD3DDeviceImpl_SetClipStatus,
7088 IWineD3DDeviceImpl_GetClipStatus,
7089 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7090 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7091 IWineD3DDeviceImpl_SetDepthStencilSurface,
7092 IWineD3DDeviceImpl_GetDepthStencilSurface,
7093 IWineD3DDeviceImpl_SetGammaRamp,
7094 IWineD3DDeviceImpl_GetGammaRamp,
7095 IWineD3DDeviceImpl_SetIndexBuffer,
7096 IWineD3DDeviceImpl_GetIndexBuffer,
7097 IWineD3DDeviceImpl_SetBaseVertexIndex,
7098 IWineD3DDeviceImpl_GetBaseVertexIndex,
7099 IWineD3DDeviceImpl_SetLight,
7100 IWineD3DDeviceImpl_GetLight,
7101 IWineD3DDeviceImpl_SetLightEnable,
7102 IWineD3DDeviceImpl_GetLightEnable,
7103 IWineD3DDeviceImpl_SetMaterial,
7104 IWineD3DDeviceImpl_GetMaterial,
7105 IWineD3DDeviceImpl_SetNPatchMode,
7106 IWineD3DDeviceImpl_GetNPatchMode,
7107 IWineD3DDeviceImpl_SetPaletteEntries,
7108 IWineD3DDeviceImpl_GetPaletteEntries,
7109 IWineD3DDeviceImpl_SetPixelShader,
7110 IWineD3DDeviceImpl_GetPixelShader,
7111 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7112 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7113 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7114 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7115 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7116 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7117 IWineD3DDeviceImpl_SetRenderState,
7118 IWineD3DDeviceImpl_GetRenderState,
7119 IWineD3DDeviceImpl_SetRenderTarget,
7120 IWineD3DDeviceImpl_GetRenderTarget,
7121 IWineD3DDeviceImpl_SetFrontBackBuffers,
7122 IWineD3DDeviceImpl_SetSamplerState,
7123 IWineD3DDeviceImpl_GetSamplerState,
7124 IWineD3DDeviceImpl_SetScissorRect,
7125 IWineD3DDeviceImpl_GetScissorRect,
7126 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7127 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7128 IWineD3DDeviceImpl_SetStreamSource,
7129 IWineD3DDeviceImpl_GetStreamSource,
7130 IWineD3DDeviceImpl_SetStreamSourceFreq,
7131 IWineD3DDeviceImpl_GetStreamSourceFreq,
7132 IWineD3DDeviceImpl_SetTexture,
7133 IWineD3DDeviceImpl_GetTexture,
7134 IWineD3DDeviceImpl_SetTextureStageState,
7135 IWineD3DDeviceImpl_GetTextureStageState,
7136 IWineD3DDeviceImpl_SetTransform,
7137 IWineD3DDeviceImpl_GetTransform,
7138 IWineD3DDeviceImpl_SetVertexDeclaration,
7139 IWineD3DDeviceImpl_GetVertexDeclaration,
7140 IWineD3DDeviceImpl_SetVertexShader,
7141 IWineD3DDeviceImpl_GetVertexShader,
7142 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7143 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7144 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7145 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7146 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7147 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7148 IWineD3DDeviceImpl_SetViewport,
7149 IWineD3DDeviceImpl_GetViewport,
7150 IWineD3DDeviceImpl_MultiplyTransform,
7151 IWineD3DDeviceImpl_ValidateDevice,
7152 IWineD3DDeviceImpl_ProcessVertices,
7153 /*** State block ***/
7154 IWineD3DDeviceImpl_BeginStateBlock,
7155 IWineD3DDeviceImpl_EndStateBlock,
7156 /*** Scene management ***/
7157 IWineD3DDeviceImpl_BeginScene,
7158 IWineD3DDeviceImpl_EndScene,
7159 IWineD3DDeviceImpl_Present,
7160 IWineD3DDeviceImpl_Clear,
7161 IWineD3DDeviceImpl_ClearRendertargetView,
7162 /*** Drawing ***/
7163 IWineD3DDeviceImpl_SetPrimitiveType,
7164 IWineD3DDeviceImpl_GetPrimitiveType,
7165 IWineD3DDeviceImpl_DrawPrimitive,
7166 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7167 IWineD3DDeviceImpl_DrawPrimitiveUP,
7168 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7169 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7170 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7171 IWineD3DDeviceImpl_DrawRectPatch,
7172 IWineD3DDeviceImpl_DrawTriPatch,
7173 IWineD3DDeviceImpl_DeletePatch,
7174 IWineD3DDeviceImpl_ColorFill,
7175 IWineD3DDeviceImpl_UpdateTexture,
7176 IWineD3DDeviceImpl_UpdateSurface,
7177 IWineD3DDeviceImpl_GetFrontBufferData,
7178 /*** object tracking ***/
7179 IWineD3DDeviceImpl_EnumResources
7182 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7183 DWORD rep = This->StateTable[state].representative;
7184 struct wined3d_context *context;
7185 DWORD idx;
7186 BYTE shift;
7187 UINT i;
7189 for(i = 0; i < This->numContexts; i++) {
7190 context = This->contexts[i];
7191 if(isStateDirty(context, rep)) continue;
7193 context->dirtyArray[context->numDirtyEntries++] = rep;
7194 idx = rep >> 5;
7195 shift = rep & 0x1f;
7196 context->isStateDirty[idx] |= (1 << shift);
7200 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7202 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.wineD3DDevice;
7203 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7204 *width = device->pbufferWidth;
7205 *height = device->pbufferHeight;
7208 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7210 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7211 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7212 *width = surface->pow2Width;
7213 *height = surface->pow2Height;
7216 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7218 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7219 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7220 * current context's drawable, which is the size of the back buffer of the swapchain
7221 * the active context belongs to. The back buffer of the swapchain is stored as the
7222 * surface the context belongs to. */
7223 *width = surface->currentDesc.Width;
7224 *height = surface->currentDesc.Height;