wined3d: DepthStencilSurface hack
[wine/hacks.git] / dlls / wined3d / device.c
blob2523d0e9a3acfd8c9fcde08a8855794abd9e4761
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"
35 #include "winreg.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
38 #define GLINFO_LOCATION This->adapter->gl_info
40 /* Define the default light parameters as specified by MSDN */
41 const WINED3DLIGHT WINED3D_default_light = {
43 WINED3DLIGHT_DIRECTIONAL, /* Type */
44 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
45 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
46 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
47 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
48 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
49 0.0f, /* Range */
50 0.0f, /* Falloff */
51 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
52 0.0f, /* Theta */
53 0.0f /* Phi */
56 #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
57 /**********************************************************
58 * Global variable / Constants follow
59 **********************************************************/
60 const float identity[] =
62 1.0f, 0.0f, 0.0f, 0.0f,
63 0.0f, 1.0f, 0.0f, 0.0f,
64 0.0f, 0.0f, 1.0f, 0.0f,
65 0.0f, 0.0f, 0.0f, 1.0f,
66 }; /* When needed for comparisons */
68 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
69 * actually have the same values in GL and D3D. */
70 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
72 switch(primitive_type)
74 case WINED3DPT_POINTLIST:
75 return GL_POINTS;
77 case WINED3DPT_LINELIST:
78 return GL_LINES;
80 case WINED3DPT_LINESTRIP:
81 return GL_LINE_STRIP;
83 case WINED3DPT_TRIANGLELIST:
84 return GL_TRIANGLES;
86 case WINED3DPT_TRIANGLESTRIP:
87 return GL_TRIANGLE_STRIP;
89 case WINED3DPT_TRIANGLEFAN:
90 return GL_TRIANGLE_FAN;
92 case WINED3DPT_LINELIST_ADJ:
93 return GL_LINES_ADJACENCY_ARB;
95 case WINED3DPT_LINESTRIP_ADJ:
96 return GL_LINE_STRIP_ADJACENCY_ARB;
98 case WINED3DPT_TRIANGLELIST_ADJ:
99 return GL_TRIANGLES_ADJACENCY_ARB;
101 case WINED3DPT_TRIANGLESTRIP_ADJ:
102 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
104 default:
105 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
106 return GL_NONE;
110 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
112 switch(primitive_type)
114 case GL_POINTS:
115 return WINED3DPT_POINTLIST;
117 case GL_LINES:
118 return WINED3DPT_LINELIST;
120 case GL_LINE_STRIP:
121 return WINED3DPT_LINESTRIP;
123 case GL_TRIANGLES:
124 return WINED3DPT_TRIANGLELIST;
126 case GL_TRIANGLE_STRIP:
127 return WINED3DPT_TRIANGLESTRIP;
129 case GL_TRIANGLE_FAN:
130 return WINED3DPT_TRIANGLEFAN;
132 case GL_LINES_ADJACENCY_ARB:
133 return WINED3DPT_LINELIST_ADJ;
135 case GL_LINE_STRIP_ADJACENCY_ARB:
136 return WINED3DPT_LINESTRIP_ADJ;
138 case GL_TRIANGLES_ADJACENCY_ARB:
139 return WINED3DPT_TRIANGLELIST_ADJ;
141 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
142 return WINED3DPT_TRIANGLESTRIP_ADJ;
144 default:
145 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
146 return WINED3DPT_UNDEFINED;
150 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
152 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
153 *regnum = WINED3D_FFP_POSITION;
154 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
155 *regnum = WINED3D_FFP_BLENDWEIGHT;
156 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
157 *regnum = WINED3D_FFP_BLENDINDICES;
158 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
159 *regnum = WINED3D_FFP_NORMAL;
160 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
161 *regnum = WINED3D_FFP_PSIZE;
162 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
163 *regnum = WINED3D_FFP_DIFFUSE;
164 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
165 *regnum = WINED3D_FFP_SPECULAR;
166 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
167 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
168 else
170 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
171 *regnum = ~0U;
172 return FALSE;
175 return TRUE;
178 /* Context activation is done by the caller. */
179 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
180 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
182 /* We need to deal with frequency data! */
183 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
184 UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
185 const DWORD *streams = declaration->streams;
186 unsigned int i;
188 stream_info->use_map = 0;
189 stream_info->swizzle_map = 0;
191 /* Check for transformed vertices, disable vertex shader if present. */
192 stream_info->position_transformed = declaration->position_transformed;
193 if (declaration->position_transformed) use_vshader = FALSE;
195 /* Translate the declaration into strided data. */
196 for (i = 0; i < declaration->element_count; ++i)
198 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
199 GLuint buffer_object = 0;
200 const BYTE *data = NULL;
201 BOOL stride_used;
202 unsigned int idx;
203 DWORD stride;
205 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
206 element, i + 1, declaration->element_count);
208 if (!This->stateBlock->streamSource[element->input_slot]) continue;
210 stride = This->stateBlock->streamStride[element->input_slot];
211 if (This->stateBlock->streamIsUP)
213 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
214 buffer_object = 0;
215 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
217 else
219 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
220 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
222 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
223 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
224 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
225 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
226 * not, drawStridedSlow is needed, including a vertex buffer path. */
227 if (This->stateBlock->loadBaseVertexIndex < 0)
229 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
230 buffer_object = 0;
231 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
232 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
234 FIXME("System memory vertex data load offset is negative!\n");
238 if (fixup)
240 if (buffer_object) *fixup = TRUE;
241 else if (*fixup && !use_vshader
242 && (element->usage == WINED3DDECLUSAGE_COLOR
243 || element->usage == WINED3DDECLUSAGE_POSITIONT))
245 static BOOL warned = FALSE;
246 if (!warned)
248 /* This may be bad with the fixed function pipeline. */
249 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
250 warned = TRUE;
255 data += element->offset;
257 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
259 if (use_vshader)
261 if (element->output_slot == ~0U)
263 /* TODO: Assuming vertexdeclarations are usually used with the
264 * same or a similar shader, it might be worth it to store the
265 * last used output slot and try that one first. */
266 stride_used = vshader_get_input(This->stateBlock->vertexShader,
267 element->usage, element->usage_idx, &idx);
269 else
271 idx = element->output_slot;
272 stride_used = TRUE;
275 else
277 if (!element->ffp_valid)
279 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
280 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
281 stride_used = FALSE;
283 else
285 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
289 if (stride_used)
291 TRACE("Load %s array %u [usage %s, usage_idx %u, "
292 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
293 use_vshader ? "shader": "fixed function", idx,
294 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
295 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
297 stream_info->elements[idx].format_desc = element->format_desc;
298 stream_info->elements[idx].stride = stride;
299 stream_info->elements[idx].data = data;
300 stream_info->elements[idx].stream_idx = element->input_slot;
301 stream_info->elements[idx].buffer_object = buffer_object;
303 if (!This->adapter->gl_info.supported[EXT_VERTEX_ARRAY_BGRA]
304 && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
306 stream_info->swizzle_map |= 1 << idx;
308 stream_info->use_map |= 1 << idx;
312 /* Now call PreLoad on all the vertex buffers. In the very rare case
313 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
314 * The vertex buffer can now use the strided structure in the device instead of finding its
315 * own again.
317 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
318 * once in there. */
319 for (i = 0; i < stream_count; ++i)
321 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
322 if (vb) IWineD3DBuffer_PreLoad(vb);
326 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
327 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
329 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, gl_info);
330 e->format_desc = format_desc;
331 e->stride = strided->dwStride;
332 e->data = strided->lpData;
333 e->stream_idx = 0;
334 e->buffer_object = 0;
337 void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
338 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
340 unsigned int i;
342 memset(stream_info, 0, sizeof(*stream_info));
344 if (strided->position.lpData)
345 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
346 if (strided->normal.lpData)
347 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
348 if (strided->diffuse.lpData)
349 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
350 if (strided->specular.lpData)
351 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
353 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
355 if (strided->texCoords[i].lpData)
356 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
357 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
360 stream_info->position_transformed = strided->position_transformed;
362 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
364 if (!stream_info->elements[i].format_desc) continue;
366 if (!gl_info->supported[EXT_VERTEX_ARRAY_BGRA]
367 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
369 stream_info->swizzle_map |= 1 << i;
371 stream_info->use_map |= 1 << i;
375 /**********************************************************
376 * IUnknown parts follows
377 **********************************************************/
379 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
383 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
384 if (IsEqualGUID(riid, &IID_IUnknown)
385 || IsEqualGUID(riid, &IID_IWineD3DBase)
386 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
387 IUnknown_AddRef(iface);
388 *ppobj = This;
389 return S_OK;
391 *ppobj = NULL;
392 return E_NOINTERFACE;
395 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
397 ULONG refCount = InterlockedIncrement(&This->ref);
399 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
400 return refCount;
403 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
405 ULONG refCount = InterlockedDecrement(&This->ref);
407 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
409 if (!refCount) {
410 UINT i;
412 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
413 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
414 This->multistate_funcs[i] = NULL;
417 /* TODO: Clean up all the surfaces and textures! */
418 /* NOTE: You must release the parent if the object was created via a callback
419 ** ***************************/
421 if (!list_empty(&This->resources)) {
422 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
423 dumpResources(&This->resources);
426 if(This->contexts) ERR("Context array not freed!\n");
427 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
428 This->haveHardwareCursor = FALSE;
430 IWineD3D_Release(This->wined3d);
431 This->wined3d = NULL;
432 HeapFree(GetProcessHeap(), 0, This);
433 TRACE("Freed device %p\n", This);
434 This = NULL;
436 return refCount;
439 /**********************************************************
440 * IWineD3DDevice implementation follows
441 **********************************************************/
442 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
444 *pParent = This->parent;
445 IUnknown_AddRef(This->parent);
446 return WINED3D_OK;
449 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
450 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
453 struct wined3d_buffer *object;
454 HRESULT hr;
456 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
458 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
459 if (!object)
461 ERR("Failed to allocate memory\n");
462 return E_OUTOFMEMORY;
465 FIXME("Ignoring access flags (pool)\n");
467 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
468 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
469 if (FAILED(hr))
471 WARN("Failed to initialize buffer, hr %#x.\n", hr);
472 HeapFree(GetProcessHeap(), 0, object);
473 return hr;
475 object->desc = *desc;
477 TRACE("Created buffer %p.\n", object);
479 *buffer = (IWineD3DBuffer *)object;
481 return WINED3D_OK;
484 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
485 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
486 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
489 struct wined3d_buffer *object;
490 HRESULT hr;
492 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
493 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
495 if (Pool == WINED3DPOOL_SCRATCH)
497 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
498 * anyway, SCRATCH vertex buffers aren't usable anywhere
500 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
501 *ppVertexBuffer = NULL;
502 return WINED3DERR_INVALIDCALL;
505 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
506 if (!object)
508 ERR("Out of memory\n");
509 *ppVertexBuffer = NULL;
510 return WINED3DERR_OUTOFVIDEOMEMORY;
513 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
514 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
515 if (FAILED(hr))
517 WARN("Failed to initialize buffer, hr %#x.\n", hr);
518 HeapFree(GetProcessHeap(), 0, object);
519 return hr;
522 TRACE("Created buffer %p.\n", object);
523 *ppVertexBuffer = (IWineD3DBuffer *)object;
525 return WINED3D_OK;
528 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
529 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
530 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
533 struct wined3d_buffer *object;
534 HRESULT hr;
536 TRACE("(%p) Creating index buffer\n", This);
538 /* Allocate the storage for the device */
539 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
540 if (!object)
542 ERR("Out of memory\n");
543 *ppIndexBuffer = NULL;
544 return WINED3DERR_OUTOFVIDEOMEMORY;
547 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
548 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
549 parent, parent_ops);
550 if (FAILED(hr))
552 WARN("Failed to initialize buffer, hr %#x\n", hr);
553 HeapFree(GetProcessHeap(), 0, object);
554 return hr;
557 TRACE("Created buffer %p.\n", object);
559 *ppIndexBuffer = (IWineD3DBuffer *) object;
561 return WINED3D_OK;
564 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
565 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
568 IWineD3DStateBlockImpl *object;
569 HRESULT hr;
571 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
572 if(!object)
574 ERR("Failed to allocate stateblock memory.\n");
575 return E_OUTOFMEMORY;
578 hr = stateblock_init(object, This, type);
579 if (FAILED(hr))
581 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
582 HeapFree(GetProcessHeap(), 0, object);
583 return hr;
586 TRACE("Created stateblock %p.\n", object);
587 *stateblock = (IWineD3DStateBlock *)object;
589 return WINED3D_OK;
592 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
593 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
594 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
595 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
598 IWineD3DSurfaceImpl *object;
599 HRESULT hr;
601 TRACE("(%p) Create surface\n",This);
603 if (Impl == SURFACE_OPENGL && !This->adapter)
605 ERR("OpenGL surfaces are not available without OpenGL.\n");
606 return WINED3DERR_NOTAVAILABLE;
609 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
610 if (!object)
612 ERR("Failed to allocate surface memory.\n");
613 return WINED3DERR_OUTOFVIDEOMEMORY;
616 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
617 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
618 if (FAILED(hr))
620 WARN("Failed to initialize surface, returning %#x.\n", hr);
621 HeapFree(GetProcessHeap(), 0, object);
622 return hr;
625 TRACE("(%p) : Created surface %p\n", This, object);
627 *ppSurface = (IWineD3DSurface *)object;
629 return hr;
632 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
633 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
635 struct wined3d_rendertarget_view *object;
637 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
638 if (!object)
640 ERR("Failed to allocate memory\n");
641 return E_OUTOFMEMORY;
644 object->vtbl = &wined3d_rendertarget_view_vtbl;
645 object->refcount = 1;
646 IWineD3DResource_AddRef(resource);
647 object->resource = resource;
648 object->parent = parent;
650 *rendertarget_view = (IWineD3DRendertargetView *)object;
652 return WINED3D_OK;
655 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
656 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
657 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
660 IWineD3DTextureImpl *object;
661 HRESULT hr;
663 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
664 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
665 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
667 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
668 if (!object)
670 ERR("Out of memory\n");
671 *ppTexture = NULL;
672 return WINED3DERR_OUTOFVIDEOMEMORY;
675 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
676 if (FAILED(hr))
678 WARN("Failed to initialize texture, returning %#x\n", hr);
679 HeapFree(GetProcessHeap(), 0, object);
680 *ppTexture = NULL;
681 return hr;
684 *ppTexture = (IWineD3DTexture *)object;
686 TRACE("(%p) : Created texture %p\n", This, object);
688 return WINED3D_OK;
691 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
692 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
693 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
695 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
696 IWineD3DVolumeTextureImpl *object;
697 HRESULT hr;
699 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
700 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
702 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
703 if (!object)
705 ERR("Out of memory\n");
706 *ppVolumeTexture = NULL;
707 return WINED3DERR_OUTOFVIDEOMEMORY;
710 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
711 if (FAILED(hr))
713 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
714 HeapFree(GetProcessHeap(), 0, object);
715 *ppVolumeTexture = NULL;
716 return hr;
719 TRACE("(%p) : Created volume texture %p.\n", This, object);
720 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
722 return WINED3D_OK;
725 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
726 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
727 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
730 IWineD3DVolumeImpl *object;
731 HRESULT hr;
733 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
734 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
736 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
737 if (!object)
739 ERR("Out of memory\n");
740 *ppVolume = NULL;
741 return WINED3DERR_OUTOFVIDEOMEMORY;
744 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
745 if (FAILED(hr))
747 WARN("Failed to initialize volume, returning %#x.\n", hr);
748 HeapFree(GetProcessHeap(), 0, object);
749 return hr;
752 TRACE("(%p) : Created volume %p.\n", This, object);
753 *ppVolume = (IWineD3DVolume *)object;
755 return WINED3D_OK;
758 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
759 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
760 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
763 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
764 HRESULT hr;
766 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
767 if (!object)
769 ERR("Out of memory\n");
770 *ppCubeTexture = NULL;
771 return WINED3DERR_OUTOFVIDEOMEMORY;
774 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
775 if (FAILED(hr))
777 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
778 HeapFree(GetProcessHeap(), 0, object);
779 *ppCubeTexture = NULL;
780 return hr;
783 TRACE("(%p) : Created Cube Texture %p\n", This, object);
784 *ppCubeTexture = (IWineD3DCubeTexture *)object;
786 return WINED3D_OK;
789 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
791 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
792 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
793 HRESULT hr = WINED3DERR_NOTAVAILABLE;
794 const IWineD3DQueryVtbl *vtable;
796 /* Just a check to see if we support this type of query */
797 switch(Type) {
798 case WINED3DQUERYTYPE_OCCLUSION:
799 TRACE("(%p) occlusion query\n", This);
800 if (gl_info->supported[ARB_OCCLUSION_QUERY])
801 hr = WINED3D_OK;
802 else
803 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
805 vtable = &IWineD3DOcclusionQuery_Vtbl;
806 break;
808 case WINED3DQUERYTYPE_EVENT:
809 if (!gl_info->supported[NV_FENCE] && !gl_info->supported[APPLE_FENCE])
811 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
812 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
814 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
816 vtable = &IWineD3DEventQuery_Vtbl;
817 hr = WINED3D_OK;
818 break;
820 case WINED3DQUERYTYPE_VCACHE:
821 case WINED3DQUERYTYPE_RESOURCEMANAGER:
822 case WINED3DQUERYTYPE_VERTEXSTATS:
823 case WINED3DQUERYTYPE_TIMESTAMP:
824 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
825 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
826 case WINED3DQUERYTYPE_PIPELINETIMINGS:
827 case WINED3DQUERYTYPE_INTERFACETIMINGS:
828 case WINED3DQUERYTYPE_VERTEXTIMINGS:
829 case WINED3DQUERYTYPE_PIXELTIMINGS:
830 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
831 case WINED3DQUERYTYPE_CACHEUTILIZATION:
832 default:
833 /* Use the base Query vtable until we have a special one for each query */
834 vtable = &IWineD3DQuery_Vtbl;
835 FIXME("(%p) Unhandled query type %d\n", This, Type);
837 if(NULL == ppQuery || hr != WINED3D_OK) {
838 return hr;
841 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
842 if(!object)
844 ERR("Out of memory\n");
845 *ppQuery = NULL;
846 return WINED3DERR_OUTOFVIDEOMEMORY;
849 object->lpVtbl = vtable;
850 object->type = Type;
851 object->state = QUERY_CREATED;
852 object->device = This;
853 object->parent = parent;
854 object->ref = 1;
856 *ppQuery = (IWineD3DQuery *)object;
858 /* allocated the 'extended' data based on the type of query requested */
859 switch(Type){
860 case WINED3DQUERYTYPE_OCCLUSION:
861 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
862 ((struct wined3d_occlusion_query *)object->extendedData)->context = NULL;
863 break;
865 case WINED3DQUERYTYPE_EVENT:
866 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query));
867 ((struct wined3d_event_query *)object->extendedData)->context = NULL;
868 break;
870 case WINED3DQUERYTYPE_VCACHE:
871 case WINED3DQUERYTYPE_RESOURCEMANAGER:
872 case WINED3DQUERYTYPE_VERTEXSTATS:
873 case WINED3DQUERYTYPE_TIMESTAMP:
874 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
875 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
876 case WINED3DQUERYTYPE_PIPELINETIMINGS:
877 case WINED3DQUERYTYPE_INTERFACETIMINGS:
878 case WINED3DQUERYTYPE_VERTEXTIMINGS:
879 case WINED3DQUERYTYPE_PIXELTIMINGS:
880 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
881 case WINED3DQUERYTYPE_CACHEUTILIZATION:
882 default:
883 object->extendedData = 0;
884 FIXME("(%p) Unhandled query type %d\n",This , Type);
886 TRACE("(%p) : Created Query %p\n", This, object);
887 return WINED3D_OK;
890 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
891 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
892 IUnknown *parent, WINED3DSURFTYPE surface_type)
894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
895 IWineD3DSwapChainImpl *object;
896 HRESULT hr;
898 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
899 iface, present_parameters, swapchain, parent, surface_type);
901 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
902 if (!object)
904 ERR("Failed to allocate swapchain memory.\n");
905 return E_OUTOFMEMORY;
908 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
909 if (FAILED(hr))
911 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
912 HeapFree(GetProcessHeap(), 0, object);
913 return hr;
916 TRACE("Created swapchain %p.\n", object);
917 *swapchain = (IWineD3DSwapChain *)object;
919 return WINED3D_OK;
922 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
923 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
925 TRACE("(%p)\n", This);
927 return This->NumberOfSwapChains;
930 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
932 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
934 if(iSwapChain < This->NumberOfSwapChains) {
935 *pSwapChain = This->swapchains[iSwapChain];
936 IWineD3DSwapChain_AddRef(*pSwapChain);
937 TRACE("(%p) returning %p\n", This, *pSwapChain);
938 return WINED3D_OK;
939 } else {
940 TRACE("Swapchain out of range\n");
941 *pSwapChain = NULL;
942 return WINED3DERR_INVALIDCALL;
946 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
947 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
948 const WINED3DVERTEXELEMENT *elements, UINT element_count)
950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
951 IWineD3DVertexDeclarationImpl *object = NULL;
952 HRESULT hr;
954 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
955 iface, declaration, parent, elements, element_count);
957 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
958 if(!object)
960 ERR("Failed to allocate vertex declaration memory.\n");
961 return E_OUTOFMEMORY;
964 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
965 if (FAILED(hr))
967 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
968 HeapFree(GetProcessHeap(), 0, object);
969 return hr;
972 TRACE("Created vertex declaration %p.\n", object);
973 *declaration = (IWineD3DVertexDeclaration *)object;
975 return WINED3D_OK;
978 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
979 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
981 unsigned int idx, idx2;
982 unsigned int offset;
983 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
984 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
985 BOOL has_blend_idx = has_blend &&
986 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
987 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
988 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
989 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
990 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
991 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
992 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
994 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
995 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
996 WINED3DVERTEXELEMENT *elements = NULL;
998 unsigned int size;
999 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1000 if (has_blend_idx) num_blends--;
1002 /* Compute declaration size */
1003 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1004 has_psize + has_diffuse + has_specular + num_textures;
1006 /* convert the declaration */
1007 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1008 if (!elements) return ~0U;
1010 idx = 0;
1011 if (has_pos) {
1012 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1013 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1014 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1016 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1017 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1018 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1020 else {
1021 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1022 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1024 elements[idx].usage_idx = 0;
1025 idx++;
1027 if (has_blend && (num_blends > 0)) {
1028 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1029 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1030 else {
1031 switch(num_blends) {
1032 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1033 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1034 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1035 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1036 default:
1037 ERR("Unexpected amount of blend values: %u\n", num_blends);
1040 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1041 elements[idx].usage_idx = 0;
1042 idx++;
1044 if (has_blend_idx) {
1045 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1046 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1047 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1048 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1049 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1050 else
1051 elements[idx].format = WINED3DFMT_R32_FLOAT;
1052 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1053 elements[idx].usage_idx = 0;
1054 idx++;
1056 if (has_normal) {
1057 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1058 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1059 elements[idx].usage_idx = 0;
1060 idx++;
1062 if (has_psize) {
1063 elements[idx].format = WINED3DFMT_R32_FLOAT;
1064 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1065 elements[idx].usage_idx = 0;
1066 idx++;
1068 if (has_diffuse) {
1069 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1070 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1071 elements[idx].usage_idx = 0;
1072 idx++;
1074 if (has_specular) {
1075 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1076 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1077 elements[idx].usage_idx = 1;
1078 idx++;
1080 for (idx2 = 0; idx2 < num_textures; idx2++) {
1081 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1082 switch (numcoords) {
1083 case WINED3DFVF_TEXTUREFORMAT1:
1084 elements[idx].format = WINED3DFMT_R32_FLOAT;
1085 break;
1086 case WINED3DFVF_TEXTUREFORMAT2:
1087 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1088 break;
1089 case WINED3DFVF_TEXTUREFORMAT3:
1090 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1091 break;
1092 case WINED3DFVF_TEXTUREFORMAT4:
1093 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1094 break;
1096 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1097 elements[idx].usage_idx = idx2;
1098 idx++;
1101 /* Now compute offsets, and initialize the rest of the fields */
1102 for (idx = 0, offset = 0; idx < size; ++idx)
1104 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1105 elements[idx].input_slot = 0;
1106 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1107 elements[idx].offset = offset;
1108 offset += format_desc->component_count * format_desc->component_size;
1111 *ppVertexElements = elements;
1112 return size;
1115 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1116 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1117 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1120 WINED3DVERTEXELEMENT *elements;
1121 unsigned int size;
1122 DWORD hr;
1124 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1126 size = ConvertFvfToDeclaration(This, fvf, &elements);
1127 if (size == ~0U) return E_OUTOFMEMORY;
1129 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1130 HeapFree(GetProcessHeap(), 0, elements);
1131 return hr;
1134 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1135 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1136 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1137 const struct wined3d_parent_ops *parent_ops)
1139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1140 IWineD3DVertexShaderImpl *object;
1141 HRESULT hr;
1143 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1144 if (!object)
1146 ERR("Failed to allocate shader memory.\n");
1147 return E_OUTOFMEMORY;
1150 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1151 if (FAILED(hr))
1153 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1154 HeapFree(GetProcessHeap(), 0, object);
1155 return hr;
1158 TRACE("Created vertex shader %p.\n", object);
1159 *ppVertexShader = (IWineD3DVertexShader *)object;
1161 return WINED3D_OK;
1164 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1165 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1166 IWineD3DGeometryShader **shader, IUnknown *parent,
1167 const struct wined3d_parent_ops *parent_ops)
1169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1170 struct wined3d_geometryshader *object;
1171 HRESULT hr;
1173 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1174 if (!object)
1176 ERR("Failed to allocate shader memory.\n");
1177 return E_OUTOFMEMORY;
1180 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1181 if (FAILED(hr))
1183 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1184 HeapFree(GetProcessHeap(), 0, object);
1185 return hr;
1188 TRACE("Created geometry shader %p.\n", object);
1189 *shader = (IWineD3DGeometryShader *)object;
1191 return WINED3D_OK;
1194 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1195 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1196 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1197 const struct wined3d_parent_ops *parent_ops)
1199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1200 IWineD3DPixelShaderImpl *object;
1201 HRESULT hr;
1203 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1204 if (!object)
1206 ERR("Failed to allocate shader memory.\n");
1207 return E_OUTOFMEMORY;
1210 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1211 if (FAILED(hr))
1213 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1214 HeapFree(GetProcessHeap(), 0, object);
1215 return hr;
1218 TRACE("Created pixel shader %p.\n", object);
1219 *ppPixelShader = (IWineD3DPixelShader *)object;
1221 return WINED3D_OK;
1224 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1225 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1228 IWineD3DPaletteImpl *object;
1229 HRESULT hr;
1230 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1232 /* Create the new object */
1233 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1234 if(!object) {
1235 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1236 return E_OUTOFMEMORY;
1239 object->lpVtbl = &IWineD3DPalette_Vtbl;
1240 object->ref = 1;
1241 object->Flags = Flags;
1242 object->parent = Parent;
1243 object->device = This;
1244 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1245 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1247 if(!object->hpal) {
1248 HeapFree( GetProcessHeap(), 0, object);
1249 return E_OUTOFMEMORY;
1252 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1253 if(FAILED(hr)) {
1254 IWineD3DPalette_Release((IWineD3DPalette *) object);
1255 return hr;
1258 *Palette = (IWineD3DPalette *) object;
1260 return WINED3D_OK;
1263 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1264 HBITMAP hbm;
1265 BITMAP bm;
1266 HRESULT hr;
1267 HDC dcb = NULL, dcs = NULL;
1268 WINEDDCOLORKEY colorkey;
1270 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1271 if(hbm)
1273 GetObjectA(hbm, sizeof(BITMAP), &bm);
1274 dcb = CreateCompatibleDC(NULL);
1275 if(!dcb) goto out;
1276 SelectObject(dcb, hbm);
1278 else
1280 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1281 * couldn't be loaded
1283 memset(&bm, 0, sizeof(bm));
1284 bm.bmWidth = 32;
1285 bm.bmHeight = 32;
1288 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1289 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1290 NULL, &wined3d_null_parent_ops);
1291 if(FAILED(hr)) {
1292 ERR("Wine logo requested, but failed to create surface\n");
1293 goto out;
1296 if(dcb) {
1297 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1298 if(FAILED(hr)) goto out;
1299 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1300 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1302 colorkey.dwColorSpaceLowValue = 0;
1303 colorkey.dwColorSpaceHighValue = 0;
1304 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1305 } else {
1306 /* Fill the surface with a white color to show that wined3d is there */
1307 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1310 out:
1311 if (dcb) DeleteDC(dcb);
1312 if (hbm) DeleteObject(hbm);
1315 /* Context activation is done by the caller. */
1316 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1318 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1319 unsigned int i;
1320 /* Under DirectX you can have texture stage operations even if no texture is
1321 bound, whereas opengl will only do texture operations when a valid texture is
1322 bound. We emulate this by creating dummy textures and binding them to each
1323 texture stage, but disable all stages by default. Hence if a stage is enabled
1324 then the default texture will kick in until replaced by a SetTexture call */
1325 ENTER_GL();
1327 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1329 /* The dummy texture does not have client storage backing */
1330 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1331 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1334 for (i = 0; i < gl_info->limits.textures; ++i)
1336 GLubyte white = 255;
1338 /* Make appropriate texture active */
1339 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1340 checkGLcall("glActiveTextureARB");
1342 /* Generate an opengl texture name */
1343 glGenTextures(1, &This->dummyTextureName[i]);
1344 checkGLcall("glGenTextures");
1345 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1347 /* Generate a dummy 2d texture (not using 1d because they cause many
1348 * DRI drivers fall back to sw) */
1349 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1350 checkGLcall("glBindTexture");
1352 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1353 checkGLcall("glTexImage2D");
1356 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1358 /* Reenable because if supported it is enabled by default */
1359 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1360 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1363 LEAVE_GL();
1366 /* Context activation is done by the caller. */
1367 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1369 ENTER_GL();
1370 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1371 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1372 LEAVE_GL();
1374 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1377 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1378 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1381 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1382 IWineD3DSwapChainImpl *swapchain = NULL;
1383 struct wined3d_context *context;
1384 HRESULT hr;
1385 DWORD state;
1386 unsigned int i;
1388 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1390 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1391 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1393 if (!pPresentationParameters->Windowed)
1395 This->focus_window = This->createParms.hFocusWindow;
1396 if (!This->focus_window) This->focus_window = pPresentationParameters->hDeviceWindow;
1397 if (!wined3d_register_window(This->focus_window, This))
1399 ERR("Failed to register window %p.\n", This->focus_window);
1400 return E_FAIL;
1404 TRACE("(%p) : Creating stateblock\n", This);
1405 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1406 hr = IWineD3DDevice_CreateStateBlock(iface,
1407 WINED3DSBT_INIT,
1408 (IWineD3DStateBlock **)&This->stateBlock,
1409 NULL);
1410 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1411 WARN("Failed to create stateblock\n");
1412 goto err_out;
1414 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1415 This->updateStateBlock = This->stateBlock;
1416 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1418 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1419 sizeof(IWineD3DSurface *) * gl_info->limits.buffers);
1420 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1421 sizeof(GLenum) * gl_info->limits.buffers);
1423 This->NumberOfPalettes = 1;
1424 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1425 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1426 ERR("Out of memory!\n");
1427 hr = E_OUTOFMEMORY;
1428 goto err_out;
1430 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1431 if(!This->palettes[0]) {
1432 ERR("Out of memory!\n");
1433 hr = E_OUTOFMEMORY;
1434 goto err_out;
1436 for (i = 0; i < 256; ++i) {
1437 This->palettes[0][i].peRed = 0xFF;
1438 This->palettes[0][i].peGreen = 0xFF;
1439 This->palettes[0][i].peBlue = 0xFF;
1440 This->palettes[0][i].peFlags = 0xFF;
1442 This->currentPalette = 0;
1444 /* Initialize the texture unit mapping to a 1:1 mapping */
1445 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1447 if (state < gl_info->limits.fragment_samplers)
1449 This->texUnitMap[state] = state;
1450 This->rev_tex_unit_map[state] = state;
1451 } else {
1452 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1453 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1457 if (This->focus_window) SetFocus(This->focus_window);
1459 /* Setup the implicit swapchain. This also initializes a context. */
1460 TRACE("Creating implicit swapchain\n");
1461 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1462 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1463 if (FAILED(hr))
1465 WARN("Failed to create implicit swapchain\n");
1466 goto err_out;
1469 This->NumberOfSwapChains = 1;
1470 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1471 if(!This->swapchains) {
1472 ERR("Out of memory!\n");
1473 goto err_out;
1475 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1477 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1478 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1479 This->render_targets[0] = swapchain->backBuffer[0];
1481 else {
1482 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1483 This->render_targets[0] = swapchain->frontBuffer;
1485 IWineD3DSurface_AddRef(This->render_targets[0]);
1487 /* Depth Stencil support */
1488 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1489 if (NULL != This->stencilBufferTarget) {
1490 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1493 hr = This->shader_backend->shader_alloc_private(iface);
1494 if(FAILED(hr)) {
1495 TRACE("Shader private data couldn't be allocated\n");
1496 goto err_out;
1498 hr = This->frag_pipe->alloc_private(iface);
1499 if(FAILED(hr)) {
1500 TRACE("Fragment pipeline private data couldn't be allocated\n");
1501 goto err_out;
1503 hr = This->blitter->alloc_private(iface);
1504 if(FAILED(hr)) {
1505 TRACE("Blitter private data couldn't be allocated\n");
1506 goto err_out;
1509 /* Set up some starting GL setup */
1511 /* Setup all the devices defaults */
1512 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1514 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1516 create_dummy_textures(This);
1518 ENTER_GL();
1520 /* Initialize the current view state */
1521 This->view_ident = 1;
1522 This->contexts[0]->last_was_rhw = 0;
1523 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1524 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1526 switch(wined3d_settings.offscreen_rendering_mode) {
1527 case ORM_FBO:
1528 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1529 break;
1531 case ORM_PBUFFER:
1532 This->offscreenBuffer = GL_BACK;
1533 break;
1535 case ORM_BACKBUFFER:
1537 if (context_get_current()->aux_buffers > 0)
1539 TRACE("Using auxilliary buffer for offscreen rendering\n");
1540 This->offscreenBuffer = GL_AUX0;
1541 } else {
1542 TRACE("Using back buffer for offscreen rendering\n");
1543 This->offscreenBuffer = GL_BACK;
1548 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1549 LEAVE_GL();
1551 context_release(context);
1553 /* Clear the screen */
1554 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1555 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1556 0x00, 1.0f, 0);
1558 This->d3d_initialized = TRUE;
1560 if(wined3d_settings.logo) {
1561 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1563 This->highest_dirty_ps_const = 0;
1564 This->highest_dirty_vs_const = 0;
1565 return WINED3D_OK;
1567 err_out:
1568 HeapFree(GetProcessHeap(), 0, This->render_targets);
1569 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1570 HeapFree(GetProcessHeap(), 0, This->swapchains);
1571 This->NumberOfSwapChains = 0;
1572 if(This->palettes) {
1573 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1574 HeapFree(GetProcessHeap(), 0, This->palettes);
1576 This->NumberOfPalettes = 0;
1577 if(swapchain) {
1578 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1580 if(This->stateBlock) {
1581 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1582 This->stateBlock = NULL;
1584 if (This->blit_priv) {
1585 This->blitter->free_private(iface);
1587 if (This->fragment_priv) {
1588 This->frag_pipe->free_private(iface);
1590 if (This->shader_priv) {
1591 This->shader_backend->shader_free_private(iface);
1593 if (This->focus_window) wined3d_unregister_window(This->focus_window);
1594 return hr;
1597 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1598 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1601 IWineD3DSwapChainImpl *swapchain = NULL;
1602 HRESULT hr;
1604 /* Setup the implicit swapchain */
1605 TRACE("Creating implicit swapchain\n");
1606 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1607 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1608 if (FAILED(hr))
1610 WARN("Failed to create implicit swapchain\n");
1611 goto err_out;
1614 This->NumberOfSwapChains = 1;
1615 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1616 if(!This->swapchains) {
1617 ERR("Out of memory!\n");
1618 goto err_out;
1620 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1621 return WINED3D_OK;
1623 err_out:
1624 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1625 return hr;
1628 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1630 IWineD3DResource_UnLoad(resource);
1631 IWineD3DResource_Release(resource);
1632 return WINED3D_OK;
1635 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1636 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1639 const struct wined3d_gl_info *gl_info;
1640 struct wined3d_context *context;
1641 int sampler;
1642 UINT i;
1643 TRACE("(%p)\n", This);
1645 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1647 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1648 * it was created. Thus make sure a context is active for the glDelete* calls
1650 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1651 gl_info = context->gl_info;
1653 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1655 /* Unload resources */
1656 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1658 TRACE("Deleting high order patches\n");
1659 for(i = 0; i < PATCHMAP_SIZE; i++) {
1660 struct list *e1, *e2;
1661 struct WineD3DRectPatch *patch;
1662 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1663 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1664 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1668 /* Delete the palette conversion shader if it is around */
1669 if(This->paletteConversionShader) {
1670 ENTER_GL();
1671 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
1672 LEAVE_GL();
1673 This->paletteConversionShader = 0;
1676 /* Delete the pbuffer context if there is any */
1677 if(This->pbufferContext) context_destroy(This, This->pbufferContext);
1679 /* Delete the mouse cursor texture */
1680 if(This->cursorTexture) {
1681 ENTER_GL();
1682 glDeleteTextures(1, &This->cursorTexture);
1683 LEAVE_GL();
1684 This->cursorTexture = 0;
1687 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1688 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1690 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1691 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1694 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1695 * private data, it might contain opengl pointers
1697 if(This->depth_blt_texture) {
1698 ENTER_GL();
1699 glDeleteTextures(1, &This->depth_blt_texture);
1700 LEAVE_GL();
1701 This->depth_blt_texture = 0;
1703 if (This->depth_blt_rb) {
1704 ENTER_GL();
1705 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1706 LEAVE_GL();
1707 This->depth_blt_rb = 0;
1708 This->depth_blt_rb_w = 0;
1709 This->depth_blt_rb_h = 0;
1712 /* Release the update stateblock */
1713 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1714 if(This->updateStateBlock != This->stateBlock)
1715 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1717 This->updateStateBlock = NULL;
1719 { /* because were not doing proper internal refcounts releasing the primary state block
1720 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1721 to set this->stateBlock = NULL; first */
1722 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1723 This->stateBlock = NULL;
1725 /* Release the stateblock */
1726 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1727 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1731 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1732 This->blitter->free_private(iface);
1733 This->frag_pipe->free_private(iface);
1734 This->shader_backend->shader_free_private(iface);
1736 /* Release the buffers (with sanity checks)*/
1737 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1738 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1739 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
1740 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
1742 This->stencilBufferTarget = NULL;
1744 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1745 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1746 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1748 TRACE("Setting rendertarget to NULL\n");
1749 This->render_targets[0] = NULL;
1751 if (This->auto_depth_stencil_buffer) {
1752 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
1754 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1756 This->auto_depth_stencil_buffer = NULL;
1759 context_release(context);
1761 for(i=0; i < This->NumberOfSwapChains; i++) {
1762 TRACE("Releasing the implicit swapchain %d\n", i);
1763 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1764 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1768 HeapFree(GetProcessHeap(), 0, This->swapchains);
1769 This->swapchains = NULL;
1770 This->NumberOfSwapChains = 0;
1772 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1773 HeapFree(GetProcessHeap(), 0, This->palettes);
1774 This->palettes = NULL;
1775 This->NumberOfPalettes = 0;
1777 HeapFree(GetProcessHeap(), 0, This->render_targets);
1778 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1779 This->render_targets = NULL;
1780 This->draw_buffers = NULL;
1782 This->d3d_initialized = FALSE;
1784 if (This->focus_window) wined3d_unregister_window(This->focus_window);
1786 return WINED3D_OK;
1789 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1791 unsigned int i;
1793 for(i=0; i < This->NumberOfSwapChains; i++) {
1794 TRACE("Releasing the implicit swapchain %d\n", i);
1795 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1796 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1800 HeapFree(GetProcessHeap(), 0, This->swapchains);
1801 This->swapchains = NULL;
1802 This->NumberOfSwapChains = 0;
1803 return WINED3D_OK;
1806 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1807 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1808 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1810 * There is no way to deactivate thread safety once it is enabled.
1812 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1813 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1815 /*For now just store the flag(needed in case of ddraw) */
1816 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1819 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1820 const WINED3DDISPLAYMODE* pMode) {
1821 DEVMODEW devmode;
1822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1823 LONG ret;
1824 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1825 RECT clip_rc;
1827 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1829 /* Resize the screen even without a window:
1830 * The app could have unset it with SetCooperativeLevel, but not called
1831 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1832 * but we don't have any hwnd
1835 memset(&devmode, 0, sizeof(devmode));
1836 devmode.dmSize = sizeof(devmode);
1837 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1838 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1839 devmode.dmPelsWidth = pMode->Width;
1840 devmode.dmPelsHeight = pMode->Height;
1842 devmode.dmDisplayFrequency = pMode->RefreshRate;
1843 if (pMode->RefreshRate != 0) {
1844 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1847 /* Only change the mode if necessary */
1848 if( (This->ddraw_width == pMode->Width) &&
1849 (This->ddraw_height == pMode->Height) &&
1850 (This->ddraw_format == pMode->Format) &&
1851 (pMode->RefreshRate == 0) ) {
1852 return WINED3D_OK;
1855 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1856 if (ret != DISP_CHANGE_SUCCESSFUL) {
1857 if(devmode.dmDisplayFrequency != 0) {
1858 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1859 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1860 devmode.dmDisplayFrequency = 0;
1861 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1863 if(ret != DISP_CHANGE_SUCCESSFUL) {
1864 return WINED3DERR_NOTAVAILABLE;
1868 /* Store the new values */
1869 This->ddraw_width = pMode->Width;
1870 This->ddraw_height = pMode->Height;
1871 This->ddraw_format = pMode->Format;
1873 /* And finally clip mouse to our screen */
1874 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1875 ClipCursor(&clip_rc);
1877 return WINED3D_OK;
1880 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1882 *ppD3D = This->wined3d;
1883 TRACE("Returning %p.\n", *ppD3D);
1884 IWineD3D_AddRef(*ppD3D);
1885 return WINED3D_OK;
1888 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1891 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1892 (This->adapter->TextureRam/(1024*1024)),
1893 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
1894 /* return simulated texture memory left */
1895 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
1898 /*****
1899 * Get / Set Stream Source
1900 *****/
1901 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
1902 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
1904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1905 IWineD3DBuffer *oldSrc;
1907 if (StreamNumber >= MAX_STREAMS) {
1908 WARN("Stream out of range %d\n", StreamNumber);
1909 return WINED3DERR_INVALIDCALL;
1910 } else if(OffsetInBytes & 0x3) {
1911 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
1912 return WINED3DERR_INVALIDCALL;
1915 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
1916 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
1918 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
1920 if(oldSrc == pStreamData &&
1921 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
1922 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
1923 TRACE("Application is setting the old values over, nothing to do\n");
1924 return WINED3D_OK;
1927 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
1928 if (pStreamData) {
1929 This->updateStateBlock->streamStride[StreamNumber] = Stride;
1930 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
1933 /* Handle recording of state blocks */
1934 if (This->isRecordingState) {
1935 TRACE("Recording... not performing anything\n");
1936 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
1937 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
1938 return WINED3D_OK;
1941 if (pStreamData != NULL) {
1942 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
1943 IWineD3DBuffer_AddRef(pStreamData);
1945 if (oldSrc != NULL) {
1946 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
1947 IWineD3DBuffer_Release(oldSrc);
1950 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
1952 return WINED3D_OK;
1955 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
1956 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
1958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1960 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
1961 This->stateBlock->streamSource[StreamNumber],
1962 This->stateBlock->streamOffset[StreamNumber],
1963 This->stateBlock->streamStride[StreamNumber]);
1965 if (StreamNumber >= MAX_STREAMS) {
1966 WARN("Stream out of range %d\n", StreamNumber);
1967 return WINED3DERR_INVALIDCALL;
1969 *pStream = This->stateBlock->streamSource[StreamNumber];
1970 *pStride = This->stateBlock->streamStride[StreamNumber];
1971 if (pOffset) {
1972 *pOffset = This->stateBlock->streamOffset[StreamNumber];
1975 if (*pStream != NULL) {
1976 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
1978 return WINED3D_OK;
1981 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
1982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1983 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
1984 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
1986 /* Verify input at least in d3d9 this is invalid*/
1987 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
1988 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
1989 return WINED3DERR_INVALIDCALL;
1991 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
1992 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
1993 return WINED3DERR_INVALIDCALL;
1995 if( Divider == 0 ){
1996 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
1997 return WINED3DERR_INVALIDCALL;
2000 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2001 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2003 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2004 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2006 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2007 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2008 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2011 return WINED3D_OK;
2014 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2017 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2018 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2020 TRACE("(%p) : returning %d\n", This, *Divider);
2022 return WINED3D_OK;
2025 /*****
2026 * Get / Set & Multiply Transform
2027 *****/
2028 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2031 /* Most of this routine, comments included copied from ddraw tree initially: */
2032 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2034 /* Handle recording of state blocks */
2035 if (This->isRecordingState) {
2036 TRACE("Recording... not performing anything\n");
2037 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2038 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2039 return WINED3D_OK;
2043 * If the new matrix is the same as the current one,
2044 * we cut off any further processing. this seems to be a reasonable
2045 * optimization because as was noticed, some apps (warcraft3 for example)
2046 * tend towards setting the same matrix repeatedly for some reason.
2048 * From here on we assume that the new matrix is different, wherever it matters.
2050 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2051 TRACE("The app is setting the same matrix over again\n");
2052 return WINED3D_OK;
2053 } else {
2054 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2058 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2059 where ViewMat = Camera space, WorldMat = world space.
2061 In OpenGL, camera and world space is combined into GL_MODELVIEW
2062 matrix. The Projection matrix stay projection matrix.
2065 /* Capture the times we can just ignore the change for now */
2066 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2067 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2068 /* Handled by the state manager */
2071 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2072 return WINED3D_OK;
2075 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2077 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2078 *pMatrix = This->stateBlock->transforms[State];
2079 return WINED3D_OK;
2082 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2083 const WINED3DMATRIX *mat = NULL;
2084 WINED3DMATRIX temp;
2086 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2087 * below means it will be recorded in a state block change, but it
2088 * works regardless where it is recorded.
2089 * If this is found to be wrong, change to StateBlock.
2091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2092 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2094 if (State <= HIGHEST_TRANSFORMSTATE)
2096 mat = &This->updateStateBlock->transforms[State];
2097 } else {
2098 FIXME("Unhandled transform state!!\n");
2101 multiply_matrix(&temp, mat, pMatrix);
2103 /* Apply change via set transform - will reapply to eg. lights this way */
2104 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2107 /*****
2108 * Get / Set Light
2109 *****/
2110 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2111 you can reference any indexes you want as long as that number max are enabled at any
2112 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2113 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2114 but when recording, just build a chain pretty much of commands to be replayed. */
2116 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2117 float rho;
2118 struct wined3d_light_info *object = NULL;
2119 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2120 struct list *e;
2122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2123 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2125 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2126 * the gl driver.
2128 if(!pLight) {
2129 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2130 return WINED3DERR_INVALIDCALL;
2133 switch(pLight->Type) {
2134 case WINED3DLIGHT_POINT:
2135 case WINED3DLIGHT_SPOT:
2136 case WINED3DLIGHT_PARALLELPOINT:
2137 case WINED3DLIGHT_GLSPOT:
2138 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2139 * most wanted
2141 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2143 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2144 return WINED3DERR_INVALIDCALL;
2146 break;
2148 case WINED3DLIGHT_DIRECTIONAL:
2149 /* Ignores attenuation */
2150 break;
2152 default:
2153 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2154 return WINED3DERR_INVALIDCALL;
2157 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2159 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2160 if(object->OriginalIndex == Index) break;
2161 object = NULL;
2164 if(!object) {
2165 TRACE("Adding new light\n");
2166 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2167 if(!object) {
2168 ERR("Out of memory error when allocating a light\n");
2169 return E_OUTOFMEMORY;
2171 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2172 object->glIndex = -1;
2173 object->OriginalIndex = Index;
2176 /* Initialize the object */
2177 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,
2178 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2179 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2180 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2181 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2182 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2183 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2185 /* Save away the information */
2186 object->OriginalParms = *pLight;
2188 switch (pLight->Type) {
2189 case WINED3DLIGHT_POINT:
2190 /* Position */
2191 object->lightPosn[0] = pLight->Position.x;
2192 object->lightPosn[1] = pLight->Position.y;
2193 object->lightPosn[2] = pLight->Position.z;
2194 object->lightPosn[3] = 1.0f;
2195 object->cutoff = 180.0f;
2196 /* FIXME: Range */
2197 break;
2199 case WINED3DLIGHT_DIRECTIONAL:
2200 /* Direction */
2201 object->lightPosn[0] = -pLight->Direction.x;
2202 object->lightPosn[1] = -pLight->Direction.y;
2203 object->lightPosn[2] = -pLight->Direction.z;
2204 object->lightPosn[3] = 0.0f;
2205 object->exponent = 0.0f;
2206 object->cutoff = 180.0f;
2207 break;
2209 case WINED3DLIGHT_SPOT:
2210 /* Position */
2211 object->lightPosn[0] = pLight->Position.x;
2212 object->lightPosn[1] = pLight->Position.y;
2213 object->lightPosn[2] = pLight->Position.z;
2214 object->lightPosn[3] = 1.0f;
2216 /* Direction */
2217 object->lightDirn[0] = pLight->Direction.x;
2218 object->lightDirn[1] = pLight->Direction.y;
2219 object->lightDirn[2] = pLight->Direction.z;
2220 object->lightDirn[3] = 1.0f;
2223 * opengl-ish and d3d-ish spot lights use too different models for the
2224 * light "intensity" as a function of the angle towards the main light direction,
2225 * so we only can approximate very roughly.
2226 * however spot lights are rather rarely used in games (if ever used at all).
2227 * furthermore if still used, probably nobody pays attention to such details.
2229 if (pLight->Falloff == 0) {
2230 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2231 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2232 * will always be 1.0 for both of them, and we don't have to care for the
2233 * rest of the rather complex calculation
2235 object->exponent = 0.0f;
2236 } else {
2237 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2238 if (rho < 0.0001f) rho = 0.0001f;
2239 object->exponent = -0.3f/logf(cosf(rho/2));
2241 if (object->exponent > 128.0f)
2243 object->exponent = 128.0f;
2245 object->cutoff = pLight->Phi*90/M_PI;
2247 /* FIXME: Range */
2248 break;
2250 default:
2251 FIXME("Unrecognized light type %d\n", pLight->Type);
2254 /* Update the live definitions if the light is currently assigned a glIndex */
2255 if (object->glIndex != -1 && !This->isRecordingState) {
2256 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2258 return WINED3D_OK;
2261 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2263 struct wined3d_light_info *lightInfo = NULL;
2264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2265 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2266 struct list *e;
2267 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2269 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2271 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2272 if(lightInfo->OriginalIndex == Index) break;
2273 lightInfo = NULL;
2276 if (lightInfo == NULL) {
2277 TRACE("Light information requested but light not defined\n");
2278 return WINED3DERR_INVALIDCALL;
2281 *pLight = lightInfo->OriginalParms;
2282 return WINED3D_OK;
2285 /*****
2286 * Get / Set Light Enable
2287 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2288 *****/
2289 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2291 struct wined3d_light_info *lightInfo = NULL;
2292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2293 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2294 struct list *e;
2295 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2297 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2299 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2300 if(lightInfo->OriginalIndex == Index) break;
2301 lightInfo = NULL;
2303 TRACE("Found light: %p\n", lightInfo);
2305 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2306 if (lightInfo == NULL) {
2308 TRACE("Light enabled requested but light not defined, so defining one!\n");
2309 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2311 /* Search for it again! Should be fairly quick as near head of list */
2312 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2314 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2315 if(lightInfo->OriginalIndex == Index) break;
2316 lightInfo = NULL;
2318 if (lightInfo == NULL) {
2319 FIXME("Adding default lights has failed dismally\n");
2320 return WINED3DERR_INVALIDCALL;
2324 if(!Enable) {
2325 if(lightInfo->glIndex != -1) {
2326 if(!This->isRecordingState) {
2327 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2330 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2331 lightInfo->glIndex = -1;
2332 } else {
2333 TRACE("Light already disabled, nothing to do\n");
2335 lightInfo->enabled = FALSE;
2336 } else {
2337 lightInfo->enabled = TRUE;
2338 if (lightInfo->glIndex != -1) {
2339 /* nop */
2340 TRACE("Nothing to do as light was enabled\n");
2341 } else {
2342 int i;
2343 /* Find a free gl light */
2344 for(i = 0; i < This->maxConcurrentLights; i++) {
2345 if(This->updateStateBlock->activeLights[i] == NULL) {
2346 This->updateStateBlock->activeLights[i] = lightInfo;
2347 lightInfo->glIndex = i;
2348 break;
2351 if(lightInfo->glIndex == -1) {
2352 /* Our tests show that Windows returns D3D_OK in this situation, even with
2353 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2354 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2355 * as well for those lights.
2357 * TODO: Test how this affects rendering
2359 WARN("Too many concurrently active lights\n");
2360 return WINED3D_OK;
2363 /* i == lightInfo->glIndex */
2364 if(!This->isRecordingState) {
2365 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2370 return WINED3D_OK;
2373 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2375 struct wined3d_light_info *lightInfo = NULL;
2376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2377 struct list *e;
2378 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2379 TRACE("(%p) : for idx(%d)\n", This, Index);
2381 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2383 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2384 if(lightInfo->OriginalIndex == Index) break;
2385 lightInfo = NULL;
2388 if (lightInfo == NULL) {
2389 TRACE("Light enabled state requested but light not defined\n");
2390 return WINED3DERR_INVALIDCALL;
2392 /* true is 128 according to SetLightEnable */
2393 *pEnable = lightInfo->enabled ? 128 : 0;
2394 return WINED3D_OK;
2397 /*****
2398 * Get / Set Clip Planes
2399 *****/
2400 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2402 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2404 /* Validate Index */
2405 if (Index >= This->adapter->gl_info.limits.clipplanes)
2407 TRACE("Application has requested clipplane this device doesn't support\n");
2408 return WINED3DERR_INVALIDCALL;
2411 This->updateStateBlock->changed.clipplane |= 1 << Index;
2413 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2414 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2415 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2416 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2417 TRACE("Application is setting old values over, nothing to do\n");
2418 return WINED3D_OK;
2421 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2422 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2423 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2424 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2426 /* Handle recording of state blocks */
2427 if (This->isRecordingState) {
2428 TRACE("Recording... not performing anything\n");
2429 return WINED3D_OK;
2432 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2434 return WINED3D_OK;
2437 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2439 TRACE("(%p) : for idx %d\n", This, Index);
2441 /* Validate Index */
2442 if (Index >= This->adapter->gl_info.limits.clipplanes)
2444 TRACE("Application has requested clipplane this device doesn't support\n");
2445 return WINED3DERR_INVALIDCALL;
2448 pPlane[0] = This->stateBlock->clipplane[Index][0];
2449 pPlane[1] = This->stateBlock->clipplane[Index][1];
2450 pPlane[2] = This->stateBlock->clipplane[Index][2];
2451 pPlane[3] = This->stateBlock->clipplane[Index][3];
2452 return WINED3D_OK;
2455 /*****
2456 * Get / Set Clip Plane Status
2457 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2458 *****/
2459 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2461 FIXME("(%p) : stub\n", This);
2462 if (NULL == pClipStatus) {
2463 return WINED3DERR_INVALIDCALL;
2465 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2466 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2467 return WINED3D_OK;
2470 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2472 FIXME("(%p) : stub\n", This);
2473 if (NULL == pClipStatus) {
2474 return WINED3DERR_INVALIDCALL;
2476 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2477 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2478 return WINED3D_OK;
2481 /*****
2482 * Get / Set Material
2483 *****/
2484 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2487 This->updateStateBlock->changed.material = TRUE;
2488 This->updateStateBlock->material = *pMaterial;
2490 /* Handle recording of state blocks */
2491 if (This->isRecordingState) {
2492 TRACE("Recording... not performing anything\n");
2493 return WINED3D_OK;
2496 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2497 return WINED3D_OK;
2500 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2502 *pMaterial = This->updateStateBlock->material;
2503 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2504 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2505 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2506 pMaterial->Ambient.b, pMaterial->Ambient.a);
2507 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2508 pMaterial->Specular.b, pMaterial->Specular.a);
2509 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2510 pMaterial->Emissive.b, pMaterial->Emissive.a);
2511 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2513 return WINED3D_OK;
2516 /*****
2517 * Get / Set Indices
2518 *****/
2519 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2520 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2523 IWineD3DBuffer *oldIdxs;
2525 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2526 oldIdxs = This->updateStateBlock->pIndexData;
2528 This->updateStateBlock->changed.indices = TRUE;
2529 This->updateStateBlock->pIndexData = pIndexData;
2530 This->updateStateBlock->IndexFmt = fmt;
2532 /* Handle recording of state blocks */
2533 if (This->isRecordingState) {
2534 TRACE("Recording... not performing anything\n");
2535 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2536 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2537 return WINED3D_OK;
2540 if(oldIdxs != pIndexData) {
2541 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2542 if(pIndexData) {
2543 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2544 IWineD3DBuffer_AddRef(pIndexData);
2546 if(oldIdxs) {
2547 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2548 IWineD3DBuffer_Release(oldIdxs);
2552 return WINED3D_OK;
2555 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2559 *ppIndexData = This->stateBlock->pIndexData;
2561 /* up ref count on ppindexdata */
2562 if (*ppIndexData) {
2563 IWineD3DBuffer_AddRef(*ppIndexData);
2564 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2565 }else{
2566 TRACE("(%p) No index data set\n", This);
2568 TRACE("Returning %p\n", *ppIndexData);
2570 return WINED3D_OK;
2573 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2574 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2576 TRACE("(%p)->(%d)\n", This, BaseIndex);
2578 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2579 TRACE("Application is setting the old value over, nothing to do\n");
2580 return WINED3D_OK;
2583 This->updateStateBlock->baseVertexIndex = BaseIndex;
2585 if (This->isRecordingState) {
2586 TRACE("Recording... not performing anything\n");
2587 return WINED3D_OK;
2589 /* The base vertex index affects the stream sources */
2590 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2591 return WINED3D_OK;
2594 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2596 TRACE("(%p) : base_index %p\n", This, base_index);
2598 *base_index = This->stateBlock->baseVertexIndex;
2600 TRACE("Returning %u\n", *base_index);
2602 return WINED3D_OK;
2605 /*****
2606 * Get / Set Viewports
2607 *****/
2608 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2611 TRACE("(%p)\n", This);
2612 This->updateStateBlock->changed.viewport = TRUE;
2613 This->updateStateBlock->viewport = *pViewport;
2615 /* Handle recording of state blocks */
2616 if (This->isRecordingState) {
2617 TRACE("Recording... not performing anything\n");
2618 return WINED3D_OK;
2621 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2622 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2624 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2625 return WINED3D_OK;
2629 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2631 TRACE("(%p)\n", This);
2632 *pViewport = This->stateBlock->viewport;
2633 return WINED3D_OK;
2636 /*****
2637 * Get / Set Render States
2638 * TODO: Verify against dx9 definitions
2639 *****/
2640 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2643 DWORD oldValue = This->stateBlock->renderState[State];
2645 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2647 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2648 This->updateStateBlock->renderState[State] = Value;
2650 /* Handle recording of state blocks */
2651 if (This->isRecordingState) {
2652 TRACE("Recording... not performing anything\n");
2653 return WINED3D_OK;
2656 /* Compared here and not before the assignment to allow proper stateblock recording */
2657 if(Value == oldValue) {
2658 TRACE("Application is setting the old value over, nothing to do\n");
2659 } else {
2660 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2663 return WINED3D_OK;
2666 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2668 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2669 *pValue = This->stateBlock->renderState[State];
2670 return WINED3D_OK;
2673 /*****
2674 * Get / Set Sampler States
2675 * TODO: Verify against dx9 definitions
2676 *****/
2678 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2680 DWORD oldValue;
2682 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2683 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2685 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2686 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2689 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2690 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2691 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2694 * SetSampler is designed to allow for more than the standard up to 8 textures
2695 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2696 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2698 * http://developer.nvidia.com/object/General_FAQ.html#t6
2700 * There are two new settings for GForce
2701 * the sampler one:
2702 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2703 * and the texture one:
2704 * GL_MAX_TEXTURE_COORDS_ARB.
2705 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2706 ******************/
2708 oldValue = This->stateBlock->samplerState[Sampler][Type];
2709 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2710 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2712 /* Handle recording of state blocks */
2713 if (This->isRecordingState) {
2714 TRACE("Recording... not performing anything\n");
2715 return WINED3D_OK;
2718 if(oldValue == Value) {
2719 TRACE("Application is setting the old value over, nothing to do\n");
2720 return WINED3D_OK;
2723 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2725 return WINED3D_OK;
2728 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2731 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2732 This, Sampler, debug_d3dsamplerstate(Type), Type);
2734 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2735 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2738 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2739 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2740 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2742 *Value = This->stateBlock->samplerState[Sampler][Type];
2743 TRACE("(%p) : Returning %#x\n", This, *Value);
2745 return WINED3D_OK;
2748 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2749 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2751 This->updateStateBlock->changed.scissorRect = TRUE;
2752 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2753 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2754 return WINED3D_OK;
2756 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2758 if(This->isRecordingState) {
2759 TRACE("Recording... not performing anything\n");
2760 return WINED3D_OK;
2763 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2765 return WINED3D_OK;
2768 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2771 *pRect = This->updateStateBlock->scissorRect;
2772 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2773 return WINED3D_OK;
2776 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2778 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2780 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2782 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2783 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2785 This->updateStateBlock->vertexDecl = pDecl;
2786 This->updateStateBlock->changed.vertexDecl = TRUE;
2788 if (This->isRecordingState) {
2789 TRACE("Recording... not performing anything\n");
2790 return WINED3D_OK;
2791 } else if(pDecl == oldDecl) {
2792 /* Checked after the assignment to allow proper stateblock recording */
2793 TRACE("Application is setting the old declaration over, nothing to do\n");
2794 return WINED3D_OK;
2797 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2798 return WINED3D_OK;
2801 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2804 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2806 *ppDecl = This->stateBlock->vertexDecl;
2807 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2808 return WINED3D_OK;
2811 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2813 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2815 This->updateStateBlock->vertexShader = pShader;
2816 This->updateStateBlock->changed.vertexShader = TRUE;
2818 if (This->isRecordingState) {
2819 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2820 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2821 TRACE("Recording... not performing anything\n");
2822 return WINED3D_OK;
2823 } else if(oldShader == pShader) {
2824 /* Checked here to allow proper stateblock recording */
2825 TRACE("App is setting the old shader over, nothing to do\n");
2826 return WINED3D_OK;
2829 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2830 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2831 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2833 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2835 return WINED3D_OK;
2838 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2841 if (NULL == ppShader) {
2842 return WINED3DERR_INVALIDCALL;
2844 *ppShader = This->stateBlock->vertexShader;
2845 if( NULL != *ppShader)
2846 IWineD3DVertexShader_AddRef(*ppShader);
2848 TRACE("(%p) : returning %p\n", This, *ppShader);
2849 return WINED3D_OK;
2852 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2853 IWineD3DDevice *iface,
2854 UINT start,
2855 CONST BOOL *srcData,
2856 UINT count) {
2858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2859 unsigned int i, cnt = min(count, MAX_CONST_B - start);
2861 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2862 iface, srcData, start, count);
2864 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
2866 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2867 for (i = 0; i < cnt; i++)
2868 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2870 for (i = start; i < cnt + start; ++i) {
2871 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
2874 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2876 return WINED3D_OK;
2879 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2880 IWineD3DDevice *iface,
2881 UINT start,
2882 BOOL *dstData,
2883 UINT count) {
2885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2886 int cnt = min(count, MAX_CONST_B - start);
2888 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2889 iface, dstData, start, count);
2891 if (dstData == NULL || cnt < 0)
2892 return WINED3DERR_INVALIDCALL;
2894 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2895 return WINED3D_OK;
2898 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2899 IWineD3DDevice *iface,
2900 UINT start,
2901 CONST int *srcData,
2902 UINT count) {
2904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2905 unsigned int i, cnt = min(count, MAX_CONST_I - start);
2907 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2908 iface, srcData, start, count);
2910 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
2912 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2913 for (i = 0; i < cnt; i++)
2914 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2915 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2917 for (i = start; i < cnt + start; ++i) {
2918 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
2921 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2923 return WINED3D_OK;
2926 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2927 IWineD3DDevice *iface,
2928 UINT start,
2929 int *dstData,
2930 UINT count) {
2932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2933 int cnt = min(count, MAX_CONST_I - start);
2935 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2936 iface, dstData, start, count);
2938 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2939 return WINED3DERR_INVALIDCALL;
2941 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
2942 return WINED3D_OK;
2945 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
2946 IWineD3DDevice *iface,
2947 UINT start,
2948 CONST float *srcData,
2949 UINT count) {
2951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2952 UINT i;
2954 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2955 iface, srcData, start, count);
2957 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
2958 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
2959 return WINED3DERR_INVALIDCALL;
2961 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
2962 if(TRACE_ON(d3d)) {
2963 for (i = 0; i < count; i++)
2964 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
2965 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2968 if (!This->isRecordingState)
2970 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
2971 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2974 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
2975 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
2977 return WINED3D_OK;
2980 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
2981 IWineD3DDevice *iface,
2982 UINT start,
2983 float *dstData,
2984 UINT count) {
2986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2987 int cnt = min(count, This->d3d_vshader_constantF - start);
2989 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2990 iface, dstData, start, count);
2992 if (dstData == NULL || cnt < 0)
2993 return WINED3DERR_INVALIDCALL;
2995 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
2996 return WINED3D_OK;
2999 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3000 DWORD i;
3001 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3003 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3007 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3009 DWORD i = This->rev_tex_unit_map[unit];
3010 DWORD j = This->texUnitMap[stage];
3012 This->texUnitMap[stage] = unit;
3013 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3015 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3018 This->rev_tex_unit_map[unit] = stage;
3019 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3021 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3025 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3026 int i;
3028 This->fixed_function_usage_map = 0;
3029 for (i = 0; i < MAX_TEXTURES; ++i) {
3030 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3031 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3032 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3033 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3034 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3035 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3036 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3037 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3039 if (color_op == WINED3DTOP_DISABLE) {
3040 /* Not used, and disable higher stages */
3041 break;
3044 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3045 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3046 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3047 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3048 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3049 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3050 This->fixed_function_usage_map |= (1 << i);
3053 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3054 This->fixed_function_usage_map |= (1 << (i + 1));
3059 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3060 unsigned int i, tex;
3061 WORD ffu_map;
3063 device_update_fixed_function_usage_map(This);
3064 ffu_map = This->fixed_function_usage_map;
3066 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3067 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3068 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3070 if (!(ffu_map & 1)) continue;
3072 if (This->texUnitMap[i] != i) {
3073 device_map_stage(This, i, i);
3074 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3075 markTextureStagesDirty(This, i);
3078 return;
3081 /* Now work out the mapping */
3082 tex = 0;
3083 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3085 if (!(ffu_map & 1)) continue;
3087 if (This->texUnitMap[i] != tex) {
3088 device_map_stage(This, i, tex);
3089 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3090 markTextureStagesDirty(This, i);
3093 ++tex;
3097 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3098 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3099 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3100 unsigned int i;
3102 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3103 if (sampler_type[i] && This->texUnitMap[i] != i)
3105 device_map_stage(This, i, i);
3106 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3107 if (i < MAX_TEXTURES) {
3108 markTextureStagesDirty(This, i);
3114 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3115 const DWORD *vshader_sampler_tokens, DWORD unit)
3117 DWORD current_mapping = This->rev_tex_unit_map[unit];
3119 /* Not currently used */
3120 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3122 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3123 /* Used by a fragment sampler */
3125 if (!pshader_sampler_tokens) {
3126 /* No pixel shader, check fixed function */
3127 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3130 /* Pixel shader, check the shader's sampler map */
3131 return !pshader_sampler_tokens[current_mapping];
3134 /* Used by a vertex sampler */
3135 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3138 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3139 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3140 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3141 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3142 int start = min(MAX_COMBINED_SAMPLERS, This->adapter->gl_info.limits.combined_samplers) - 1;
3143 int i;
3145 if (ps) {
3146 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3148 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3149 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3150 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3153 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3154 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3155 if (vshader_sampler_type[i])
3157 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3159 /* Already mapped somewhere */
3160 continue;
3163 while (start >= 0) {
3164 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3166 device_map_stage(This, vsampler_idx, start);
3167 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3169 --start;
3170 break;
3173 --start;
3179 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3180 BOOL vs = use_vs(This->stateBlock);
3181 BOOL ps = use_ps(This->stateBlock);
3183 * Rules are:
3184 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3185 * that would be really messy and require shader recompilation
3186 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3187 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3189 if (ps) {
3190 device_map_psamplers(This);
3191 } else {
3192 device_map_fixed_function_samplers(This);
3195 if (vs) {
3196 device_map_vsamplers(This, ps);
3200 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3202 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3203 This->updateStateBlock->pixelShader = pShader;
3204 This->updateStateBlock->changed.pixelShader = TRUE;
3206 /* Handle recording of state blocks */
3207 if (This->isRecordingState) {
3208 TRACE("Recording... not performing anything\n");
3211 if (This->isRecordingState) {
3212 TRACE("Recording... not performing anything\n");
3213 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3214 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3215 return WINED3D_OK;
3218 if(pShader == oldShader) {
3219 TRACE("App is setting the old pixel shader over, nothing to do\n");
3220 return WINED3D_OK;
3223 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3224 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3226 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3227 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3229 return WINED3D_OK;
3232 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3235 if (NULL == ppShader) {
3236 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3237 return WINED3DERR_INVALIDCALL;
3240 *ppShader = This->stateBlock->pixelShader;
3241 if (NULL != *ppShader) {
3242 IWineD3DPixelShader_AddRef(*ppShader);
3244 TRACE("(%p) : returning %p\n", This, *ppShader);
3245 return WINED3D_OK;
3248 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3249 IWineD3DDevice *iface,
3250 UINT start,
3251 CONST BOOL *srcData,
3252 UINT count) {
3254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3255 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3257 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3258 iface, srcData, start, count);
3260 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3262 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3263 for (i = 0; i < cnt; i++)
3264 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3266 for (i = start; i < cnt + start; ++i) {
3267 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3270 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3272 return WINED3D_OK;
3275 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3276 IWineD3DDevice *iface,
3277 UINT start,
3278 BOOL *dstData,
3279 UINT count) {
3281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3282 int cnt = min(count, MAX_CONST_B - start);
3284 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3285 iface, dstData, start, count);
3287 if (dstData == NULL || cnt < 0)
3288 return WINED3DERR_INVALIDCALL;
3290 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3291 return WINED3D_OK;
3294 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3295 IWineD3DDevice *iface,
3296 UINT start,
3297 CONST int *srcData,
3298 UINT count) {
3300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3301 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3303 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3304 iface, srcData, start, count);
3306 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3308 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3309 for (i = 0; i < cnt; i++)
3310 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3311 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3313 for (i = start; i < cnt + start; ++i) {
3314 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3317 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3319 return WINED3D_OK;
3322 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3323 IWineD3DDevice *iface,
3324 UINT start,
3325 int *dstData,
3326 UINT count) {
3328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3329 int cnt = min(count, MAX_CONST_I - start);
3331 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3332 iface, dstData, start, count);
3334 if (dstData == NULL || cnt < 0)
3335 return WINED3DERR_INVALIDCALL;
3337 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3338 return WINED3D_OK;
3341 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3342 IWineD3DDevice *iface,
3343 UINT start,
3344 CONST float *srcData,
3345 UINT count) {
3347 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3348 UINT i;
3350 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3351 iface, srcData, start, count);
3353 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3354 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3355 return WINED3DERR_INVALIDCALL;
3357 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3358 if(TRACE_ON(d3d)) {
3359 for (i = 0; i < count; i++)
3360 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3361 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3364 if (!This->isRecordingState)
3366 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3367 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3370 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3371 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3373 return WINED3D_OK;
3376 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3377 IWineD3DDevice *iface,
3378 UINT start,
3379 float *dstData,
3380 UINT count) {
3382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3383 int cnt = min(count, This->d3d_pshader_constantF - start);
3385 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3386 iface, dstData, start, count);
3388 if (dstData == NULL || cnt < 0)
3389 return WINED3DERR_INVALIDCALL;
3391 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3392 return WINED3D_OK;
3395 /* Context activation is done by the caller. */
3396 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3397 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3398 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3399 DWORD DestFVF)
3401 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3402 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3403 unsigned int i;
3404 WINED3DVIEWPORT vp;
3405 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3406 BOOL doClip;
3407 DWORD numTextures;
3409 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3411 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3414 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3416 ERR("Source has no position mask\n");
3417 return WINED3DERR_INVALIDCALL;
3420 /* We might access VBOs from this code, so hold the lock */
3421 ENTER_GL();
3423 if (dest->resource.allocatedMemory == NULL) {
3424 buffer_get_sysmem(dest);
3427 /* Get a pointer into the destination vbo(create one if none exists) and
3428 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3430 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3432 dest->flags |= WINED3D_BUFFER_CREATEBO;
3433 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3436 if (dest->buffer_object)
3438 unsigned char extrabytes = 0;
3439 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3440 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3441 * this may write 4 extra bytes beyond the area that should be written
3443 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3444 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3445 if(!dest_conv_addr) {
3446 ERR("Out of memory\n");
3447 /* Continue without storing converted vertices */
3449 dest_conv = dest_conv_addr;
3452 /* Should I clip?
3453 * a) WINED3DRS_CLIPPING is enabled
3454 * b) WINED3DVOP_CLIP is passed
3456 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3457 static BOOL warned = FALSE;
3459 * The clipping code is not quite correct. Some things need
3460 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3461 * so disable clipping for now.
3462 * (The graphics in Half-Life are broken, and my processvertices
3463 * test crashes with IDirect3DDevice3)
3464 doClip = TRUE;
3466 doClip = FALSE;
3467 if(!warned) {
3468 warned = TRUE;
3469 FIXME("Clipping is broken and disabled for now\n");
3471 } else doClip = FALSE;
3472 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3474 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3475 WINED3DTS_VIEW,
3476 &view_mat);
3477 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3478 WINED3DTS_PROJECTION,
3479 &proj_mat);
3480 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3481 WINED3DTS_WORLDMATRIX(0),
3482 &world_mat);
3484 TRACE("View mat:\n");
3485 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);
3486 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);
3487 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);
3488 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);
3490 TRACE("Proj mat:\n");
3491 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);
3492 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);
3493 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);
3494 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);
3496 TRACE("World mat:\n");
3497 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);
3498 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);
3499 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);
3500 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);
3502 /* Get the viewport */
3503 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3504 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3505 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3507 multiply_matrix(&mat,&view_mat,&world_mat);
3508 multiply_matrix(&mat,&proj_mat,&mat);
3510 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3512 for (i = 0; i < dwCount; i+= 1) {
3513 unsigned int tex_index;
3515 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3516 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3517 /* The position first */
3518 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3519 const float *p = (const float *)(element->data + i * element->stride);
3520 float x, y, z, rhw;
3521 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3523 /* Multiplication with world, view and projection matrix */
3524 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);
3525 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);
3526 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);
3527 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);
3529 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3531 /* WARNING: The following things are taken from d3d7 and were not yet checked
3532 * against d3d8 or d3d9!
3535 /* Clipping conditions: From msdn
3537 * A vertex is clipped if it does not match the following requirements
3538 * -rhw < x <= rhw
3539 * -rhw < y <= rhw
3540 * 0 < z <= rhw
3541 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3543 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3544 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3548 if( !doClip ||
3549 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3550 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3551 ( rhw > eps ) ) ) {
3553 /* "Normal" viewport transformation (not clipped)
3554 * 1) The values are divided by rhw
3555 * 2) The y axis is negative, so multiply it with -1
3556 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3557 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3558 * 4) Multiply x with Width/2 and add Width/2
3559 * 5) The same for the height
3560 * 6) Add the viewpoint X and Y to the 2D coordinates and
3561 * The minimum Z value to z
3562 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3564 * Well, basically it's simply a linear transformation into viewport
3565 * coordinates
3568 x /= rhw;
3569 y /= rhw;
3570 z /= rhw;
3572 y *= -1;
3574 x *= vp.Width / 2;
3575 y *= vp.Height / 2;
3576 z *= vp.MaxZ - vp.MinZ;
3578 x += vp.Width / 2 + vp.X;
3579 y += vp.Height / 2 + vp.Y;
3580 z += vp.MinZ;
3582 rhw = 1 / rhw;
3583 } else {
3584 /* That vertex got clipped
3585 * Contrary to OpenGL it is not dropped completely, it just
3586 * undergoes a different calculation.
3588 TRACE("Vertex got clipped\n");
3589 x += rhw;
3590 y += rhw;
3592 x /= 2;
3593 y /= 2;
3595 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3596 * outside of the main vertex buffer memory. That needs some more
3597 * investigation...
3601 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3604 ( (float *) dest_ptr)[0] = x;
3605 ( (float *) dest_ptr)[1] = y;
3606 ( (float *) dest_ptr)[2] = z;
3607 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3609 dest_ptr += 3 * sizeof(float);
3611 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3612 dest_ptr += sizeof(float);
3615 if(dest_conv) {
3616 float w = 1 / rhw;
3617 ( (float *) dest_conv)[0] = x * w;
3618 ( (float *) dest_conv)[1] = y * w;
3619 ( (float *) dest_conv)[2] = z * w;
3620 ( (float *) dest_conv)[3] = w;
3622 dest_conv += 3 * sizeof(float);
3624 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3625 dest_conv += sizeof(float);
3629 if (DestFVF & WINED3DFVF_PSIZE) {
3630 dest_ptr += sizeof(DWORD);
3631 if(dest_conv) dest_conv += sizeof(DWORD);
3633 if (DestFVF & WINED3DFVF_NORMAL) {
3634 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3635 const float *normal = (const float *)(element->data + i * element->stride);
3636 /* AFAIK this should go into the lighting information */
3637 FIXME("Didn't expect the destination to have a normal\n");
3638 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3639 if(dest_conv) {
3640 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3644 if (DestFVF & WINED3DFVF_DIFFUSE) {
3645 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3646 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3647 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3649 static BOOL warned = FALSE;
3651 if(!warned) {
3652 ERR("No diffuse color in source, but destination has one\n");
3653 warned = TRUE;
3656 *( (DWORD *) dest_ptr) = 0xffffffff;
3657 dest_ptr += sizeof(DWORD);
3659 if(dest_conv) {
3660 *( (DWORD *) dest_conv) = 0xffffffff;
3661 dest_conv += sizeof(DWORD);
3664 else {
3665 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3666 if(dest_conv) {
3667 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3668 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3669 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3670 dest_conv += sizeof(DWORD);
3675 if (DestFVF & WINED3DFVF_SPECULAR)
3677 /* What's the color value in the feedback buffer? */
3678 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3679 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3680 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3682 static BOOL warned = FALSE;
3684 if(!warned) {
3685 ERR("No specular color in source, but destination has one\n");
3686 warned = TRUE;
3689 *( (DWORD *) dest_ptr) = 0xFF000000;
3690 dest_ptr += sizeof(DWORD);
3692 if(dest_conv) {
3693 *( (DWORD *) dest_conv) = 0xFF000000;
3694 dest_conv += sizeof(DWORD);
3697 else {
3698 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3699 if(dest_conv) {
3700 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3701 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3702 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3703 dest_conv += sizeof(DWORD);
3708 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3709 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3710 const float *tex_coord = (const float *)(element->data + i * element->stride);
3711 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3713 ERR("No source texture, but destination requests one\n");
3714 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3715 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3717 else {
3718 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3719 if(dest_conv) {
3720 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3726 if(dest_conv) {
3727 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3728 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3729 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3730 dwCount * get_flexible_vertex_size(DestFVF),
3731 dest_conv_addr));
3732 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3733 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3736 LEAVE_GL();
3738 return WINED3D_OK;
3740 #undef copy_and_next
3742 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3743 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3744 DWORD DestFVF)
3746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3747 struct wined3d_stream_info stream_info;
3748 struct wined3d_context *context;
3749 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3750 HRESULT hr;
3752 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3754 if(pVertexDecl) {
3755 ERR("Output vertex declaration not implemented yet\n");
3758 /* Need any context to write to the vbo. */
3759 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
3761 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3762 * control the streamIsUP flag, thus restore it afterwards.
3764 This->stateBlock->streamIsUP = FALSE;
3765 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3766 This->stateBlock->streamIsUP = streamWasUP;
3768 if(vbo || SrcStartIndex) {
3769 unsigned int i;
3770 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3771 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3773 * Also get the start index in, but only loop over all elements if there's something to add at all.
3775 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3777 struct wined3d_stream_info_element *e;
3779 if (!(stream_info.use_map & (1 << i))) continue;
3781 e = &stream_info.elements[i];
3782 if (e->buffer_object)
3784 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3785 e->buffer_object = 0;
3786 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3787 ENTER_GL();
3788 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3789 vb->buffer_object = 0;
3790 LEAVE_GL();
3792 if (e->data) e->data += e->stride * SrcStartIndex;
3796 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3797 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3799 context_release(context);
3801 return hr;
3804 /*****
3805 * Get / Set Texture Stage States
3806 * TODO: Verify against dx9 definitions
3807 *****/
3808 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3810 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3812 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3814 if (Stage >= MAX_TEXTURES) {
3815 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
3816 return WINED3D_OK;
3819 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3820 This->updateStateBlock->textureState[Stage][Type] = Value;
3822 if (This->isRecordingState) {
3823 TRACE("Recording... not performing anything\n");
3824 return WINED3D_OK;
3827 /* Checked after the assignments to allow proper stateblock recording */
3828 if(oldValue == Value) {
3829 TRACE("App is setting the old value over, nothing to do\n");
3830 return WINED3D_OK;
3833 if(Stage > This->stateBlock->lowest_disabled_stage &&
3834 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3835 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3836 * Changes in other states are important on disabled stages too
3838 return WINED3D_OK;
3841 if(Type == WINED3DTSS_COLOROP) {
3842 unsigned int i;
3844 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3845 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3846 * they have to be disabled
3848 * The current stage is dirtified below.
3850 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3851 TRACE("Additionally dirtifying stage %u\n", i);
3852 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3854 This->stateBlock->lowest_disabled_stage = Stage;
3855 TRACE("New lowest disabled: %u\n", Stage);
3856 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3857 /* Previously disabled stage enabled. Stages above it may need enabling
3858 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3859 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3861 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3864 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
3866 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3867 break;
3869 TRACE("Additionally dirtifying stage %u due to enable\n", i);
3870 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3872 This->stateBlock->lowest_disabled_stage = i;
3873 TRACE("New lowest disabled: %u\n", i);
3877 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3879 return WINED3D_OK;
3882 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3884 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3885 *pValue = This->updateStateBlock->textureState[Stage][Type];
3886 return WINED3D_OK;
3889 /*****
3890 * Get / Set Texture
3891 *****/
3892 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
3893 DWORD stage, IWineD3DBaseTexture *texture)
3895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3896 IWineD3DBaseTexture *prev;
3898 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
3900 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
3901 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3903 /* Windows accepts overflowing this array... we do not. */
3904 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
3906 WARN("Ignoring invalid stage %u.\n", stage);
3907 return WINED3D_OK;
3910 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
3911 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
3913 WARN("Rejecting attempt to set scratch texture.\n");
3914 return WINED3DERR_INVALIDCALL;
3917 This->updateStateBlock->changed.textures |= 1 << stage;
3919 prev = This->updateStateBlock->textures[stage];
3920 TRACE("Previous texture %p.\n", prev);
3922 if (texture == prev)
3924 TRACE("App is setting the same texture again, nothing to do.\n");
3925 return WINED3D_OK;
3928 TRACE("Setting new texture to %p.\n", texture);
3929 This->updateStateBlock->textures[stage] = texture;
3931 if (This->isRecordingState)
3933 TRACE("Recording... not performing anything\n");
3935 if (texture) IWineD3DBaseTexture_AddRef(texture);
3936 if (prev) IWineD3DBaseTexture_Release(prev);
3938 return WINED3D_OK;
3941 if (texture)
3943 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
3944 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
3945 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
3947 IWineD3DBaseTexture_AddRef(texture);
3949 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
3951 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3954 if (!prev && stage < MAX_TEXTURES)
3956 /* The source arguments for color and alpha ops have different
3957 * meanings when a NULL texture is bound, so the COLOROP and
3958 * ALPHAOP have to be dirtified. */
3959 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
3960 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
3963 if (bind_count == 1) t->baseTexture.sampler = stage;
3966 if (prev)
3968 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
3969 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
3971 IWineD3DBaseTexture_Release(prev);
3973 if (!texture && stage < MAX_TEXTURES)
3975 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
3976 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
3979 if (bind_count && t->baseTexture.sampler == stage)
3981 unsigned int i;
3983 /* Search for other stages the texture is bound to. Shouldn't
3984 * happen if applications bind textures to a single stage only. */
3985 TRACE("Searching for other stages the texture is bound to.\n");
3986 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
3988 if (This->updateStateBlock->textures[i] == prev)
3990 TRACE("Texture is also bound to stage %u.\n", i);
3991 t->baseTexture.sampler = i;
3992 break;
3998 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4000 return WINED3D_OK;
4003 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4006 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4008 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4009 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4012 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4013 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4014 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4017 *ppTexture=This->stateBlock->textures[Stage];
4018 if (*ppTexture)
4019 IWineD3DBaseTexture_AddRef(*ppTexture);
4021 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4023 return WINED3D_OK;
4026 /*****
4027 * Get Back Buffer
4028 *****/
4029 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4030 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4032 IWineD3DSwapChain *swapchain;
4033 HRESULT hr;
4035 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4036 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4038 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4039 if (FAILED(hr))
4041 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4042 return hr;
4045 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4046 IWineD3DSwapChain_Release(swapchain);
4047 if (FAILED(hr))
4049 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4050 return hr;
4053 return WINED3D_OK;
4056 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4058 WARN("(%p) : stub, calling idirect3d for now\n", This);
4059 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4062 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4064 IWineD3DSwapChain *swapChain;
4065 HRESULT hr;
4067 if(iSwapChain > 0) {
4068 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4069 if (hr == WINED3D_OK) {
4070 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4071 IWineD3DSwapChain_Release(swapChain);
4072 } else {
4073 FIXME("(%p) Error getting display mode\n", This);
4075 } else {
4076 /* Don't read the real display mode,
4077 but return the stored mode instead. X11 can't change the color
4078 depth, and some apps are pretty angry if they SetDisplayMode from
4079 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4081 Also don't relay to the swapchain because with ddraw it's possible
4082 that there isn't a swapchain at all */
4083 pMode->Width = This->ddraw_width;
4084 pMode->Height = This->ddraw_height;
4085 pMode->Format = This->ddraw_format;
4086 pMode->RefreshRate = 0;
4087 hr = WINED3D_OK;
4090 return hr;
4093 /*****
4094 * Stateblock related functions
4095 *****/
4097 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4098 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4099 IWineD3DStateBlock *stateblock;
4100 HRESULT hr;
4102 TRACE("(%p)\n", This);
4104 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4106 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4107 if (FAILED(hr)) return hr;
4109 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4110 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4111 This->isRecordingState = TRUE;
4113 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4115 return WINED3D_OK;
4118 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4120 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4122 if (!This->isRecordingState) {
4123 WARN("(%p) not recording! returning error\n", This);
4124 *ppStateBlock = NULL;
4125 return WINED3DERR_INVALIDCALL;
4128 stateblock_init_contained_states(object);
4130 *ppStateBlock = (IWineD3DStateBlock*) object;
4131 This->isRecordingState = FALSE;
4132 This->updateStateBlock = This->stateBlock;
4133 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4134 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4135 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4136 return WINED3D_OK;
4139 /*****
4140 * Scene related functions
4141 *****/
4142 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4143 /* At the moment we have no need for any functionality at the beginning
4144 of a scene */
4145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4146 TRACE("(%p)\n", This);
4148 if(This->inScene) {
4149 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4150 return WINED3DERR_INVALIDCALL;
4152 This->inScene = TRUE;
4153 return WINED3D_OK;
4156 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4159 struct wined3d_context *context;
4161 TRACE("(%p)\n", This);
4163 if(!This->inScene) {
4164 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4165 return WINED3DERR_INVALIDCALL;
4168 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4169 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4170 wglFlush();
4171 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4172 * fails. */
4173 context_release(context);
4175 This->inScene = FALSE;
4176 return WINED3D_OK;
4179 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4180 const RECT *pSourceRect, const RECT *pDestRect,
4181 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4183 IWineD3DSwapChain *swapChain = NULL;
4184 int i;
4185 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4187 TRACE("iface %p.\n", iface);
4189 for(i = 0 ; i < swapchains ; i ++) {
4191 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4192 TRACE("presentinng chain %d, %p\n", i, swapChain);
4193 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4194 IWineD3DSwapChain_Release(swapChain);
4197 return WINED3D_OK;
4200 /* Not called from the VTable (internal subroutine) */
4201 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4202 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4203 float Z, DWORD Stencil) {
4204 GLbitfield glMask = 0;
4205 unsigned int i;
4206 WINED3DRECT curRect;
4207 RECT vp_rect;
4208 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4209 UINT drawable_width, drawable_height;
4210 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4211 IWineD3DSwapChainImpl *swapchain = NULL;
4212 struct wined3d_context *context;
4214 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4215 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4216 * for the cleared parts, and the untouched parts.
4218 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4219 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4220 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4221 * checking all this if the dest surface is in the drawable anyway.
4223 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4224 while(1) {
4225 if(vp->X != 0 || vp->Y != 0 ||
4226 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4227 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4228 break;
4230 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4231 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4232 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4233 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4234 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4235 break;
4237 if(Count > 0 && pRects && (
4238 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4239 pRects[0].x2 < target->currentDesc.Width ||
4240 pRects[0].y2 < target->currentDesc.Height)) {
4241 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4242 break;
4244 break;
4248 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4250 target->get_drawable_size(context, &drawable_width, &drawable_height);
4252 ENTER_GL();
4254 /* Only set the values up once, as they are not changing */
4255 if (Flags & WINED3DCLEAR_STENCIL) {
4256 glClearStencil(Stencil);
4257 checkGLcall("glClearStencil");
4258 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4259 glStencilMask(0xFFFFFFFF);
4262 if (Flags & WINED3DCLEAR_ZBUFFER) {
4263 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4264 glDepthMask(GL_TRUE);
4265 glClearDepth(Z);
4266 checkGLcall("glClearDepth");
4267 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4268 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4270 if (vp->X != 0 || vp->Y != 0 ||
4271 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4272 surface_load_ds_location(This->stencilBufferTarget, context, location);
4274 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4275 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4276 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4277 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4278 surface_load_ds_location(This->stencilBufferTarget, context, location);
4280 else if (Count > 0 && pRects && (
4281 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4282 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4283 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4284 surface_load_ds_location(This->stencilBufferTarget, context, location);
4288 if (Flags & WINED3DCLEAR_TARGET) {
4289 TRACE("Clearing screen with glClear to color %x\n", Color);
4290 glClearColor(D3DCOLOR_R(Color),
4291 D3DCOLOR_G(Color),
4292 D3DCOLOR_B(Color),
4293 D3DCOLOR_A(Color));
4294 checkGLcall("glClearColor");
4296 /* Clear ALL colors! */
4297 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4298 glMask = glMask | GL_COLOR_BUFFER_BIT;
4301 vp_rect.left = vp->X;
4302 vp_rect.top = vp->Y;
4303 vp_rect.right = vp->X + vp->Width;
4304 vp_rect.bottom = vp->Y + vp->Height;
4305 if (!(Count > 0 && pRects)) {
4306 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4307 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4309 if (context->render_offscreen)
4311 glScissor(vp_rect.left, vp_rect.top,
4312 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4313 } else {
4314 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4315 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4317 checkGLcall("glScissor");
4318 glClear(glMask);
4319 checkGLcall("glClear");
4320 } else {
4321 /* Now process each rect in turn */
4322 for (i = 0; i < Count; i++) {
4323 /* Note gl uses lower left, width/height */
4324 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4325 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4326 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4328 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4329 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4330 curRect.x1, (target->currentDesc.Height - curRect.y2),
4331 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4333 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4334 * The rectangle is not cleared, no error is returned, but further rectanlges are
4335 * still cleared if they are valid
4337 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4338 TRACE("Rectangle with negative dimensions, ignoring\n");
4339 continue;
4342 if (context->render_offscreen)
4344 glScissor(curRect.x1, curRect.y1,
4345 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4346 } else {
4347 glScissor(curRect.x1, drawable_height - curRect.y2,
4348 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4350 checkGLcall("glScissor");
4352 glClear(glMask);
4353 checkGLcall("glClear");
4357 /* Restore the old values (why..?) */
4358 if (Flags & WINED3DCLEAR_STENCIL) {
4359 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4361 if (Flags & WINED3DCLEAR_TARGET) {
4362 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4363 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4364 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4365 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4366 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4368 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4369 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4371 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4373 if (Flags & WINED3DCLEAR_ZBUFFER) {
4374 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4375 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4376 surface_modify_ds_location(This->stencilBufferTarget, location);
4379 LEAVE_GL();
4381 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
4382 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
4383 wglFlush();
4385 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
4388 context_release(context);
4390 return WINED3D_OK;
4393 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4394 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4396 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4398 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4399 Count, pRects, Flags, Color, Z, Stencil);
4401 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4402 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4403 /* TODO: What about depth stencil buffers without stencil bits? */
4404 return WINED3DERR_INVALIDCALL;
4407 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4410 /*****
4411 * Drawing functions
4412 *****/
4414 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4415 WINED3DPRIMITIVETYPE primitive_type)
4417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4419 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4421 This->updateStateBlock->changed.primitive_type = TRUE;
4422 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4425 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4426 WINED3DPRIMITIVETYPE *primitive_type)
4428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4430 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4432 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4434 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4437 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4441 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4443 if(!This->stateBlock->vertexDecl) {
4444 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4445 return WINED3DERR_INVALIDCALL;
4448 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4449 if(This->stateBlock->streamIsUP) {
4450 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4451 This->stateBlock->streamIsUP = FALSE;
4454 if(This->stateBlock->loadBaseVertexIndex != 0) {
4455 This->stateBlock->loadBaseVertexIndex = 0;
4456 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4458 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4459 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4460 return WINED3D_OK;
4463 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4465 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4466 UINT idxStride = 2;
4467 IWineD3DBuffer *pIB;
4468 GLuint vbo;
4470 pIB = This->stateBlock->pIndexData;
4471 if (!pIB) {
4472 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4473 * without an index buffer set. (The first time at least...)
4474 * D3D8 simply dies, but I doubt it can do much harm to return
4475 * D3DERR_INVALIDCALL there as well. */
4476 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4477 return WINED3DERR_INVALIDCALL;
4480 if(!This->stateBlock->vertexDecl) {
4481 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4482 return WINED3DERR_INVALIDCALL;
4485 if(This->stateBlock->streamIsUP) {
4486 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4487 This->stateBlock->streamIsUP = FALSE;
4489 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4491 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4493 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4494 idxStride = 2;
4495 } else {
4496 idxStride = 4;
4499 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4500 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4501 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4504 drawPrimitive(iface, index_count, startIndex, idxStride,
4505 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4507 return WINED3D_OK;
4510 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4511 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4514 IWineD3DBuffer *vb;
4516 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4517 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4519 if(!This->stateBlock->vertexDecl) {
4520 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4521 return WINED3DERR_INVALIDCALL;
4524 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4525 vb = This->stateBlock->streamSource[0];
4526 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4527 if (vb) IWineD3DBuffer_Release(vb);
4528 This->stateBlock->streamOffset[0] = 0;
4529 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4530 This->stateBlock->streamIsUP = TRUE;
4531 This->stateBlock->loadBaseVertexIndex = 0;
4533 /* TODO: Only mark dirty if drawing from a different UP address */
4534 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4536 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4538 /* MSDN specifies stream zero settings must be set to NULL */
4539 This->stateBlock->streamStride[0] = 0;
4540 This->stateBlock->streamSource[0] = NULL;
4542 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4543 * the new stream sources or use UP drawing again
4545 return WINED3D_OK;
4548 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4549 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4550 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4552 int idxStride;
4553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4554 IWineD3DBuffer *vb;
4555 IWineD3DBuffer *ib;
4557 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4558 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4560 if(!This->stateBlock->vertexDecl) {
4561 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4562 return WINED3DERR_INVALIDCALL;
4565 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4566 idxStride = 2;
4567 } else {
4568 idxStride = 4;
4571 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4572 vb = This->stateBlock->streamSource[0];
4573 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4574 if (vb) IWineD3DBuffer_Release(vb);
4575 This->stateBlock->streamIsUP = TRUE;
4576 This->stateBlock->streamOffset[0] = 0;
4577 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4579 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4580 This->stateBlock->baseVertexIndex = 0;
4581 This->stateBlock->loadBaseVertexIndex = 0;
4582 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4583 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4584 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4586 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4588 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4589 This->stateBlock->streamSource[0] = NULL;
4590 This->stateBlock->streamStride[0] = 0;
4591 ib = This->stateBlock->pIndexData;
4592 if(ib) {
4593 IWineD3DBuffer_Release(ib);
4594 This->stateBlock->pIndexData = NULL;
4596 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4597 * SetStreamSource to specify a vertex buffer
4600 return WINED3D_OK;
4603 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4604 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4608 /* Mark the state dirty until we have nicer tracking
4609 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4610 * that value.
4612 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4613 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4614 This->stateBlock->baseVertexIndex = 0;
4615 This->up_strided = DrawPrimStrideData;
4616 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4617 This->up_strided = NULL;
4618 return WINED3D_OK;
4621 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4622 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4623 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4626 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4628 /* Mark the state dirty until we have nicer tracking
4629 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4630 * that value.
4632 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4633 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4634 This->stateBlock->streamIsUP = TRUE;
4635 This->stateBlock->baseVertexIndex = 0;
4636 This->up_strided = DrawPrimStrideData;
4637 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4638 This->up_strided = NULL;
4639 return WINED3D_OK;
4642 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4643 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4644 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4646 WINED3DLOCKED_BOX src;
4647 WINED3DLOCKED_BOX dst;
4648 HRESULT hr;
4650 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4651 iface, pSourceVolume, pDestinationVolume);
4653 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4654 * dirtification to improve loading performance.
4656 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4657 if(FAILED(hr)) return hr;
4658 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4659 if(FAILED(hr)) {
4660 IWineD3DVolume_UnlockBox(pSourceVolume);
4661 return hr;
4664 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4666 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4667 if(FAILED(hr)) {
4668 IWineD3DVolume_UnlockBox(pSourceVolume);
4669 } else {
4670 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4672 return hr;
4675 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4676 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4678 unsigned int level_count, i;
4679 WINED3DRESOURCETYPE type;
4680 HRESULT hr;
4682 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4684 /* Verify that the source and destination textures are non-NULL. */
4685 if (!src_texture || !dst_texture)
4687 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4688 return WINED3DERR_INVALIDCALL;
4691 if (src_texture == dst_texture)
4693 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4694 return WINED3DERR_INVALIDCALL;
4697 /* Verify that the source and destination textures are the same type. */
4698 type = IWineD3DBaseTexture_GetType(src_texture);
4699 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4701 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4702 return WINED3DERR_INVALIDCALL;
4705 /* Check that both textures have the identical numbers of levels. */
4706 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4707 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4709 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4710 return WINED3DERR_INVALIDCALL;
4713 /* Make sure that the destination texture is loaded. */
4714 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4716 /* Update every surface level of the texture. */
4717 switch (type)
4719 case WINED3DRTYPE_TEXTURE:
4721 IWineD3DSurface *src_surface;
4722 IWineD3DSurface *dst_surface;
4724 for (i = 0; i < level_count; ++i)
4726 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4727 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4728 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4729 IWineD3DSurface_Release(dst_surface);
4730 IWineD3DSurface_Release(src_surface);
4731 if (FAILED(hr))
4733 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4734 return hr;
4737 break;
4740 case WINED3DRTYPE_CUBETEXTURE:
4742 IWineD3DSurface *src_surface;
4743 IWineD3DSurface *dst_surface;
4744 WINED3DCUBEMAP_FACES face;
4746 for (i = 0; i < level_count; ++i)
4748 /* Update each cube face. */
4749 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4751 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4752 face, i, &src_surface);
4753 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4754 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4755 face, i, &dst_surface);
4756 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4757 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4758 IWineD3DSurface_Release(dst_surface);
4759 IWineD3DSurface_Release(src_surface);
4760 if (FAILED(hr))
4762 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4763 return hr;
4767 break;
4770 case WINED3DRTYPE_VOLUMETEXTURE:
4772 IWineD3DVolume *src_volume;
4773 IWineD3DVolume *dst_volume;
4775 for (i = 0; i < level_count; ++i)
4777 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4778 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4779 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4780 IWineD3DVolume_Release(dst_volume);
4781 IWineD3DVolume_Release(src_volume);
4782 if (FAILED(hr))
4784 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4785 return hr;
4788 break;
4791 default:
4792 FIXME("Unsupported texture type %#x.\n", type);
4793 return WINED3DERR_INVALIDCALL;
4796 return WINED3D_OK;
4799 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4800 IWineD3DSwapChain *swapChain;
4801 HRESULT hr;
4802 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4803 if(hr == WINED3D_OK) {
4804 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4805 IWineD3DSwapChain_Release(swapChain);
4807 return hr;
4810 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4812 IWineD3DBaseTextureImpl *texture;
4813 DWORD i;
4815 TRACE("(%p) : %p\n", This, pNumPasses);
4817 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4818 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
4819 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4820 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4822 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
4823 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4824 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4827 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
4828 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
4830 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
4831 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4832 return E_FAIL;
4834 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
4835 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4836 return E_FAIL;
4838 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
4839 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
4840 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4841 return E_FAIL;
4845 /* return a sensible default */
4846 *pNumPasses = 1;
4848 TRACE("returning D3D_OK\n");
4849 return WINED3D_OK;
4852 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
4854 int i;
4856 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4858 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
4859 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
4860 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
4862 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
4867 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4869 int j;
4870 UINT NewSize;
4871 PALETTEENTRY **palettes;
4873 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4875 if (PaletteNumber >= MAX_PALETTES) {
4876 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4877 return WINED3DERR_INVALIDCALL;
4880 if (PaletteNumber >= This->NumberOfPalettes) {
4881 NewSize = This->NumberOfPalettes;
4882 do {
4883 NewSize *= 2;
4884 } while(PaletteNumber >= NewSize);
4885 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
4886 if (!palettes) {
4887 ERR("Out of memory!\n");
4888 return E_OUTOFMEMORY;
4890 This->palettes = palettes;
4891 This->NumberOfPalettes = NewSize;
4894 if (!This->palettes[PaletteNumber]) {
4895 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
4896 if (!This->palettes[PaletteNumber]) {
4897 ERR("Out of memory!\n");
4898 return E_OUTOFMEMORY;
4902 for (j = 0; j < 256; ++j) {
4903 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4904 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4905 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4906 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4908 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
4909 TRACE("(%p) : returning\n", This);
4910 return WINED3D_OK;
4913 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4915 int j;
4916 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4917 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
4918 /* What happens in such situation isn't documented; Native seems to silently abort
4919 on such conditions. Return Invalid Call. */
4920 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
4921 return WINED3DERR_INVALIDCALL;
4923 for (j = 0; j < 256; ++j) {
4924 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4925 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4926 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4927 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4929 TRACE("(%p) : returning\n", This);
4930 return WINED3D_OK;
4933 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4935 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4936 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
4937 (tested with reference rasterizer). Return Invalid Call. */
4938 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
4939 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
4940 return WINED3DERR_INVALIDCALL;
4942 /*TODO: stateblocks */
4943 if (This->currentPalette != PaletteNumber) {
4944 This->currentPalette = PaletteNumber;
4945 dirtify_p8_texture_samplers(This);
4947 TRACE("(%p) : returning\n", This);
4948 return WINED3D_OK;
4951 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4953 if (PaletteNumber == NULL) {
4954 WARN("(%p) : returning Invalid Call\n", This);
4955 return WINED3DERR_INVALIDCALL;
4957 /*TODO: stateblocks */
4958 *PaletteNumber = This->currentPalette;
4959 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4960 return WINED3D_OK;
4963 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4965 static BOOL warned;
4966 if (!warned)
4968 FIXME("(%p) : stub\n", This);
4969 warned = TRUE;
4972 This->softwareVertexProcessing = bSoftware;
4973 return WINED3D_OK;
4977 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4979 static BOOL warned;
4980 if (!warned)
4982 FIXME("(%p) : stub\n", This);
4983 warned = TRUE;
4985 return This->softwareVertexProcessing;
4988 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
4989 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
4991 IWineD3DSwapChain *swapchain;
4992 HRESULT hr;
4994 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
4995 iface, swapchain_idx, raster_status);
4997 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4998 if (FAILED(hr))
5000 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5001 return hr;
5004 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5005 IWineD3DSwapChain_Release(swapchain);
5006 if (FAILED(hr))
5008 WARN("Failed to get raster status, hr %#x.\n", hr);
5009 return hr;
5012 return WINED3D_OK;
5015 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5017 static BOOL warned;
5018 if(nSegments != 0.0f) {
5019 if (!warned)
5021 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5022 warned = TRUE;
5025 return WINED3D_OK;
5028 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5030 static BOOL warned;
5031 if (!warned)
5033 FIXME("iface %p stub!\n", iface);
5034 warned = TRUE;
5036 return 0.0f;
5039 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5041 /** TODO: remove casts to IWineD3DSurfaceImpl
5042 * NOTE: move code to surface to accomplish this
5043 ****************************************/
5044 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5045 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5046 int srcWidth, srcHeight;
5047 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5048 WINED3DFORMAT destFormat, srcFormat;
5049 UINT destSize;
5050 int srcLeft, destLeft, destTop;
5051 WINED3DPOOL srcPool, destPool;
5052 int offset = 0;
5053 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5054 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5055 GLenum dummy;
5056 DWORD sampler;
5057 int bpp;
5058 CONVERT_TYPES convert = NO_CONVERSION;
5059 struct wined3d_context *context;
5061 WINED3DSURFACE_DESC winedesc;
5063 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5065 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5066 srcSurfaceWidth = winedesc.width;
5067 srcSurfaceHeight = winedesc.height;
5068 srcPool = winedesc.pool;
5069 srcFormat = winedesc.format;
5071 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5072 destSurfaceWidth = winedesc.width;
5073 destSurfaceHeight = winedesc.height;
5074 destPool = winedesc.pool;
5075 destFormat = winedesc.format;
5076 destSize = winedesc.size;
5078 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5079 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5080 return WINED3DERR_INVALIDCALL;
5083 /* This call loads the opengl surface directly, instead of copying the surface to the
5084 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5085 * copy in sysmem and use regular surface loading.
5087 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5088 if(convert != NO_CONVERSION) {
5089 return IWineD3DSurface_BltFast(pDestinationSurface,
5090 pDestPoint ? pDestPoint->x : 0,
5091 pDestPoint ? pDestPoint->y : 0,
5092 pSourceSurface, pSourceRect, 0);
5095 if (destFormat == WINED3DFMT_UNKNOWN) {
5096 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5097 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5099 /* Get the update surface description */
5100 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5103 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5105 ENTER_GL();
5106 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5107 checkGLcall("glActiveTextureARB");
5108 LEAVE_GL();
5110 /* Make sure the surface is loaded and up to date */
5111 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5112 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5114 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5115 dst_format_desc = dst_impl->resource.format_desc;
5117 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5118 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5119 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5120 srcLeft = pSourceRect ? pSourceRect->left : 0;
5121 destLeft = pDestPoint ? pDestPoint->x : 0;
5122 destTop = pDestPoint ? pDestPoint->y : 0;
5125 /* This function doesn't support compressed textures
5126 the pitch is just bytesPerPixel * width */
5127 if(srcWidth != srcSurfaceWidth || srcLeft ){
5128 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5129 offset += srcLeft * src_format_desc->byte_count;
5130 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5132 /* TODO DXT formats */
5134 if(pSourceRect != NULL && pSourceRect->top != 0){
5135 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5137 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5138 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5139 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5141 /* Sanity check */
5142 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5144 /* need to lock the surface to get the data */
5145 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5148 ENTER_GL();
5150 /* TODO: Cube and volume support */
5151 if(rowoffset != 0){
5152 /* not a whole row so we have to do it a line at a time */
5153 int j;
5155 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5156 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5158 for (j = destTop; j < (srcHeight + destTop); ++j)
5160 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5161 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5162 data += rowoffset;
5165 } else { /* Full width, so just write out the whole texture */
5166 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5168 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5170 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5172 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5173 FIXME("Updating part of a compressed texture is not supported.\n");
5175 if (destFormat != srcFormat)
5177 FIXME("Updating mixed format compressed textures is not supported.\n");
5179 else
5181 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5182 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5185 else
5187 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5188 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5191 checkGLcall("glTexSubImage2D");
5193 LEAVE_GL();
5194 context_release(context);
5196 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5197 sampler = This->rev_tex_unit_map[0];
5198 if (sampler != WINED3D_UNMAPPED_STAGE)
5200 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5203 return WINED3D_OK;
5206 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5208 struct WineD3DRectPatch *patch;
5209 GLenum old_primitive_type;
5210 unsigned int i;
5211 struct list *e;
5212 BOOL found;
5213 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5215 if(!(Handle || pRectPatchInfo)) {
5216 /* TODO: Write a test for the return value, thus the FIXME */
5217 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5218 return WINED3DERR_INVALIDCALL;
5221 if(Handle) {
5222 i = PATCHMAP_HASHFUNC(Handle);
5223 found = FALSE;
5224 LIST_FOR_EACH(e, &This->patches[i]) {
5225 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5226 if(patch->Handle == Handle) {
5227 found = TRUE;
5228 break;
5232 if(!found) {
5233 TRACE("Patch does not exist. Creating a new one\n");
5234 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5235 patch->Handle = Handle;
5236 list_add_head(&This->patches[i], &patch->entry);
5237 } else {
5238 TRACE("Found existing patch %p\n", patch);
5240 } else {
5241 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5242 * attributes we have to tesselate, read back, and draw. This needs a patch
5243 * management structure instance. Create one.
5245 * A possible improvement is to check if a vertex shader is used, and if not directly
5246 * draw the patch.
5248 FIXME("Drawing an uncached patch. This is slow\n");
5249 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5252 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5253 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5254 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5255 HRESULT hr;
5256 TRACE("Tesselation density or patch info changed, retesselating\n");
5258 if(pRectPatchInfo) {
5259 patch->RectPatchInfo = *pRectPatchInfo;
5261 patch->numSegs[0] = pNumSegs[0];
5262 patch->numSegs[1] = pNumSegs[1];
5263 patch->numSegs[2] = pNumSegs[2];
5264 patch->numSegs[3] = pNumSegs[3];
5266 hr = tesselate_rectpatch(This, patch);
5267 if(FAILED(hr)) {
5268 WARN("Patch tesselation failed\n");
5270 /* Do not release the handle to store the params of the patch */
5271 if(!Handle) {
5272 HeapFree(GetProcessHeap(), 0, patch);
5274 return hr;
5278 This->currentPatch = patch;
5279 old_primitive_type = This->stateBlock->gl_primitive_type;
5280 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5281 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5282 This->stateBlock->gl_primitive_type = old_primitive_type;
5283 This->currentPatch = NULL;
5285 /* Destroy uncached patches */
5286 if(!Handle) {
5287 HeapFree(GetProcessHeap(), 0, patch->mem);
5288 HeapFree(GetProcessHeap(), 0, patch);
5290 return WINED3D_OK;
5293 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5294 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5296 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5297 iface, handle, segment_count, patch_info);
5299 return WINED3D_OK;
5302 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5304 int i;
5305 struct WineD3DRectPatch *patch;
5306 struct list *e;
5307 TRACE("(%p) Handle(%d)\n", This, Handle);
5309 i = PATCHMAP_HASHFUNC(Handle);
5310 LIST_FOR_EACH(e, &This->patches[i]) {
5311 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5312 if(patch->Handle == Handle) {
5313 TRACE("Deleting patch %p\n", patch);
5314 list_remove(&patch->entry);
5315 HeapFree(GetProcessHeap(), 0, patch->mem);
5316 HeapFree(GetProcessHeap(), 0, patch);
5317 return WINED3D_OK;
5321 /* TODO: Write a test for the return value */
5322 FIXME("Attempt to destroy nonexistent patch\n");
5323 return WINED3DERR_INVALIDCALL;
5326 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5327 HRESULT hr;
5328 IWineD3DSwapChain *swapchain;
5330 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5331 if (SUCCEEDED(hr)) {
5332 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5333 return swapchain;
5336 return NULL;
5339 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5340 const WINED3DRECT *rect, const float color[4])
5342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5343 struct wined3d_context *context;
5345 if (!surface_is_offscreen(surface))
5347 TRACE("Surface %p is onscreen\n", surface);
5349 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5350 ENTER_GL();
5351 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5352 context_set_draw_buffer(context, surface_get_gl_buffer(surface));
5354 else
5356 TRACE("Surface %p is offscreen\n", surface);
5358 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5359 ENTER_GL();
5360 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5361 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5362 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5365 if (rect) {
5366 glEnable(GL_SCISSOR_TEST);
5367 if(surface_is_offscreen(surface)) {
5368 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5369 } else {
5370 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5371 rect->x2 - rect->x1, rect->y2 - rect->y1);
5373 checkGLcall("glScissor");
5374 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5375 } else {
5376 glDisable(GL_SCISSOR_TEST);
5378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5380 glDisable(GL_BLEND);
5381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5383 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5384 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5386 glClearColor(color[0], color[1], color[2], color[3]);
5387 glClear(GL_COLOR_BUFFER_BIT);
5388 checkGLcall("glClear");
5390 LEAVE_GL();
5391 context_release(context);
5394 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5395 unsigned int r, g, b, a;
5396 DWORD ret;
5398 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5399 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5400 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5401 return color;
5403 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5405 a = (color & 0xff000000) >> 24;
5406 r = (color & 0x00ff0000) >> 16;
5407 g = (color & 0x0000ff00) >> 8;
5408 b = (color & 0x000000ff) >> 0;
5410 switch(destfmt)
5412 case WINED3DFMT_B5G6R5_UNORM:
5413 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5414 r = (r * 32) / 256;
5415 g = (g * 64) / 256;
5416 b = (b * 32) / 256;
5417 ret = r << 11;
5418 ret |= g << 5;
5419 ret |= b;
5420 TRACE("Returning %08x\n", ret);
5421 return ret;
5423 case WINED3DFMT_B5G5R5X1_UNORM:
5424 case WINED3DFMT_B5G5R5A1_UNORM:
5425 a = (a * 2) / 256;
5426 r = (r * 32) / 256;
5427 g = (g * 32) / 256;
5428 b = (b * 32) / 256;
5429 ret = a << 15;
5430 ret |= r << 10;
5431 ret |= g << 5;
5432 ret |= b << 0;
5433 TRACE("Returning %08x\n", ret);
5434 return ret;
5436 case WINED3DFMT_A8_UNORM:
5437 TRACE("Returning %08x\n", a);
5438 return a;
5440 case WINED3DFMT_B4G4R4X4_UNORM:
5441 case WINED3DFMT_B4G4R4A4_UNORM:
5442 a = (a * 16) / 256;
5443 r = (r * 16) / 256;
5444 g = (g * 16) / 256;
5445 b = (b * 16) / 256;
5446 ret = a << 12;
5447 ret |= r << 8;
5448 ret |= g << 4;
5449 ret |= b << 0;
5450 TRACE("Returning %08x\n", ret);
5451 return ret;
5453 case WINED3DFMT_B2G3R3_UNORM:
5454 r = (r * 8) / 256;
5455 g = (g * 8) / 256;
5456 b = (b * 4) / 256;
5457 ret = r << 5;
5458 ret |= g << 2;
5459 ret |= b << 0;
5460 TRACE("Returning %08x\n", ret);
5461 return ret;
5463 case WINED3DFMT_R8G8B8X8_UNORM:
5464 case WINED3DFMT_R8G8B8A8_UNORM:
5465 ret = a << 24;
5466 ret |= b << 16;
5467 ret |= g << 8;
5468 ret |= r << 0;
5469 TRACE("Returning %08x\n", ret);
5470 return ret;
5472 case WINED3DFMT_B10G10R10A2_UNORM:
5473 a = (a * 4) / 256;
5474 r = (r * 1024) / 256;
5475 g = (g * 1024) / 256;
5476 b = (b * 1024) / 256;
5477 ret = a << 30;
5478 ret |= r << 20;
5479 ret |= g << 10;
5480 ret |= b << 0;
5481 TRACE("Returning %08x\n", ret);
5482 return ret;
5484 case WINED3DFMT_R10G10B10A2_UNORM:
5485 a = (a * 4) / 256;
5486 r = (r * 1024) / 256;
5487 g = (g * 1024) / 256;
5488 b = (b * 1024) / 256;
5489 ret = a << 30;
5490 ret |= b << 20;
5491 ret |= g << 10;
5492 ret |= r << 0;
5493 TRACE("Returning %08x\n", ret);
5494 return ret;
5496 default:
5497 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5498 return 0;
5502 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5503 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5505 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5506 WINEDDBLTFX BltFx;
5508 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5510 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5511 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5512 return WINED3DERR_INVALIDCALL;
5515 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5516 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5517 color_fill_fbo(iface, pSurface, pRect, c);
5518 return WINED3D_OK;
5519 } else {
5520 /* Just forward this to the DirectDraw blitting engine */
5521 memset(&BltFx, 0, sizeof(BltFx));
5522 BltFx.dwSize = sizeof(BltFx);
5523 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5524 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5525 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5529 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5530 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5532 IWineD3DResource *resource;
5533 IWineD3DSurface *surface;
5534 HRESULT hr;
5536 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5537 if (FAILED(hr))
5539 ERR("Failed to get resource, hr %#x\n", hr);
5540 return;
5543 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5545 FIXME("Only supported on surface resources\n");
5546 IWineD3DResource_Release(resource);
5547 return;
5550 surface = (IWineD3DSurface *)resource;
5552 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5554 color_fill_fbo(iface, surface, NULL, color);
5556 else
5558 WINEDDBLTFX BltFx;
5559 WINED3DCOLOR c;
5561 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5563 c = ((DWORD)(color[2] * 255.0f));
5564 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5565 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5566 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5568 /* Just forward this to the DirectDraw blitting engine */
5569 memset(&BltFx, 0, sizeof(BltFx));
5570 BltFx.dwSize = sizeof(BltFx);
5571 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5572 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5573 if (FAILED(hr))
5575 ERR("Blt failed, hr %#x\n", hr);
5579 IWineD3DResource_Release(resource);
5582 /* rendertarget and depth stencil functions */
5583 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5586 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5588 ERR("(%p) : Only %d render targets are supported.\n",
5589 This, This->adapter->gl_info.limits.buffers);
5590 return WINED3DERR_INVALIDCALL;
5593 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5594 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5595 /* Note inc ref on returned surface */
5596 if(*ppRenderTarget != NULL)
5597 IWineD3DSurface_AddRef(*ppRenderTarget);
5598 return WINED3D_OK;
5601 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5602 IWineD3DSurface *Front, IWineD3DSurface *Back)
5604 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5605 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5606 IWineD3DSwapChainImpl *Swapchain;
5607 HRESULT hr;
5609 TRACE("iface %p, front %p, back %p.\n", iface, Front, Back);
5611 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5612 if(hr != WINED3D_OK) {
5613 ERR("Can't get the swapchain\n");
5614 return hr;
5617 /* Make sure to release the swapchain */
5618 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5620 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5621 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5622 return WINED3DERR_INVALIDCALL;
5624 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5625 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5626 return WINED3DERR_INVALIDCALL;
5629 if(Swapchain->frontBuffer != Front) {
5630 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5632 if(Swapchain->frontBuffer)
5634 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5635 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5637 Swapchain->frontBuffer = Front;
5639 if(Swapchain->frontBuffer) {
5640 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5641 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5645 if(Back && !Swapchain->backBuffer) {
5646 /* We need memory for the back buffer array - only one back buffer this way */
5647 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5648 if(!Swapchain->backBuffer) {
5649 ERR("Out of memory\n");
5650 return E_OUTOFMEMORY;
5654 if(Swapchain->backBuffer[0] != Back) {
5655 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5657 /* What to do about the context here in the case of multithreading? Not sure.
5658 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5660 WARN("No active context?\n");
5662 ENTER_GL();
5663 if(!Swapchain->backBuffer[0]) {
5664 /* GL was told to draw to the front buffer at creation,
5665 * undo that
5667 glDrawBuffer(GL_BACK);
5668 checkGLcall("glDrawBuffer(GL_BACK)");
5669 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5670 Swapchain->presentParms.BackBufferCount = 1;
5671 } else if (!Back) {
5672 /* That makes problems - disable for now */
5673 /* glDrawBuffer(GL_FRONT); */
5674 checkGLcall("glDrawBuffer(GL_FRONT)");
5675 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5676 Swapchain->presentParms.BackBufferCount = 0;
5678 LEAVE_GL();
5680 if(Swapchain->backBuffer[0])
5682 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5683 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5685 Swapchain->backBuffer[0] = Back;
5687 if(Swapchain->backBuffer[0]) {
5688 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5689 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
5690 } else {
5691 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5692 Swapchain->backBuffer = NULL;
5697 return WINED3D_OK;
5700 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5702 BYTE buffer[32];
5703 DWORD size = sizeof(buffer);
5704 HKEY hkey = 0;
5705 *ppZStencilSurface = This->stencilBufferTarget;
5706 /* @@ Wine registry key: HKCU\Software\Wine\Direct3D\MystIVStartupHack */
5707 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Direct3D", &hkey)) {
5708 if (!RegQueryValueExA( hkey, "MystIVStartupHack", 0, NULL, buffer, &size)) {
5709 if ( IS_OPTION_TRUE( buffer[0] ) ) {
5710 TRACE("Enabling MystIVStartupHack hack\n");
5711 *ppZStencilSurface = This->auto_depth_stencil_buffer;
5715 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5717 if(*ppZStencilSurface != NULL) {
5718 /* Note inc ref on returned surface */
5719 IWineD3DSurface_AddRef(*ppZStencilSurface);
5720 return WINED3D_OK;
5721 } else {
5722 return WINED3DERR_NOTFOUND;
5726 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5727 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
5729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5730 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5731 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5732 const struct wined3d_gl_info *gl_info;
5733 struct wined3d_context *context;
5734 GLenum gl_filter;
5735 POINT offset = {0, 0};
5737 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5738 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5739 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5740 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5742 switch (filter) {
5743 case WINED3DTEXF_LINEAR:
5744 gl_filter = GL_LINEAR;
5745 break;
5747 default:
5748 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5749 case WINED3DTEXF_NONE:
5750 case WINED3DTEXF_POINT:
5751 gl_filter = GL_NEAREST;
5752 break;
5755 /* Attach src surface to src fbo */
5756 src_swapchain = get_swapchain(src_surface);
5757 dst_swapchain = get_swapchain(dst_surface);
5759 if (src_swapchain) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
5760 else if (dst_swapchain) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5761 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5763 gl_info = context->gl_info;
5765 if (!surface_is_offscreen(src_surface))
5767 GLenum buffer = surface_get_gl_buffer(src_surface);
5769 TRACE("Source surface %p is onscreen\n", src_surface);
5770 /* Make sure the drawable is up to date. In the offscreen case
5771 * attach_surface_fbo() implicitly takes care of this. */
5772 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
5774 if(buffer == GL_FRONT) {
5775 RECT windowsize;
5776 UINT h;
5777 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
5778 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
5779 h = windowsize.bottom - windowsize.top;
5780 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
5781 src_rect->y1 = offset.y + h - src_rect->y1;
5782 src_rect->y2 = offset.y + h - src_rect->y2;
5783 } else {
5784 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5785 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5788 ENTER_GL();
5789 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5790 glReadBuffer(buffer);
5791 checkGLcall("glReadBuffer()");
5792 } else {
5793 TRACE("Source surface %p is offscreen\n", src_surface);
5794 ENTER_GL();
5795 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5796 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
5797 glReadBuffer(GL_COLOR_ATTACHMENT0);
5798 checkGLcall("glReadBuffer()");
5799 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5801 LEAVE_GL();
5803 /* Attach dst surface to dst fbo */
5804 if (!surface_is_offscreen(dst_surface))
5806 GLenum buffer = surface_get_gl_buffer(dst_surface);
5808 TRACE("Destination surface %p is onscreen\n", dst_surface);
5809 /* Make sure the drawable is up to date. In the offscreen case
5810 * attach_surface_fbo() implicitly takes care of this. */
5811 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
5813 if(buffer == GL_FRONT) {
5814 RECT windowsize;
5815 UINT h;
5816 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
5817 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
5818 h = windowsize.bottom - windowsize.top;
5819 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
5820 dst_rect->y1 = offset.y + h - dst_rect->y1;
5821 dst_rect->y2 = offset.y + h - dst_rect->y2;
5822 } else {
5823 /* Screen coords = window coords, surface height = window height */
5824 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5825 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5828 ENTER_GL();
5829 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5830 context_set_draw_buffer(context, buffer);
5832 else
5834 TRACE("Destination surface %p is offscreen\n", dst_surface);
5836 ENTER_GL();
5837 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5838 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
5839 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5840 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5842 glDisable(GL_SCISSOR_TEST);
5843 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5845 if (flip) {
5846 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5847 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
5848 checkGLcall("glBlitFramebuffer()");
5849 } else {
5850 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5851 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
5852 checkGLcall("glBlitFramebuffer()");
5855 LEAVE_GL();
5856 context_release(context);
5858 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
5861 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5862 BOOL set_viewport) {
5863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5865 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5867 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5869 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5870 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5871 return WINED3DERR_INVALIDCALL;
5874 /* MSDN says that null disables the render target
5875 but a device must always be associated with a render target
5876 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5878 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5879 FIXME("Trying to set render target 0 to NULL\n");
5880 return WINED3DERR_INVALIDCALL;
5882 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5883 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);
5884 return WINED3DERR_INVALIDCALL;
5887 /* If we are trying to set what we already have, don't bother */
5888 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5889 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5890 return WINED3D_OK;
5892 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5893 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5894 This->render_targets[RenderTargetIndex] = pRenderTarget;
5896 /* Render target 0 is special */
5897 if(RenderTargetIndex == 0 && set_viewport) {
5898 /* Finally, reset the viewport and scissor rect as the MSDN states.
5899 * Tests show that stateblock recording is ignored, the change goes
5900 * directly into the primary stateblock.
5902 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5903 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5904 This->stateBlock->viewport.X = 0;
5905 This->stateBlock->viewport.Y = 0;
5906 This->stateBlock->viewport.MaxZ = 1.0f;
5907 This->stateBlock->viewport.MinZ = 0.0f;
5908 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5910 This->stateBlock->scissorRect.top = 0;
5911 This->stateBlock->scissorRect.left = 0;
5912 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5913 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5914 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5916 return WINED3D_OK;
5919 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5920 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5921 HRESULT hr = WINED3D_OK;
5922 IWineD3DSurface *tmp;
5924 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
5926 if (pNewZStencil == This->stencilBufferTarget) {
5927 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5928 } else {
5929 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
5930 * depending on the renter target implementation being used.
5931 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5932 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5933 * stencil buffer and incur an extra memory overhead
5934 ******************************************************/
5936 if (This->stencilBufferTarget) {
5937 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5938 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
5939 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
5940 } else {
5941 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5942 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
5943 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
5944 context_release(context);
5948 tmp = This->stencilBufferTarget;
5949 This->stencilBufferTarget = pNewZStencil;
5950 /* should we be calling the parent or the wined3d surface? */
5951 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5952 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5953 hr = WINED3D_OK;
5955 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5956 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5957 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5958 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5959 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5963 return hr;
5966 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5967 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5969 /* TODO: the use of Impl is deprecated. */
5970 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5971 WINED3DLOCKED_RECT lockedRect;
5973 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5975 /* some basic validation checks */
5976 if(This->cursorTexture) {
5977 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5978 ENTER_GL();
5979 glDeleteTextures(1, &This->cursorTexture);
5980 LEAVE_GL();
5981 context_release(context);
5982 This->cursorTexture = 0;
5985 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5986 This->haveHardwareCursor = TRUE;
5987 else
5988 This->haveHardwareCursor = FALSE;
5990 if(pCursorBitmap) {
5991 WINED3DLOCKED_RECT rect;
5993 /* MSDN: Cursor must be A8R8G8B8 */
5994 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
5996 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5997 return WINED3DERR_INVALIDCALL;
6000 /* MSDN: Cursor must be smaller than the display mode */
6001 if(pSur->currentDesc.Width > This->ddraw_width ||
6002 pSur->currentDesc.Height > This->ddraw_height) {
6003 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);
6004 return WINED3DERR_INVALIDCALL;
6007 if (!This->haveHardwareCursor) {
6008 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6010 /* Do not store the surface's pointer because the application may
6011 * release it after setting the cursor image. Windows doesn't
6012 * addref the set surface, so we can't do this either without
6013 * creating circular refcount dependencies. Copy out the gl texture
6014 * instead.
6016 This->cursorWidth = pSur->currentDesc.Width;
6017 This->cursorHeight = pSur->currentDesc.Height;
6018 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6020 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6021 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6022 struct wined3d_context *context;
6023 char *mem, *bits = rect.pBits;
6024 GLint intfmt = glDesc->glInternal;
6025 GLint format = glDesc->glFormat;
6026 GLint type = glDesc->glType;
6027 INT height = This->cursorHeight;
6028 INT width = This->cursorWidth;
6029 INT bpp = glDesc->byte_count;
6030 DWORD sampler;
6031 INT i;
6033 /* Reformat the texture memory (pitch and width can be
6034 * different) */
6035 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6036 for(i = 0; i < height; i++)
6037 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6038 IWineD3DSurface_UnlockRect(pCursorBitmap);
6040 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6042 ENTER_GL();
6044 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6046 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6047 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6050 /* Make sure that a proper texture unit is selected */
6051 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6052 checkGLcall("glActiveTextureARB");
6053 sampler = This->rev_tex_unit_map[0];
6054 if (sampler != WINED3D_UNMAPPED_STAGE)
6056 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6058 /* Create a new cursor texture */
6059 glGenTextures(1, &This->cursorTexture);
6060 checkGLcall("glGenTextures");
6061 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6062 checkGLcall("glBindTexture");
6063 /* Copy the bitmap memory into the cursor texture */
6064 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6065 HeapFree(GetProcessHeap(), 0, mem);
6066 checkGLcall("glTexImage2D");
6068 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6070 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6071 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6074 LEAVE_GL();
6076 context_release(context);
6078 else
6080 FIXME("A cursor texture was not returned.\n");
6081 This->cursorTexture = 0;
6084 else
6086 /* Draw a hardware cursor */
6087 ICONINFO cursorInfo;
6088 HCURSOR cursor;
6089 /* Create and clear maskBits because it is not needed for
6090 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6091 * chunks. */
6092 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6093 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6094 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6095 WINED3DLOCK_NO_DIRTY_UPDATE |
6096 WINED3DLOCK_READONLY
6098 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6099 pSur->currentDesc.Height);
6101 cursorInfo.fIcon = FALSE;
6102 cursorInfo.xHotspot = XHotSpot;
6103 cursorInfo.yHotspot = YHotSpot;
6104 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6105 1, 1, maskBits);
6106 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6107 1, 32, lockedRect.pBits);
6108 IWineD3DSurface_UnlockRect(pCursorBitmap);
6109 /* Create our cursor and clean up. */
6110 cursor = CreateIconIndirect(&cursorInfo);
6111 SetCursor(cursor);
6112 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6113 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6114 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6115 This->hardwareCursor = cursor;
6116 HeapFree(GetProcessHeap(), 0, maskBits);
6120 This->xHotSpot = XHotSpot;
6121 This->yHotSpot = YHotSpot;
6122 return WINED3D_OK;
6125 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6127 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6129 This->xScreenSpace = XScreenSpace;
6130 This->yScreenSpace = YScreenSpace;
6132 return;
6136 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6138 BOOL oldVisible = This->bCursorVisible;
6139 POINT pt;
6141 TRACE("(%p) : visible(%d)\n", This, bShow);
6144 * When ShowCursor is first called it should make the cursor appear at the OS's last
6145 * known cursor position. Because of this, some applications just repetitively call
6146 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6148 GetCursorPos(&pt);
6149 This->xScreenSpace = pt.x;
6150 This->yScreenSpace = pt.y;
6152 if (This->haveHardwareCursor) {
6153 This->bCursorVisible = bShow;
6154 if (bShow)
6155 SetCursor(This->hardwareCursor);
6156 else
6157 SetCursor(NULL);
6159 else
6161 if (This->cursorTexture)
6162 This->bCursorVisible = bShow;
6165 return oldVisible;
6168 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6169 TRACE("checking resource %p for eviction\n", resource);
6170 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6171 TRACE("Evicting %p\n", resource);
6172 IWineD3DResource_UnLoad(resource);
6174 IWineD3DResource_Release(resource);
6175 return S_OK;
6178 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6180 TRACE("iface %p.\n", iface);
6182 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6183 return WINED3D_OK;
6186 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6188 IWineD3DDeviceImpl *device = surface->resource.device;
6189 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6191 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6192 if(surface->Flags & SFLAG_DIBSECTION) {
6193 /* Release the DC */
6194 SelectObject(surface->hDC, surface->dib.holdbitmap);
6195 DeleteDC(surface->hDC);
6196 /* Release the DIB section */
6197 DeleteObject(surface->dib.DIBsection);
6198 surface->dib.bitmap_data = NULL;
6199 surface->resource.allocatedMemory = NULL;
6200 surface->Flags &= ~SFLAG_DIBSECTION;
6202 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6203 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6204 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6205 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6207 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6208 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6209 } else {
6210 surface->pow2Width = surface->pow2Height = 1;
6211 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6212 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6214 surface->glRect.left = 0;
6215 surface->glRect.top = 0;
6216 surface->glRect.right = surface->pow2Width;
6217 surface->glRect.bottom = surface->pow2Height;
6219 if (surface->texture_name)
6221 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6222 ENTER_GL();
6223 glDeleteTextures(1, &surface->texture_name);
6224 LEAVE_GL();
6225 context_release(context);
6226 surface->texture_name = 0;
6227 surface->Flags &= ~SFLAG_CLIENT;
6229 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6230 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6231 surface->Flags |= SFLAG_NONPOW2;
6232 } else {
6233 surface->Flags &= ~SFLAG_NONPOW2;
6235 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6236 surface->resource.allocatedMemory = NULL;
6237 surface->resource.heapMemory = NULL;
6238 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6240 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6241 * to a FBO */
6242 if(!surface_init_sysmem((IWineD3DSurface *) surface))
6244 return E_OUTOFMEMORY;
6246 return WINED3D_OK;
6249 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6250 TRACE("Unloading resource %p\n", resource);
6251 IWineD3DResource_UnLoad(resource);
6252 IWineD3DResource_Release(resource);
6253 return S_OK;
6256 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6258 UINT i, count;
6259 WINED3DDISPLAYMODE m;
6260 HRESULT hr;
6262 /* All Windowed modes are supported, as is leaving the current mode */
6263 if(pp->Windowed) return TRUE;
6264 if(!pp->BackBufferWidth) return TRUE;
6265 if(!pp->BackBufferHeight) return TRUE;
6267 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6268 for(i = 0; i < count; i++) {
6269 memset(&m, 0, sizeof(m));
6270 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6271 if(FAILED(hr)) {
6272 ERR("EnumAdapterModes failed\n");
6274 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6275 /* Mode found, it is supported */
6276 return TRUE;
6279 /* Mode not found -> not supported */
6280 return FALSE;
6283 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6285 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6286 const struct wined3d_gl_info *gl_info;
6287 struct wined3d_context *context;
6288 IWineD3DBaseShaderImpl *shader;
6290 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6291 gl_info = context->gl_info;
6293 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6294 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6295 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6298 ENTER_GL();
6299 if(This->depth_blt_texture) {
6300 glDeleteTextures(1, &This->depth_blt_texture);
6301 This->depth_blt_texture = 0;
6303 if (This->depth_blt_rb) {
6304 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6305 This->depth_blt_rb = 0;
6306 This->depth_blt_rb_w = 0;
6307 This->depth_blt_rb_h = 0;
6309 LEAVE_GL();
6311 This->blitter->free_private(iface);
6312 This->frag_pipe->free_private(iface);
6313 This->shader_backend->shader_free_private(iface);
6314 destroy_dummy_textures(This, gl_info);
6316 context_release(context);
6318 while (This->numContexts)
6320 context_destroy(This, This->contexts[0]);
6322 HeapFree(GetProcessHeap(), 0, swapchain->context);
6323 swapchain->context = NULL;
6324 swapchain->num_contexts = 0;
6327 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6329 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6330 struct wined3d_context *context;
6331 HRESULT hr;
6332 IWineD3DSurfaceImpl *target;
6334 /* Recreate the primary swapchain's context */
6335 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6336 if (!swapchain->context)
6338 ERR("Failed to allocate memory for swapchain context array.\n");
6339 return E_OUTOFMEMORY;
6342 target = (IWineD3DSurfaceImpl *)(swapchain->backBuffer ? swapchain->backBuffer[0] : swapchain->frontBuffer);
6343 context = context_create(This, target, swapchain->win_handle, FALSE, &swapchain->presentParms);
6344 if (!context)
6346 WARN("Failed to create context.\n");
6347 HeapFree(GetProcessHeap(), 0, swapchain->context);
6348 return E_FAIL;
6351 swapchain->context[0] = context;
6352 swapchain->num_contexts = 1;
6353 create_dummy_textures(This);
6354 context_release(context);
6356 hr = This->shader_backend->shader_alloc_private(iface);
6357 if (FAILED(hr))
6359 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6360 goto err;
6363 hr = This->frag_pipe->alloc_private(iface);
6364 if (FAILED(hr))
6366 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6367 This->shader_backend->shader_free_private(iface);
6368 goto err;
6371 hr = This->blitter->alloc_private(iface);
6372 if (FAILED(hr))
6374 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6375 This->frag_pipe->free_private(iface);
6376 This->shader_backend->shader_free_private(iface);
6377 goto err;
6380 return WINED3D_OK;
6382 err:
6383 context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6384 destroy_dummy_textures(This, context->gl_info);
6385 context_release(context);
6386 context_destroy(This, context);
6387 HeapFree(GetProcessHeap(), 0, swapchain->context);
6388 swapchain->num_contexts = 0;
6389 return hr;
6392 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6394 IWineD3DSwapChainImpl *swapchain;
6395 HRESULT hr;
6396 BOOL DisplayModeChanged = FALSE;
6397 WINED3DDISPLAYMODE mode;
6398 TRACE("(%p)\n", This);
6400 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6401 if(FAILED(hr)) {
6402 ERR("Failed to get the first implicit swapchain\n");
6403 return hr;
6406 if(!is_display_mode_supported(This, pPresentationParameters)) {
6407 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6408 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6409 pPresentationParameters->BackBufferHeight);
6410 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6411 return WINED3DERR_INVALIDCALL;
6414 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6415 * on an existing gl context, so there's no real need for recreation.
6417 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6419 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6421 TRACE("New params:\n");
6422 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6423 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6424 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6425 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6426 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6427 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6428 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6429 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6430 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6431 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6432 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6433 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6434 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6436 /* No special treatment of these parameters. Just store them */
6437 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6438 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6439 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6440 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6442 /* What to do about these? */
6443 if(pPresentationParameters->BackBufferCount != 0 &&
6444 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6445 ERR("Cannot change the back buffer count yet\n");
6447 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6448 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6449 ERR("Cannot change the back buffer format yet\n");
6451 if(pPresentationParameters->hDeviceWindow != NULL &&
6452 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6453 ERR("Cannot change the device window yet\n");
6455 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6456 HRESULT hrc;
6458 TRACE("Creating the depth stencil buffer\n");
6460 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6461 This->parent,
6462 pPresentationParameters->BackBufferWidth,
6463 pPresentationParameters->BackBufferHeight,
6464 pPresentationParameters->AutoDepthStencilFormat,
6465 pPresentationParameters->MultiSampleType,
6466 pPresentationParameters->MultiSampleQuality,
6467 FALSE,
6468 &This->auto_depth_stencil_buffer);
6470 if (FAILED(hrc)) {
6471 ERR("Failed to create the depth stencil buffer\n");
6472 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6473 return WINED3DERR_INVALIDCALL;
6477 /* Reset the depth stencil */
6478 if (pPresentationParameters->EnableAutoDepthStencil)
6479 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6480 else
6481 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6483 TRACE("Resetting stateblock\n");
6484 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6485 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6487 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6489 if(pPresentationParameters->Windowed) {
6490 mode.Width = swapchain->orig_width;
6491 mode.Height = swapchain->orig_height;
6492 mode.RefreshRate = 0;
6493 mode.Format = swapchain->presentParms.BackBufferFormat;
6494 } else {
6495 mode.Width = pPresentationParameters->BackBufferWidth;
6496 mode.Height = pPresentationParameters->BackBufferHeight;
6497 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6498 mode.Format = swapchain->presentParms.BackBufferFormat;
6501 /* Should Width == 800 && Height == 0 set 800x600? */
6502 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6503 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6504 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6506 UINT i;
6508 if(!pPresentationParameters->Windowed) {
6509 DisplayModeChanged = TRUE;
6511 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6512 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6514 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6515 if(FAILED(hr))
6517 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6518 return hr;
6521 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6522 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6523 if(FAILED(hr))
6525 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6526 return hr;
6529 if(This->auto_depth_stencil_buffer) {
6530 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6531 if(FAILED(hr))
6533 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6534 return hr;
6539 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6540 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6541 DisplayModeChanged) {
6543 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6545 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
6546 if(swapchain->presentParms.Windowed) {
6547 /* switch from windowed to fs */
6548 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6549 pPresentationParameters->BackBufferHeight);
6550 } else {
6551 /* Fullscreen -> fullscreen mode change */
6552 MoveWindow(swapchain->win_handle, 0, 0,
6553 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6554 TRUE);
6556 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
6557 /* Fullscreen -> windowed switch */
6558 swapchain_restore_fullscreen_window(swapchain);
6560 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6561 } else if(!pPresentationParameters->Windowed) {
6562 DWORD style = This->style, exStyle = This->exStyle;
6563 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6564 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6565 * Reset to clear up their mess. Guild Wars also loses the device during that.
6567 This->style = 0;
6568 This->exStyle = 0;
6569 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6570 pPresentationParameters->BackBufferHeight);
6571 This->style = style;
6572 This->exStyle = exStyle;
6575 /* Note: No parent needed for initial internal stateblock */
6576 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6577 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6578 else TRACE("Created stateblock %p\n", This->stateBlock);
6579 This->updateStateBlock = This->stateBlock;
6580 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6582 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6583 if(FAILED(hr)) {
6584 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6587 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6589 RECT client_rect;
6590 GetClientRect(swapchain->win_handle, &client_rect);
6592 if(!swapchain->presentParms.BackBufferCount)
6594 TRACE("Single buffered rendering\n");
6595 swapchain->render_to_fbo = FALSE;
6597 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6598 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6600 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6601 swapchain->presentParms.BackBufferWidth,
6602 swapchain->presentParms.BackBufferHeight,
6603 client_rect.right, client_rect.bottom);
6604 swapchain->render_to_fbo = TRUE;
6606 else
6608 TRACE("Rendering directly to GL_BACK\n");
6609 swapchain->render_to_fbo = FALSE;
6613 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6614 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6616 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6617 * first use
6619 return hr;
6622 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6624 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6626 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6628 return WINED3D_OK;
6632 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6634 TRACE("(%p) : pParameters %p\n", This, pParameters);
6636 *pParameters = This->createParms;
6637 return WINED3D_OK;
6640 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6641 IWineD3DSwapChain *swapchain;
6643 TRACE("Relaying to swapchain\n");
6645 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6646 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6647 IWineD3DSwapChain_Release(swapchain);
6651 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6652 IWineD3DSwapChain *swapchain;
6654 TRACE("Relaying to swapchain\n");
6656 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6657 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6658 IWineD3DSwapChain_Release(swapchain);
6663 /** ********************************************************
6664 * Notification functions
6665 ** ********************************************************/
6666 /** This function must be called in the release of a resource when ref == 0,
6667 * the contents of resource must still be correct,
6668 * any handles to other resource held by the caller must be closed
6669 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6670 *****************************************************/
6671 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6673 TRACE("(%p) : Adding resource %p\n", This, resource);
6675 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6678 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6680 TRACE("(%p) : Removing resource %p\n", This, resource);
6682 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6685 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6687 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6688 int counter;
6690 TRACE("(%p) : resource %p\n", This, resource);
6692 context_resource_released((IWineD3DDevice *)This, resource, type);
6694 switch (type) {
6695 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6696 case WINED3DRTYPE_SURFACE: {
6697 unsigned int i;
6699 if (This->d3d_initialized)
6701 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6703 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6704 This->render_targets[i] = NULL;
6707 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6708 This->stencilBufferTarget = NULL;
6712 break;
6714 case WINED3DRTYPE_TEXTURE:
6715 case WINED3DRTYPE_CUBETEXTURE:
6716 case WINED3DRTYPE_VOLUMETEXTURE:
6717 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6718 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6719 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6720 This->stateBlock->textures[counter] = NULL;
6722 if (This->updateStateBlock != This->stateBlock ){
6723 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6724 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6725 This->updateStateBlock->textures[counter] = NULL;
6729 break;
6730 case WINED3DRTYPE_VOLUME:
6731 /* TODO: nothing really? */
6732 break;
6733 case WINED3DRTYPE_BUFFER:
6735 int streamNumber;
6736 TRACE("Cleaning up stream pointers\n");
6738 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6739 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6740 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6742 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6743 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6744 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6745 This->updateStateBlock->streamSource[streamNumber] = 0;
6746 /* Set changed flag? */
6749 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) */
6750 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6751 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6752 This->stateBlock->streamSource[streamNumber] = 0;
6757 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6758 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6759 This->updateStateBlock->pIndexData = NULL;
6762 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6763 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6764 This->stateBlock->pIndexData = NULL;
6768 break;
6770 default:
6771 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6772 break;
6776 /* Remove the resource from the resourceStore */
6777 device_resource_remove(This, resource);
6779 TRACE("Resource released\n");
6783 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6785 IWineD3DResourceImpl *resource, *cursor;
6786 HRESULT ret;
6787 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6789 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6790 TRACE("enumerating resource %p\n", resource);
6791 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6792 ret = pCallback((IWineD3DResource *) resource, pData);
6793 if(ret == S_FALSE) {
6794 TRACE("Canceling enumeration\n");
6795 break;
6798 return WINED3D_OK;
6801 /**********************************************************
6802 * IWineD3DDevice VTbl follows
6803 **********************************************************/
6805 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6807 /*** IUnknown methods ***/
6808 IWineD3DDeviceImpl_QueryInterface,
6809 IWineD3DDeviceImpl_AddRef,
6810 IWineD3DDeviceImpl_Release,
6811 /*** IWineD3DDevice methods ***/
6812 IWineD3DDeviceImpl_GetParent,
6813 /*** Creation methods**/
6814 IWineD3DDeviceImpl_CreateBuffer,
6815 IWineD3DDeviceImpl_CreateVertexBuffer,
6816 IWineD3DDeviceImpl_CreateIndexBuffer,
6817 IWineD3DDeviceImpl_CreateStateBlock,
6818 IWineD3DDeviceImpl_CreateSurface,
6819 IWineD3DDeviceImpl_CreateRendertargetView,
6820 IWineD3DDeviceImpl_CreateTexture,
6821 IWineD3DDeviceImpl_CreateVolumeTexture,
6822 IWineD3DDeviceImpl_CreateVolume,
6823 IWineD3DDeviceImpl_CreateCubeTexture,
6824 IWineD3DDeviceImpl_CreateQuery,
6825 IWineD3DDeviceImpl_CreateSwapChain,
6826 IWineD3DDeviceImpl_CreateVertexDeclaration,
6827 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6828 IWineD3DDeviceImpl_CreateVertexShader,
6829 IWineD3DDeviceImpl_CreateGeometryShader,
6830 IWineD3DDeviceImpl_CreatePixelShader,
6831 IWineD3DDeviceImpl_CreatePalette,
6832 /*** Odd functions **/
6833 IWineD3DDeviceImpl_Init3D,
6834 IWineD3DDeviceImpl_InitGDI,
6835 IWineD3DDeviceImpl_Uninit3D,
6836 IWineD3DDeviceImpl_UninitGDI,
6837 IWineD3DDeviceImpl_SetMultithreaded,
6838 IWineD3DDeviceImpl_EvictManagedResources,
6839 IWineD3DDeviceImpl_GetAvailableTextureMem,
6840 IWineD3DDeviceImpl_GetBackBuffer,
6841 IWineD3DDeviceImpl_GetCreationParameters,
6842 IWineD3DDeviceImpl_GetDeviceCaps,
6843 IWineD3DDeviceImpl_GetDirect3D,
6844 IWineD3DDeviceImpl_GetDisplayMode,
6845 IWineD3DDeviceImpl_SetDisplayMode,
6846 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6847 IWineD3DDeviceImpl_GetRasterStatus,
6848 IWineD3DDeviceImpl_GetSwapChain,
6849 IWineD3DDeviceImpl_Reset,
6850 IWineD3DDeviceImpl_SetDialogBoxMode,
6851 IWineD3DDeviceImpl_SetCursorProperties,
6852 IWineD3DDeviceImpl_SetCursorPosition,
6853 IWineD3DDeviceImpl_ShowCursor,
6854 /*** Getters and setters **/
6855 IWineD3DDeviceImpl_SetClipPlane,
6856 IWineD3DDeviceImpl_GetClipPlane,
6857 IWineD3DDeviceImpl_SetClipStatus,
6858 IWineD3DDeviceImpl_GetClipStatus,
6859 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6860 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6861 IWineD3DDeviceImpl_SetDepthStencilSurface,
6862 IWineD3DDeviceImpl_GetDepthStencilSurface,
6863 IWineD3DDeviceImpl_SetGammaRamp,
6864 IWineD3DDeviceImpl_GetGammaRamp,
6865 IWineD3DDeviceImpl_SetIndexBuffer,
6866 IWineD3DDeviceImpl_GetIndexBuffer,
6867 IWineD3DDeviceImpl_SetBaseVertexIndex,
6868 IWineD3DDeviceImpl_GetBaseVertexIndex,
6869 IWineD3DDeviceImpl_SetLight,
6870 IWineD3DDeviceImpl_GetLight,
6871 IWineD3DDeviceImpl_SetLightEnable,
6872 IWineD3DDeviceImpl_GetLightEnable,
6873 IWineD3DDeviceImpl_SetMaterial,
6874 IWineD3DDeviceImpl_GetMaterial,
6875 IWineD3DDeviceImpl_SetNPatchMode,
6876 IWineD3DDeviceImpl_GetNPatchMode,
6877 IWineD3DDeviceImpl_SetPaletteEntries,
6878 IWineD3DDeviceImpl_GetPaletteEntries,
6879 IWineD3DDeviceImpl_SetPixelShader,
6880 IWineD3DDeviceImpl_GetPixelShader,
6881 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6882 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6883 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6884 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6885 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6886 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6887 IWineD3DDeviceImpl_SetRenderState,
6888 IWineD3DDeviceImpl_GetRenderState,
6889 IWineD3DDeviceImpl_SetRenderTarget,
6890 IWineD3DDeviceImpl_GetRenderTarget,
6891 IWineD3DDeviceImpl_SetFrontBackBuffers,
6892 IWineD3DDeviceImpl_SetSamplerState,
6893 IWineD3DDeviceImpl_GetSamplerState,
6894 IWineD3DDeviceImpl_SetScissorRect,
6895 IWineD3DDeviceImpl_GetScissorRect,
6896 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6897 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6898 IWineD3DDeviceImpl_SetStreamSource,
6899 IWineD3DDeviceImpl_GetStreamSource,
6900 IWineD3DDeviceImpl_SetStreamSourceFreq,
6901 IWineD3DDeviceImpl_GetStreamSourceFreq,
6902 IWineD3DDeviceImpl_SetTexture,
6903 IWineD3DDeviceImpl_GetTexture,
6904 IWineD3DDeviceImpl_SetTextureStageState,
6905 IWineD3DDeviceImpl_GetTextureStageState,
6906 IWineD3DDeviceImpl_SetTransform,
6907 IWineD3DDeviceImpl_GetTransform,
6908 IWineD3DDeviceImpl_SetVertexDeclaration,
6909 IWineD3DDeviceImpl_GetVertexDeclaration,
6910 IWineD3DDeviceImpl_SetVertexShader,
6911 IWineD3DDeviceImpl_GetVertexShader,
6912 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6913 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6914 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6915 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6916 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6917 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6918 IWineD3DDeviceImpl_SetViewport,
6919 IWineD3DDeviceImpl_GetViewport,
6920 IWineD3DDeviceImpl_MultiplyTransform,
6921 IWineD3DDeviceImpl_ValidateDevice,
6922 IWineD3DDeviceImpl_ProcessVertices,
6923 /*** State block ***/
6924 IWineD3DDeviceImpl_BeginStateBlock,
6925 IWineD3DDeviceImpl_EndStateBlock,
6926 /*** Scene management ***/
6927 IWineD3DDeviceImpl_BeginScene,
6928 IWineD3DDeviceImpl_EndScene,
6929 IWineD3DDeviceImpl_Present,
6930 IWineD3DDeviceImpl_Clear,
6931 IWineD3DDeviceImpl_ClearRendertargetView,
6932 /*** Drawing ***/
6933 IWineD3DDeviceImpl_SetPrimitiveType,
6934 IWineD3DDeviceImpl_GetPrimitiveType,
6935 IWineD3DDeviceImpl_DrawPrimitive,
6936 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6937 IWineD3DDeviceImpl_DrawPrimitiveUP,
6938 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6939 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6940 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6941 IWineD3DDeviceImpl_DrawRectPatch,
6942 IWineD3DDeviceImpl_DrawTriPatch,
6943 IWineD3DDeviceImpl_DeletePatch,
6944 IWineD3DDeviceImpl_ColorFill,
6945 IWineD3DDeviceImpl_UpdateTexture,
6946 IWineD3DDeviceImpl_UpdateSurface,
6947 IWineD3DDeviceImpl_GetFrontBufferData,
6948 /*** object tracking ***/
6949 IWineD3DDeviceImpl_EnumResources
6952 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6953 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6954 IUnknown *parent, IWineD3DDeviceParent *device_parent)
6956 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6957 const struct fragment_pipeline *fragment_pipeline;
6958 struct shader_caps shader_caps;
6959 struct fragment_caps ffp_caps;
6960 WINED3DDISPLAYMODE mode;
6961 unsigned int i;
6962 HRESULT hr;
6964 device->lpVtbl = &IWineD3DDevice_Vtbl;
6965 device->ref = 1;
6966 device->wined3d = (IWineD3D *)wined3d;
6967 IWineD3D_AddRef(device->wined3d);
6968 device->adapter = wined3d->adapter_count ? adapter : NULL;
6969 device->parent = parent;
6970 device->device_parent = device_parent;
6971 list_init(&device->resources);
6972 list_init(&device->shaders);
6974 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6975 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6977 /* Get the initial screen setup for ddraw. */
6978 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6979 if (FAILED(hr))
6981 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6982 IWineD3D_Release(device->wined3d);
6983 return hr;
6985 device->ddraw_width = mode.Width;
6986 device->ddraw_height = mode.Height;
6987 device->ddraw_format = mode.Format;
6989 /* Save the creation parameters. */
6990 device->createParms.AdapterOrdinal = adapter_idx;
6991 device->createParms.DeviceType = device_type;
6992 device->createParms.hFocusWindow = focus_window;
6993 device->createParms.BehaviorFlags = flags;
6995 device->devType = device_type;
6996 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6998 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6999 device->shader_backend = select_shader_backend(adapter, device_type);
7001 memset(&shader_caps, 0, sizeof(shader_caps));
7002 device->shader_backend->shader_get_caps(device_type, &adapter->gl_info, &shader_caps);
7003 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7004 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7005 device->vs_clipping = shader_caps.VSClipping;
7007 memset(&ffp_caps, 0, sizeof(ffp_caps));
7008 fragment_pipeline = select_fragment_implementation(adapter, device_type);
7009 device->frag_pipe = fragment_pipeline;
7010 fragment_pipeline->get_caps(device_type, &adapter->gl_info, &ffp_caps);
7011 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7012 device->max_ffp_texture_stages = ffp_caps.MaxTextureBlendStages;
7014 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7015 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7016 if (FAILED(hr))
7018 ERR("Failed to compile state table, hr %#x.\n", hr);
7019 IWineD3D_Release(device->wined3d);
7020 return hr;
7023 device->blitter = select_blit_implementation(adapter, device_type);
7025 return WINED3D_OK;
7029 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7030 DWORD rep = This->StateTable[state].representative;
7031 struct wined3d_context *context;
7032 DWORD idx;
7033 BYTE shift;
7034 UINT i;
7036 for(i = 0; i < This->numContexts; i++) {
7037 context = This->contexts[i];
7038 if(isStateDirty(context, rep)) continue;
7040 context->dirtyArray[context->numDirtyEntries++] = rep;
7041 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7042 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7043 context->isStateDirty[idx] |= (1 << shift);
7047 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7049 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.device;
7050 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7051 *width = device->pbufferWidth;
7052 *height = device->pbufferHeight;
7055 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7057 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7058 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7059 *width = surface->pow2Width;
7060 *height = surface->pow2Height;
7063 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7065 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7066 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7067 * current context's drawable, which is the size of the back buffer of the swapchain
7068 * the active context belongs to. The back buffer of the swapchain is stored as the
7069 * surface the context belongs to. */
7070 *width = surface->currentDesc.Width;
7071 *height = surface->currentDesc.Height;
7074 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7075 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7077 if (device->filter_messages)
7079 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7080 window, message, wparam, lparam);
7081 return DefWindowProcW(window, message, wparam, lparam);
7084 if (message == WM_DESTROY)
7086 TRACE("unregister window %p.\n", window);
7087 wined3d_unregister_window(window);
7089 if (device->focus_window == window) device->focus_window = NULL;
7090 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7093 return CallWindowProcW(proc, window, message, wparam, lparam);