wined3d: Don't render single buffered swapchains to a FBO.
[wine/multimedia.git] / dlls / wined3d / device.c
blob9d603d5d0729c4701284c84f88921639ed60df7a
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "config.h"
30 #include <stdio.h>
31 #ifdef HAVE_FLOAT_H
32 # include <float.h>
33 #endif
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
37 #define GLINFO_LOCATION This->adapter->gl_info
39 /* Define the default light parameters as specified by MSDN */
40 const WINED3DLIGHT WINED3D_default_light = {
42 WINED3DLIGHT_DIRECTIONAL, /* Type */
43 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
45 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
46 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
47 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
48 0.0f, /* Range */
49 0.0f, /* Falloff */
50 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
51 0.0f, /* Theta */
52 0.0f /* Phi */
55 /**********************************************************
56 * Global variable / Constants follow
57 **********************************************************/
58 const float identity[] =
60 1.0f, 0.0f, 0.0f, 0.0f,
61 0.0f, 1.0f, 0.0f, 0.0f,
62 0.0f, 0.0f, 1.0f, 0.0f,
63 0.0f, 0.0f, 0.0f, 1.0f,
64 }; /* When needed for comparisons */
66 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
67 * actually have the same values in GL and D3D. */
68 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
70 switch(primitive_type)
72 case WINED3DPT_POINTLIST:
73 return GL_POINTS;
75 case WINED3DPT_LINELIST:
76 return GL_LINES;
78 case WINED3DPT_LINESTRIP:
79 return GL_LINE_STRIP;
81 case WINED3DPT_TRIANGLELIST:
82 return GL_TRIANGLES;
84 case WINED3DPT_TRIANGLESTRIP:
85 return GL_TRIANGLE_STRIP;
87 case WINED3DPT_TRIANGLEFAN:
88 return GL_TRIANGLE_FAN;
90 case WINED3DPT_LINELIST_ADJ:
91 return GL_LINES_ADJACENCY_ARB;
93 case WINED3DPT_LINESTRIP_ADJ:
94 return GL_LINE_STRIP_ADJACENCY_ARB;
96 case WINED3DPT_TRIANGLELIST_ADJ:
97 return GL_TRIANGLES_ADJACENCY_ARB;
99 case WINED3DPT_TRIANGLESTRIP_ADJ:
100 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
102 default:
103 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
104 return GL_NONE;
108 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
110 switch(primitive_type)
112 case GL_POINTS:
113 return WINED3DPT_POINTLIST;
115 case GL_LINES:
116 return WINED3DPT_LINELIST;
118 case GL_LINE_STRIP:
119 return WINED3DPT_LINESTRIP;
121 case GL_TRIANGLES:
122 return WINED3DPT_TRIANGLELIST;
124 case GL_TRIANGLE_STRIP:
125 return WINED3DPT_TRIANGLESTRIP;
127 case GL_TRIANGLE_FAN:
128 return WINED3DPT_TRIANGLEFAN;
130 case GL_LINES_ADJACENCY_ARB:
131 return WINED3DPT_LINELIST_ADJ;
133 case GL_LINE_STRIP_ADJACENCY_ARB:
134 return WINED3DPT_LINESTRIP_ADJ;
136 case GL_TRIANGLES_ADJACENCY_ARB:
137 return WINED3DPT_TRIANGLELIST_ADJ;
139 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
140 return WINED3DPT_TRIANGLESTRIP_ADJ;
142 default:
143 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
144 return WINED3DPT_UNDEFINED;
148 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
150 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
151 *regnum = WINED3D_FFP_POSITION;
152 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
153 *regnum = WINED3D_FFP_BLENDWEIGHT;
154 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
155 *regnum = WINED3D_FFP_BLENDINDICES;
156 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
157 *regnum = WINED3D_FFP_NORMAL;
158 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
159 *regnum = WINED3D_FFP_PSIZE;
160 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
161 *regnum = WINED3D_FFP_DIFFUSE;
162 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
163 *regnum = WINED3D_FFP_SPECULAR;
164 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
165 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
166 else
168 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
169 *regnum = ~0U;
170 return FALSE;
173 return TRUE;
176 /* Context activation is done by the caller. */
177 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
178 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
180 /* We need to deal with frequency data! */
181 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
182 UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
183 const DWORD *streams = declaration->streams;
184 unsigned int i;
186 stream_info->use_map = 0;
187 stream_info->swizzle_map = 0;
189 /* Check for transformed vertices, disable vertex shader if present. */
190 stream_info->position_transformed = declaration->position_transformed;
191 if (declaration->position_transformed) use_vshader = FALSE;
193 /* Translate the declaration into strided data. */
194 for (i = 0; i < declaration->element_count; ++i)
196 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
197 GLuint buffer_object = 0;
198 const BYTE *data = NULL;
199 BOOL stride_used;
200 unsigned int idx;
201 DWORD stride;
203 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
204 element, i + 1, declaration->element_count);
206 if (!This->stateBlock->streamSource[element->input_slot]) continue;
208 stride = This->stateBlock->streamStride[element->input_slot];
209 if (This->stateBlock->streamIsUP)
211 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
212 buffer_object = 0;
213 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
215 else
217 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
218 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
220 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
221 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
222 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
223 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
224 * not, drawStridedSlow is needed, including a vertex buffer path. */
225 if (This->stateBlock->loadBaseVertexIndex < 0)
227 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
228 buffer_object = 0;
229 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
230 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
232 FIXME("System memory vertex data load offset is negative!\n");
236 if (fixup)
238 if (buffer_object) *fixup = TRUE;
239 else if (*fixup && !use_vshader
240 && (element->usage == WINED3DDECLUSAGE_COLOR
241 || element->usage == WINED3DDECLUSAGE_POSITIONT))
243 static BOOL warned = FALSE;
244 if (!warned)
246 /* This may be bad with the fixed function pipeline. */
247 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
248 warned = TRUE;
253 data += element->offset;
255 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
257 if (use_vshader)
259 if (element->output_slot == ~0U)
261 /* TODO: Assuming vertexdeclarations are usually used with the
262 * same or a similar shader, it might be worth it to store the
263 * last used output slot and try that one first. */
264 stride_used = vshader_get_input(This->stateBlock->vertexShader,
265 element->usage, element->usage_idx, &idx);
267 else
269 idx = element->output_slot;
270 stride_used = TRUE;
273 else
275 if (!element->ffp_valid)
277 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
278 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
279 stride_used = FALSE;
281 else
283 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
287 if (stride_used)
289 TRACE("Load %s array %u [usage %s, usage_idx %u, "
290 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
291 use_vshader ? "shader": "fixed function", idx,
292 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
293 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
295 stream_info->elements[idx].format_desc = element->format_desc;
296 stream_info->elements[idx].stride = stride;
297 stream_info->elements[idx].data = data;
298 stream_info->elements[idx].stream_idx = element->input_slot;
299 stream_info->elements[idx].buffer_object = buffer_object;
301 if (!This->adapter->gl_info.supported[EXT_VERTEX_ARRAY_BGRA]
302 && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
304 stream_info->swizzle_map |= 1 << idx;
306 stream_info->use_map |= 1 << idx;
310 /* Now call PreLoad on all the vertex buffers. In the very rare case
311 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
312 * The vertex buffer can now use the strided structure in the device instead of finding its
313 * own again.
315 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
316 * once in there. */
317 for (i = 0; i < stream_count; ++i)
319 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
320 if (vb) IWineD3DBuffer_PreLoad(vb);
324 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
325 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
327 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, gl_info);
328 e->format_desc = format_desc;
329 e->stride = strided->dwStride;
330 e->data = strided->lpData;
331 e->stream_idx = 0;
332 e->buffer_object = 0;
335 void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
336 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
338 unsigned int i;
340 memset(stream_info, 0, sizeof(*stream_info));
342 if (strided->position.lpData)
343 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
344 if (strided->normal.lpData)
345 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
346 if (strided->diffuse.lpData)
347 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
348 if (strided->specular.lpData)
349 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
351 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
353 if (strided->texCoords[i].lpData)
354 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
355 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
358 stream_info->position_transformed = strided->position_transformed;
360 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
362 if (!stream_info->elements[i].format_desc) continue;
364 if (!gl_info->supported[EXT_VERTEX_ARRAY_BGRA]
365 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
367 stream_info->swizzle_map |= 1 << i;
369 stream_info->use_map |= 1 << i;
373 /**********************************************************
374 * IUnknown parts follows
375 **********************************************************/
377 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
381 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
382 if (IsEqualGUID(riid, &IID_IUnknown)
383 || IsEqualGUID(riid, &IID_IWineD3DBase)
384 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
385 IUnknown_AddRef(iface);
386 *ppobj = This;
387 return S_OK;
389 *ppobj = NULL;
390 return E_NOINTERFACE;
393 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
395 ULONG refCount = InterlockedIncrement(&This->ref);
397 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
398 return refCount;
401 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
403 ULONG refCount = InterlockedDecrement(&This->ref);
405 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
407 if (!refCount) {
408 UINT i;
410 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
411 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
412 This->multistate_funcs[i] = NULL;
415 /* TODO: Clean up all the surfaces and textures! */
416 /* NOTE: You must release the parent if the object was created via a callback
417 ** ***************************/
419 if (!list_empty(&This->resources)) {
420 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
421 dumpResources(&This->resources);
424 if(This->contexts) ERR("Context array not freed!\n");
425 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
426 This->haveHardwareCursor = FALSE;
428 IWineD3D_Release(This->wined3d);
429 This->wined3d = NULL;
430 HeapFree(GetProcessHeap(), 0, This);
431 TRACE("Freed device %p\n", This);
432 This = NULL;
434 return refCount;
437 /**********************************************************
438 * IWineD3DDevice implementation follows
439 **********************************************************/
440 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
442 *pParent = This->parent;
443 IUnknown_AddRef(This->parent);
444 return WINED3D_OK;
447 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
448 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
451 struct wined3d_buffer *object;
452 HRESULT hr;
454 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
456 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
457 if (!object)
459 ERR("Failed to allocate memory\n");
460 return E_OUTOFMEMORY;
463 FIXME("Ignoring access flags (pool)\n");
465 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
466 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
467 if (FAILED(hr))
469 WARN("Failed to initialize buffer, hr %#x.\n", hr);
470 HeapFree(GetProcessHeap(), 0, object);
471 return hr;
473 object->desc = *desc;
475 TRACE("Created buffer %p.\n", object);
477 *buffer = (IWineD3DBuffer *)object;
479 return WINED3D_OK;
482 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size,
483 DWORD Usage, DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
484 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
487 struct wined3d_buffer *object;
488 HRESULT hr;
489 BOOL conv;
491 if (Pool == WINED3DPOOL_SCRATCH)
493 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
494 * anyway, SCRATCH vertex buffers aren't usable anywhere
496 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
497 *ppVertexBuffer = NULL;
498 return WINED3DERR_INVALIDCALL;
501 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
502 if (!object)
504 ERR("Out of memory\n");
505 *ppVertexBuffer = NULL;
506 return WINED3DERR_OUTOFVIDEOMEMORY;
509 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
510 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
511 if (FAILED(hr))
513 WARN("Failed to initialize buffer, hr %#x.\n", hr);
514 HeapFree(GetProcessHeap(), 0, object);
515 return hr;
518 TRACE("Created buffer %p.\n", object);
519 TRACE("FVF %#x, Pool %#x.\n", FVF, Pool);
520 *ppVertexBuffer = (IWineD3DBuffer *)object;
522 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
523 * drawStridedFast (half-life 2).
525 * Basically converting the vertices in the buffer is quite expensive, and observations
526 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
527 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
529 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
530 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
531 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
532 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
533 * dx7 apps.
534 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
535 * more. In this call we can convert dx7 buffers too.
537 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
538 if (!This->adapter->gl_info.supported[ARB_VERTEX_BUFFER_OBJECT])
540 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
541 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
542 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
543 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
544 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
545 } else if(!(Usage & WINED3DUSAGE_OPTIMIZE) && conv) {
546 TRACE("Not creating a vbo because the fvf needs conversion, but VB optimization is disabled\n");
547 } else {
548 object->flags |= WINED3D_BUFFER_CREATEBO;
550 return WINED3D_OK;
553 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
554 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
555 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
558 struct wined3d_buffer *object;
559 HRESULT hr;
561 TRACE("(%p) Creating index buffer\n", This);
563 /* Allocate the storage for the device */
564 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
565 if (!object)
567 ERR("Out of memory\n");
568 *ppIndexBuffer = NULL;
569 return WINED3DERR_OUTOFVIDEOMEMORY;
572 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
573 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
574 if (FAILED(hr))
576 WARN("Failed to initialize buffer, hr %#x\n", hr);
577 HeapFree(GetProcessHeap(), 0, object);
578 return hr;
581 TRACE("Created buffer %p.\n", object);
583 if (Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC)
584 && This->adapter->gl_info.supported[ARB_VERTEX_BUFFER_OBJECT])
586 object->flags |= WINED3D_BUFFER_CREATEBO;
589 *ppIndexBuffer = (IWineD3DBuffer *) object;
591 return WINED3D_OK;
594 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
595 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
598 IWineD3DStateBlockImpl *object;
599 HRESULT hr;
601 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
602 if(!object)
604 ERR("Failed to allocate stateblock memory.\n");
605 return E_OUTOFMEMORY;
608 hr = stateblock_init(object, This, type);
609 if (FAILED(hr))
611 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
612 HeapFree(GetProcessHeap(), 0, object);
613 return hr;
616 TRACE("Created stateblock %p.\n", object);
617 *stateblock = (IWineD3DStateBlock *)object;
619 return WINED3D_OK;
622 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
623 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
624 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
625 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
628 IWineD3DSurfaceImpl *object;
629 HRESULT hr;
631 TRACE("(%p) Create surface\n",This);
633 if (Impl == SURFACE_OPENGL && !This->adapter)
635 ERR("OpenGL surfaces are not available without OpenGL.\n");
636 return WINED3DERR_NOTAVAILABLE;
639 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
640 if (!object)
642 ERR("Failed to allocate surface memory.\n");
643 *ppSurface = NULL;
644 return WINED3DERR_OUTOFVIDEOMEMORY;
647 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
648 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
649 if (FAILED(hr))
651 WARN("Failed to initialize surface, returning %#x.\n", hr);
652 HeapFree(GetProcessHeap(), 0, object);
653 *ppSurface = NULL;
654 return hr;
657 TRACE("(%p) : Created surface %p\n", This, object);
659 *ppSurface = (IWineD3DSurface *)object;
661 return hr;
664 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
665 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
667 struct wined3d_rendertarget_view *object;
669 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
670 if (!object)
672 ERR("Failed to allocate memory\n");
673 return E_OUTOFMEMORY;
676 object->vtbl = &wined3d_rendertarget_view_vtbl;
677 object->refcount = 1;
678 IWineD3DResource_AddRef(resource);
679 object->resource = resource;
680 object->parent = parent;
682 *rendertarget_view = (IWineD3DRendertargetView *)object;
684 return WINED3D_OK;
687 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
688 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
689 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
692 IWineD3DTextureImpl *object;
693 HRESULT hr;
695 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
696 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
697 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
699 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
700 if (!object)
702 ERR("Out of memory\n");
703 *ppTexture = NULL;
704 return WINED3DERR_OUTOFVIDEOMEMORY;
707 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
708 if (FAILED(hr))
710 WARN("Failed to initialize texture, returning %#x\n", hr);
711 HeapFree(GetProcessHeap(), 0, object);
712 *ppTexture = NULL;
713 return hr;
716 *ppTexture = (IWineD3DTexture *)object;
718 TRACE("(%p) : Created texture %p\n", This, object);
720 return WINED3D_OK;
723 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
724 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
725 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
728 IWineD3DVolumeTextureImpl *object;
729 HRESULT hr;
731 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
732 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
734 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
735 if (!object)
737 ERR("Out of memory\n");
738 *ppVolumeTexture = NULL;
739 return WINED3DERR_OUTOFVIDEOMEMORY;
742 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
743 if (FAILED(hr))
745 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
746 HeapFree(GetProcessHeap(), 0, object);
747 *ppVolumeTexture = NULL;
748 return hr;
751 TRACE("(%p) : Created volume texture %p.\n", This, object);
752 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
754 return WINED3D_OK;
757 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
758 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
759 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
762 IWineD3DVolumeImpl *object;
763 HRESULT hr;
765 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
766 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
768 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
769 if (!object)
771 ERR("Out of memory\n");
772 *ppVolume = NULL;
773 return WINED3DERR_OUTOFVIDEOMEMORY;
776 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
777 if (FAILED(hr))
779 WARN("Failed to initialize volume, returning %#x.\n", hr);
780 HeapFree(GetProcessHeap(), 0, object);
781 return hr;
784 TRACE("(%p) : Created volume %p.\n", This, object);
785 *ppVolume = (IWineD3DVolume *)object;
787 return WINED3D_OK;
790 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
791 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
792 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
795 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
796 HRESULT hr;
798 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
799 if (!object)
801 ERR("Out of memory\n");
802 *ppCubeTexture = NULL;
803 return WINED3DERR_OUTOFVIDEOMEMORY;
806 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
807 if (FAILED(hr))
809 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
810 HeapFree(GetProcessHeap(), 0, object);
811 *ppCubeTexture = NULL;
812 return hr;
815 TRACE("(%p) : Created Cube Texture %p\n", This, object);
816 *ppCubeTexture = (IWineD3DCubeTexture *)object;
818 return WINED3D_OK;
821 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
823 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
824 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
825 HRESULT hr = WINED3DERR_NOTAVAILABLE;
826 const IWineD3DQueryVtbl *vtable;
828 /* Just a check to see if we support this type of query */
829 switch(Type) {
830 case WINED3DQUERYTYPE_OCCLUSION:
831 TRACE("(%p) occlusion query\n", This);
832 if (gl_info->supported[ARB_OCCLUSION_QUERY])
833 hr = WINED3D_OK;
834 else
835 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
837 vtable = &IWineD3DOcclusionQuery_Vtbl;
838 break;
840 case WINED3DQUERYTYPE_EVENT:
841 if (!gl_info->supported[NV_FENCE] && !gl_info->supported[APPLE_FENCE])
843 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
844 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
846 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
848 vtable = &IWineD3DEventQuery_Vtbl;
849 hr = WINED3D_OK;
850 break;
852 case WINED3DQUERYTYPE_VCACHE:
853 case WINED3DQUERYTYPE_RESOURCEMANAGER:
854 case WINED3DQUERYTYPE_VERTEXSTATS:
855 case WINED3DQUERYTYPE_TIMESTAMP:
856 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
857 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
858 case WINED3DQUERYTYPE_PIPELINETIMINGS:
859 case WINED3DQUERYTYPE_INTERFACETIMINGS:
860 case WINED3DQUERYTYPE_VERTEXTIMINGS:
861 case WINED3DQUERYTYPE_PIXELTIMINGS:
862 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
863 case WINED3DQUERYTYPE_CACHEUTILIZATION:
864 default:
865 /* Use the base Query vtable until we have a special one for each query */
866 vtable = &IWineD3DQuery_Vtbl;
867 FIXME("(%p) Unhandled query type %d\n", This, Type);
869 if(NULL == ppQuery || hr != WINED3D_OK) {
870 return hr;
873 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
874 if(!object)
876 ERR("Out of memory\n");
877 *ppQuery = NULL;
878 return WINED3DERR_OUTOFVIDEOMEMORY;
881 object->lpVtbl = vtable;
882 object->type = Type;
883 object->state = QUERY_CREATED;
884 object->device = This;
885 object->parent = parent;
886 object->ref = 1;
888 *ppQuery = (IWineD3DQuery *)object;
890 /* allocated the 'extended' data based on the type of query requested */
891 switch(Type){
892 case WINED3DQUERYTYPE_OCCLUSION:
893 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
894 ((struct wined3d_occlusion_query *)object->extendedData)->context = NULL;
895 break;
897 case WINED3DQUERYTYPE_EVENT:
898 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query));
899 ((struct wined3d_event_query *)object->extendedData)->context = NULL;
900 break;
902 case WINED3DQUERYTYPE_VCACHE:
903 case WINED3DQUERYTYPE_RESOURCEMANAGER:
904 case WINED3DQUERYTYPE_VERTEXSTATS:
905 case WINED3DQUERYTYPE_TIMESTAMP:
906 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
907 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
908 case WINED3DQUERYTYPE_PIPELINETIMINGS:
909 case WINED3DQUERYTYPE_INTERFACETIMINGS:
910 case WINED3DQUERYTYPE_VERTEXTIMINGS:
911 case WINED3DQUERYTYPE_PIXELTIMINGS:
912 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
913 case WINED3DQUERYTYPE_CACHEUTILIZATION:
914 default:
915 object->extendedData = 0;
916 FIXME("(%p) Unhandled query type %d\n",This , Type);
918 TRACE("(%p) : Created Query %p\n", This, object);
919 return WINED3D_OK;
922 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
923 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
924 IUnknown *parent, WINED3DSURFTYPE surface_type)
926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
927 IWineD3DSwapChainImpl *object;
928 HRESULT hr;
930 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
931 iface, present_parameters, swapchain, parent, surface_type);
933 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
934 if (!object)
936 ERR("Failed to allocate swapchain memory.\n");
937 return E_OUTOFMEMORY;
940 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
941 if (FAILED(hr))
943 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
944 HeapFree(GetProcessHeap(), 0, object);
945 return hr;
948 TRACE("Created swapchain %p.\n", object);
949 *swapchain = (IWineD3DSwapChain *)object;
951 return WINED3D_OK;
954 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
955 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
957 TRACE("(%p)\n", This);
959 return This->NumberOfSwapChains;
962 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
964 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
966 if(iSwapChain < This->NumberOfSwapChains) {
967 *pSwapChain = This->swapchains[iSwapChain];
968 IWineD3DSwapChain_AddRef(*pSwapChain);
969 TRACE("(%p) returning %p\n", This, *pSwapChain);
970 return WINED3D_OK;
971 } else {
972 TRACE("Swapchain out of range\n");
973 *pSwapChain = NULL;
974 return WINED3DERR_INVALIDCALL;
978 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
979 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
980 const WINED3DVERTEXELEMENT *elements, UINT element_count)
982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
983 IWineD3DVertexDeclarationImpl *object = NULL;
984 HRESULT hr;
986 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
987 iface, declaration, parent, elements, element_count);
989 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
990 if(!object)
992 ERR("Failed to allocate vertex declaration memory.\n");
993 return E_OUTOFMEMORY;
996 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
997 if (FAILED(hr))
999 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1000 HeapFree(GetProcessHeap(), 0, object);
1001 return hr;
1004 TRACE("Created vertex declaration %p.\n", object);
1005 *declaration = (IWineD3DVertexDeclaration *)object;
1007 return WINED3D_OK;
1010 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1011 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1013 unsigned int idx, idx2;
1014 unsigned int offset;
1015 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1016 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1017 BOOL has_blend_idx = has_blend &&
1018 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1019 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1020 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1021 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1022 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1023 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1024 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1026 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1027 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1028 WINED3DVERTEXELEMENT *elements = NULL;
1030 unsigned int size;
1031 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1032 if (has_blend_idx) num_blends--;
1034 /* Compute declaration size */
1035 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1036 has_psize + has_diffuse + has_specular + num_textures;
1038 /* convert the declaration */
1039 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1040 if (!elements) return ~0U;
1042 idx = 0;
1043 if (has_pos) {
1044 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1045 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1046 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1048 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1049 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1050 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1052 else {
1053 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1054 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1056 elements[idx].usage_idx = 0;
1057 idx++;
1059 if (has_blend && (num_blends > 0)) {
1060 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1061 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1062 else {
1063 switch(num_blends) {
1064 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1065 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1066 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1067 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1068 default:
1069 ERR("Unexpected amount of blend values: %u\n", num_blends);
1072 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1073 elements[idx].usage_idx = 0;
1074 idx++;
1076 if (has_blend_idx) {
1077 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1078 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1079 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1080 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1081 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1082 else
1083 elements[idx].format = WINED3DFMT_R32_FLOAT;
1084 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1085 elements[idx].usage_idx = 0;
1086 idx++;
1088 if (has_normal) {
1089 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1090 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1091 elements[idx].usage_idx = 0;
1092 idx++;
1094 if (has_psize) {
1095 elements[idx].format = WINED3DFMT_R32_FLOAT;
1096 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1097 elements[idx].usage_idx = 0;
1098 idx++;
1100 if (has_diffuse) {
1101 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1102 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1103 elements[idx].usage_idx = 0;
1104 idx++;
1106 if (has_specular) {
1107 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1108 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1109 elements[idx].usage_idx = 1;
1110 idx++;
1112 for (idx2 = 0; idx2 < num_textures; idx2++) {
1113 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1114 switch (numcoords) {
1115 case WINED3DFVF_TEXTUREFORMAT1:
1116 elements[idx].format = WINED3DFMT_R32_FLOAT;
1117 break;
1118 case WINED3DFVF_TEXTUREFORMAT2:
1119 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1120 break;
1121 case WINED3DFVF_TEXTUREFORMAT3:
1122 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1123 break;
1124 case WINED3DFVF_TEXTUREFORMAT4:
1125 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1126 break;
1128 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1129 elements[idx].usage_idx = idx2;
1130 idx++;
1133 /* Now compute offsets, and initialize the rest of the fields */
1134 for (idx = 0, offset = 0; idx < size; ++idx)
1136 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1137 elements[idx].input_slot = 0;
1138 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1139 elements[idx].offset = offset;
1140 offset += format_desc->component_count * format_desc->component_size;
1143 *ppVertexElements = elements;
1144 return size;
1147 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1148 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1149 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1152 WINED3DVERTEXELEMENT *elements;
1153 unsigned int size;
1154 DWORD hr;
1156 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1158 size = ConvertFvfToDeclaration(This, fvf, &elements);
1159 if (size == ~0U) return E_OUTOFMEMORY;
1161 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1162 HeapFree(GetProcessHeap(), 0, elements);
1163 return hr;
1166 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1167 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1168 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1169 const struct wined3d_parent_ops *parent_ops)
1171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1172 IWineD3DVertexShaderImpl *object;
1173 HRESULT hr;
1175 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1176 if (!object)
1178 ERR("Failed to allocate shader memory.\n");
1179 return E_OUTOFMEMORY;
1182 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1183 if (FAILED(hr))
1185 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1186 HeapFree(GetProcessHeap(), 0, object);
1187 return hr;
1190 TRACE("Created vertex shader %p.\n", object);
1191 *ppVertexShader = (IWineD3DVertexShader *)object;
1193 return WINED3D_OK;
1196 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1197 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1198 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1199 const struct wined3d_parent_ops *parent_ops)
1201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1202 IWineD3DPixelShaderImpl *object;
1203 HRESULT hr;
1205 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1206 if (!object)
1208 ERR("Failed to allocate shader memory.\n");
1209 return E_OUTOFMEMORY;
1212 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1213 if (FAILED(hr))
1215 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1216 HeapFree(GetProcessHeap(), 0, object);
1217 return hr;
1220 TRACE("Created pixel shader %p.\n", object);
1221 *ppPixelShader = (IWineD3DPixelShader *)object;
1223 return WINED3D_OK;
1226 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1227 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1230 IWineD3DPaletteImpl *object;
1231 HRESULT hr;
1232 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1234 /* Create the new object */
1235 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1236 if(!object) {
1237 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1238 return E_OUTOFMEMORY;
1241 object->lpVtbl = &IWineD3DPalette_Vtbl;
1242 object->ref = 1;
1243 object->Flags = Flags;
1244 object->parent = Parent;
1245 object->device = This;
1246 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1247 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1249 if(!object->hpal) {
1250 HeapFree( GetProcessHeap(), 0, object);
1251 return E_OUTOFMEMORY;
1254 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1255 if(FAILED(hr)) {
1256 IWineD3DPalette_Release((IWineD3DPalette *) object);
1257 return hr;
1260 *Palette = (IWineD3DPalette *) object;
1262 return WINED3D_OK;
1265 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1266 HBITMAP hbm;
1267 BITMAP bm;
1268 HRESULT hr;
1269 HDC dcb = NULL, dcs = NULL;
1270 WINEDDCOLORKEY colorkey;
1272 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1273 if(hbm)
1275 GetObjectA(hbm, sizeof(BITMAP), &bm);
1276 dcb = CreateCompatibleDC(NULL);
1277 if(!dcb) goto out;
1278 SelectObject(dcb, hbm);
1280 else
1282 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1283 * couldn't be loaded
1285 memset(&bm, 0, sizeof(bm));
1286 bm.bmWidth = 32;
1287 bm.bmHeight = 32;
1290 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1291 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1292 NULL, &wined3d_null_parent_ops);
1293 if(FAILED(hr)) {
1294 ERR("Wine logo requested, but failed to create surface\n");
1295 goto out;
1298 if(dcb) {
1299 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1300 if(FAILED(hr)) goto out;
1301 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1302 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1304 colorkey.dwColorSpaceLowValue = 0;
1305 colorkey.dwColorSpaceHighValue = 0;
1306 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1307 } else {
1308 /* Fill the surface with a white color to show that wined3d is there */
1309 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1312 out:
1313 if(dcb) {
1314 DeleteDC(dcb);
1316 if(hbm) {
1317 DeleteObject(hbm);
1319 return;
1322 /* Context activation is done by the caller. */
1323 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1325 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1326 unsigned int i;
1327 /* Under DirectX you can have texture stage operations even if no texture is
1328 bound, whereas opengl will only do texture operations when a valid texture is
1329 bound. We emulate this by creating dummy textures and binding them to each
1330 texture stage, but disable all stages by default. Hence if a stage is enabled
1331 then the default texture will kick in until replaced by a SetTexture call */
1332 ENTER_GL();
1334 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1336 /* The dummy texture does not have client storage backing */
1337 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1338 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1341 for (i = 0; i < gl_info->limits.textures; ++i)
1343 GLubyte white = 255;
1345 /* Make appropriate texture active */
1346 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1347 checkGLcall("glActiveTextureARB");
1349 /* Generate an opengl texture name */
1350 glGenTextures(1, &This->dummyTextureName[i]);
1351 checkGLcall("glGenTextures");
1352 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1354 /* Generate a dummy 2d texture (not using 1d because they cause many
1355 * DRI drivers fall back to sw) */
1356 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1357 checkGLcall("glBindTexture");
1359 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1360 checkGLcall("glTexImage2D");
1363 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1365 /* Reenable because if supported it is enabled by default */
1366 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1367 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1370 LEAVE_GL();
1373 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1374 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1377 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1378 IWineD3DSwapChainImpl *swapchain = NULL;
1379 struct wined3d_context *context;
1380 HRESULT hr;
1381 DWORD state;
1382 unsigned int i;
1384 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1386 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1387 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1389 /* TODO: Test if OpenGL is compiled in and loaded */
1391 TRACE("(%p) : Creating stateblock\n", This);
1392 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1393 hr = IWineD3DDevice_CreateStateBlock(iface,
1394 WINED3DSBT_INIT,
1395 (IWineD3DStateBlock **)&This->stateBlock,
1396 NULL);
1397 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1398 WARN("Failed to create stateblock\n");
1399 goto err_out;
1401 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1402 This->updateStateBlock = This->stateBlock;
1403 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1405 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1406 sizeof(IWineD3DSurface *) * gl_info->limits.buffers);
1407 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1408 sizeof(GLenum) * gl_info->limits.buffers);
1410 This->NumberOfPalettes = 1;
1411 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1412 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1413 ERR("Out of memory!\n");
1414 hr = E_OUTOFMEMORY;
1415 goto err_out;
1417 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1418 if(!This->palettes[0]) {
1419 ERR("Out of memory!\n");
1420 hr = E_OUTOFMEMORY;
1421 goto err_out;
1423 for (i = 0; i < 256; ++i) {
1424 This->palettes[0][i].peRed = 0xFF;
1425 This->palettes[0][i].peGreen = 0xFF;
1426 This->palettes[0][i].peBlue = 0xFF;
1427 This->palettes[0][i].peFlags = 0xFF;
1429 This->currentPalette = 0;
1431 /* Initialize the texture unit mapping to a 1:1 mapping */
1432 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1434 if (state < gl_info->limits.fragment_samplers)
1436 This->texUnitMap[state] = state;
1437 This->rev_tex_unit_map[state] = state;
1438 } else {
1439 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1440 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1444 /* Setup the implicit swapchain. This also initializes a context. */
1445 TRACE("Creating implicit swapchain\n");
1446 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1447 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1448 if (FAILED(hr))
1450 WARN("Failed to create implicit swapchain\n");
1451 goto err_out;
1454 This->NumberOfSwapChains = 1;
1455 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1456 if(!This->swapchains) {
1457 ERR("Out of memory!\n");
1458 goto err_out;
1460 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1462 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1463 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1464 This->render_targets[0] = swapchain->backBuffer[0];
1466 else {
1467 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1468 This->render_targets[0] = swapchain->frontBuffer;
1470 IWineD3DSurface_AddRef(This->render_targets[0]);
1472 /* Depth Stencil support */
1473 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1474 if (NULL != This->stencilBufferTarget) {
1475 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1478 hr = This->shader_backend->shader_alloc_private(iface);
1479 if(FAILED(hr)) {
1480 TRACE("Shader private data couldn't be allocated\n");
1481 goto err_out;
1483 hr = This->frag_pipe->alloc_private(iface);
1484 if(FAILED(hr)) {
1485 TRACE("Fragment pipeline private data couldn't be allocated\n");
1486 goto err_out;
1488 hr = This->blitter->alloc_private(iface);
1489 if(FAILED(hr)) {
1490 TRACE("Blitter private data couldn't be allocated\n");
1491 goto err_out;
1494 /* Set up some starting GL setup */
1496 /* Setup all the devices defaults */
1497 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1499 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1501 create_dummy_textures(This);
1503 ENTER_GL();
1505 /* Initialize the current view state */
1506 This->view_ident = 1;
1507 This->contexts[0]->last_was_rhw = 0;
1508 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1509 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1511 switch(wined3d_settings.offscreen_rendering_mode) {
1512 case ORM_FBO:
1513 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1514 break;
1516 case ORM_PBUFFER:
1517 This->offscreenBuffer = GL_BACK;
1518 break;
1520 case ORM_BACKBUFFER:
1522 if (context_get_current()->aux_buffers > 0)
1524 TRACE("Using auxilliary buffer for offscreen rendering\n");
1525 This->offscreenBuffer = GL_AUX0;
1526 } else {
1527 TRACE("Using back buffer for offscreen rendering\n");
1528 This->offscreenBuffer = GL_BACK;
1533 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1534 LEAVE_GL();
1536 context_release(context);
1538 /* Clear the screen */
1539 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1540 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1541 0x00, 1.0f, 0);
1543 This->d3d_initialized = TRUE;
1545 if(wined3d_settings.logo) {
1546 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1548 This->highest_dirty_ps_const = 0;
1549 This->highest_dirty_vs_const = 0;
1550 return WINED3D_OK;
1552 err_out:
1553 HeapFree(GetProcessHeap(), 0, This->render_targets);
1554 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1555 HeapFree(GetProcessHeap(), 0, This->swapchains);
1556 This->NumberOfSwapChains = 0;
1557 if(This->palettes) {
1558 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1559 HeapFree(GetProcessHeap(), 0, This->palettes);
1561 This->NumberOfPalettes = 0;
1562 if(swapchain) {
1563 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1565 if(This->stateBlock) {
1566 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1567 This->stateBlock = NULL;
1569 if (This->blit_priv) {
1570 This->blitter->free_private(iface);
1572 if (This->fragment_priv) {
1573 This->frag_pipe->free_private(iface);
1575 if (This->shader_priv) {
1576 This->shader_backend->shader_free_private(iface);
1578 return hr;
1581 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1582 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1585 IWineD3DSwapChainImpl *swapchain = NULL;
1586 HRESULT hr;
1588 /* Setup the implicit swapchain */
1589 TRACE("Creating implicit swapchain\n");
1590 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1591 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1592 if (FAILED(hr))
1594 WARN("Failed to create implicit swapchain\n");
1595 goto err_out;
1598 This->NumberOfSwapChains = 1;
1599 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1600 if(!This->swapchains) {
1601 ERR("Out of memory!\n");
1602 goto err_out;
1604 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1605 return WINED3D_OK;
1607 err_out:
1608 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1609 return hr;
1612 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1614 IWineD3DResource_UnLoad(resource);
1615 IWineD3DResource_Release(resource);
1616 return WINED3D_OK;
1619 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1620 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1623 const struct wined3d_gl_info *gl_info;
1624 struct wined3d_context *context;
1625 int sampler;
1626 UINT i;
1627 TRACE("(%p)\n", This);
1629 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1631 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1632 * it was created. Thus make sure a context is active for the glDelete* calls
1634 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1635 gl_info = context->gl_info;
1637 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1639 /* Unload resources */
1640 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1642 TRACE("Deleting high order patches\n");
1643 for(i = 0; i < PATCHMAP_SIZE; i++) {
1644 struct list *e1, *e2;
1645 struct WineD3DRectPatch *patch;
1646 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1647 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1648 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1652 /* Delete the palette conversion shader if it is around */
1653 if(This->paletteConversionShader) {
1654 ENTER_GL();
1655 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
1656 LEAVE_GL();
1657 This->paletteConversionShader = 0;
1660 /* Delete the pbuffer context if there is any */
1661 if(This->pbufferContext) context_destroy(This, This->pbufferContext);
1663 /* Delete the mouse cursor texture */
1664 if(This->cursorTexture) {
1665 ENTER_GL();
1666 glDeleteTextures(1, &This->cursorTexture);
1667 LEAVE_GL();
1668 This->cursorTexture = 0;
1671 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1672 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1674 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1675 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1678 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1679 * private data, it might contain opengl pointers
1681 if(This->depth_blt_texture) {
1682 ENTER_GL();
1683 glDeleteTextures(1, &This->depth_blt_texture);
1684 LEAVE_GL();
1685 This->depth_blt_texture = 0;
1687 if (This->depth_blt_rb) {
1688 ENTER_GL();
1689 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1690 LEAVE_GL();
1691 This->depth_blt_rb = 0;
1692 This->depth_blt_rb_w = 0;
1693 This->depth_blt_rb_h = 0;
1696 /* Release the update stateblock */
1697 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1698 if(This->updateStateBlock != This->stateBlock)
1699 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1701 This->updateStateBlock = NULL;
1703 { /* because were not doing proper internal refcounts releasing the primary state block
1704 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1705 to set this->stateBlock = NULL; first */
1706 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1707 This->stateBlock = NULL;
1709 /* Release the stateblock */
1710 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1711 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1715 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1716 This->blitter->free_private(iface);
1717 This->frag_pipe->free_private(iface);
1718 This->shader_backend->shader_free_private(iface);
1720 /* Release the buffers (with sanity checks)*/
1721 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1722 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1723 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
1724 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
1726 This->stencilBufferTarget = NULL;
1728 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1729 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1730 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1732 TRACE("Setting rendertarget to NULL\n");
1733 This->render_targets[0] = NULL;
1735 if (This->auto_depth_stencil_buffer) {
1736 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
1738 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1740 This->auto_depth_stencil_buffer = NULL;
1743 context_release(context);
1745 for(i=0; i < This->NumberOfSwapChains; i++) {
1746 TRACE("Releasing the implicit swapchain %d\n", i);
1747 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1748 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1752 HeapFree(GetProcessHeap(), 0, This->swapchains);
1753 This->swapchains = NULL;
1754 This->NumberOfSwapChains = 0;
1756 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1757 HeapFree(GetProcessHeap(), 0, This->palettes);
1758 This->palettes = NULL;
1759 This->NumberOfPalettes = 0;
1761 HeapFree(GetProcessHeap(), 0, This->render_targets);
1762 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1763 This->render_targets = NULL;
1764 This->draw_buffers = NULL;
1766 This->d3d_initialized = FALSE;
1767 return WINED3D_OK;
1770 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1772 unsigned int i;
1774 for(i=0; i < This->NumberOfSwapChains; i++) {
1775 TRACE("Releasing the implicit swapchain %d\n", i);
1776 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1777 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1781 HeapFree(GetProcessHeap(), 0, This->swapchains);
1782 This->swapchains = NULL;
1783 This->NumberOfSwapChains = 0;
1784 return WINED3D_OK;
1787 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1788 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1789 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1791 * There is no way to deactivate thread safety once it is enabled.
1793 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1796 /*For now just store the flag(needed in case of ddraw) */
1797 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1799 return;
1802 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1803 const WINED3DDISPLAYMODE* pMode) {
1804 DEVMODEW devmode;
1805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1806 LONG ret;
1807 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1808 RECT clip_rc;
1810 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1812 /* Resize the screen even without a window:
1813 * The app could have unset it with SetCooperativeLevel, but not called
1814 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1815 * but we don't have any hwnd
1818 memset(&devmode, 0, sizeof(devmode));
1819 devmode.dmSize = sizeof(devmode);
1820 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1821 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1822 devmode.dmPelsWidth = pMode->Width;
1823 devmode.dmPelsHeight = pMode->Height;
1825 devmode.dmDisplayFrequency = pMode->RefreshRate;
1826 if (pMode->RefreshRate != 0) {
1827 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1830 /* Only change the mode if necessary */
1831 if( (This->ddraw_width == pMode->Width) &&
1832 (This->ddraw_height == pMode->Height) &&
1833 (This->ddraw_format == pMode->Format) &&
1834 (pMode->RefreshRate == 0) ) {
1835 return WINED3D_OK;
1838 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1839 if (ret != DISP_CHANGE_SUCCESSFUL) {
1840 if(devmode.dmDisplayFrequency != 0) {
1841 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1842 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1843 devmode.dmDisplayFrequency = 0;
1844 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1846 if(ret != DISP_CHANGE_SUCCESSFUL) {
1847 return WINED3DERR_NOTAVAILABLE;
1851 /* Store the new values */
1852 This->ddraw_width = pMode->Width;
1853 This->ddraw_height = pMode->Height;
1854 This->ddraw_format = pMode->Format;
1856 /* And finally clip mouse to our screen */
1857 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1858 ClipCursor(&clip_rc);
1860 return WINED3D_OK;
1863 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1865 *ppD3D = This->wined3d;
1866 TRACE("Returning %p.\n", *ppD3D);
1867 IWineD3D_AddRef(*ppD3D);
1868 return WINED3D_OK;
1871 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1874 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1875 (This->adapter->TextureRam/(1024*1024)),
1876 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
1877 /* return simulated texture memory left */
1878 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
1881 /*****
1882 * Get / Set Stream Source
1883 *****/
1884 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
1885 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
1887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1888 IWineD3DBuffer *oldSrc;
1890 if (StreamNumber >= MAX_STREAMS) {
1891 WARN("Stream out of range %d\n", StreamNumber);
1892 return WINED3DERR_INVALIDCALL;
1893 } else if(OffsetInBytes & 0x3) {
1894 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
1895 return WINED3DERR_INVALIDCALL;
1898 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
1899 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
1901 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
1903 if(oldSrc == pStreamData &&
1904 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
1905 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
1906 TRACE("Application is setting the old values over, nothing to do\n");
1907 return WINED3D_OK;
1910 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
1911 if (pStreamData) {
1912 This->updateStateBlock->streamStride[StreamNumber] = Stride;
1913 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
1916 /* Handle recording of state blocks */
1917 if (This->isRecordingState) {
1918 TRACE("Recording... not performing anything\n");
1919 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
1920 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
1921 return WINED3D_OK;
1924 if (pStreamData != NULL) {
1925 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
1926 IWineD3DBuffer_AddRef(pStreamData);
1928 if (oldSrc != NULL) {
1929 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
1930 IWineD3DBuffer_Release(oldSrc);
1933 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
1935 return WINED3D_OK;
1938 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
1939 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
1941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1943 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
1944 This->stateBlock->streamSource[StreamNumber],
1945 This->stateBlock->streamOffset[StreamNumber],
1946 This->stateBlock->streamStride[StreamNumber]);
1948 if (StreamNumber >= MAX_STREAMS) {
1949 WARN("Stream out of range %d\n", StreamNumber);
1950 return WINED3DERR_INVALIDCALL;
1952 *pStream = This->stateBlock->streamSource[StreamNumber];
1953 *pStride = This->stateBlock->streamStride[StreamNumber];
1954 if (pOffset) {
1955 *pOffset = This->stateBlock->streamOffset[StreamNumber];
1958 if (*pStream != NULL) {
1959 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
1961 return WINED3D_OK;
1964 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
1965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1966 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
1967 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
1969 /* Verify input at least in d3d9 this is invalid*/
1970 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
1971 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
1972 return WINED3DERR_INVALIDCALL;
1974 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
1975 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
1976 return WINED3DERR_INVALIDCALL;
1978 if( Divider == 0 ){
1979 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
1980 return WINED3DERR_INVALIDCALL;
1983 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
1984 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
1986 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
1987 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
1989 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
1990 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
1991 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
1994 return WINED3D_OK;
1997 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
1998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2000 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2001 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2003 TRACE("(%p) : returning %d\n", This, *Divider);
2005 return WINED3D_OK;
2008 /*****
2009 * Get / Set & Multiply Transform
2010 *****/
2011 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2014 /* Most of this routine, comments included copied from ddraw tree initially: */
2015 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2017 /* Handle recording of state blocks */
2018 if (This->isRecordingState) {
2019 TRACE("Recording... not performing anything\n");
2020 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2021 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2022 return WINED3D_OK;
2026 * If the new matrix is the same as the current one,
2027 * we cut off any further processing. this seems to be a reasonable
2028 * optimization because as was noticed, some apps (warcraft3 for example)
2029 * tend towards setting the same matrix repeatedly for some reason.
2031 * From here on we assume that the new matrix is different, wherever it matters.
2033 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2034 TRACE("The app is setting the same matrix over again\n");
2035 return WINED3D_OK;
2036 } else {
2037 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2041 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2042 where ViewMat = Camera space, WorldMat = world space.
2044 In OpenGL, camera and world space is combined into GL_MODELVIEW
2045 matrix. The Projection matrix stay projection matrix.
2048 /* Capture the times we can just ignore the change for now */
2049 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2050 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2051 /* Handled by the state manager */
2054 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2055 return WINED3D_OK;
2058 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2059 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2060 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2061 *pMatrix = This->stateBlock->transforms[State];
2062 return WINED3D_OK;
2065 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2066 const WINED3DMATRIX *mat = NULL;
2067 WINED3DMATRIX temp;
2069 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2070 * below means it will be recorded in a state block change, but it
2071 * works regardless where it is recorded.
2072 * If this is found to be wrong, change to StateBlock.
2074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2075 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2077 if (State <= HIGHEST_TRANSFORMSTATE)
2079 mat = &This->updateStateBlock->transforms[State];
2080 } else {
2081 FIXME("Unhandled transform state!!\n");
2084 multiply_matrix(&temp, mat, pMatrix);
2086 /* Apply change via set transform - will reapply to eg. lights this way */
2087 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2090 /*****
2091 * Get / Set Light
2092 *****/
2093 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2094 you can reference any indexes you want as long as that number max are enabled at any
2095 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2096 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2097 but when recording, just build a chain pretty much of commands to be replayed. */
2099 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2100 float rho;
2101 struct wined3d_light_info *object = NULL;
2102 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2103 struct list *e;
2105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2106 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2108 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2109 * the gl driver.
2111 if(!pLight) {
2112 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2113 return WINED3DERR_INVALIDCALL;
2116 switch(pLight->Type) {
2117 case WINED3DLIGHT_POINT:
2118 case WINED3DLIGHT_SPOT:
2119 case WINED3DLIGHT_PARALLELPOINT:
2120 case WINED3DLIGHT_GLSPOT:
2121 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2122 * most wanted
2124 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2126 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2127 return WINED3DERR_INVALIDCALL;
2129 break;
2131 case WINED3DLIGHT_DIRECTIONAL:
2132 /* Ignores attenuation */
2133 break;
2135 default:
2136 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2137 return WINED3DERR_INVALIDCALL;
2140 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2142 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2143 if(object->OriginalIndex == Index) break;
2144 object = NULL;
2147 if(!object) {
2148 TRACE("Adding new light\n");
2149 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2150 if(!object) {
2151 ERR("Out of memory error when allocating a light\n");
2152 return E_OUTOFMEMORY;
2154 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2155 object->glIndex = -1;
2156 object->OriginalIndex = Index;
2159 /* Initialize the object */
2160 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,
2161 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2162 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2163 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2164 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2165 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2166 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2168 /* Save away the information */
2169 object->OriginalParms = *pLight;
2171 switch (pLight->Type) {
2172 case WINED3DLIGHT_POINT:
2173 /* Position */
2174 object->lightPosn[0] = pLight->Position.x;
2175 object->lightPosn[1] = pLight->Position.y;
2176 object->lightPosn[2] = pLight->Position.z;
2177 object->lightPosn[3] = 1.0f;
2178 object->cutoff = 180.0f;
2179 /* FIXME: Range */
2180 break;
2182 case WINED3DLIGHT_DIRECTIONAL:
2183 /* Direction */
2184 object->lightPosn[0] = -pLight->Direction.x;
2185 object->lightPosn[1] = -pLight->Direction.y;
2186 object->lightPosn[2] = -pLight->Direction.z;
2187 object->lightPosn[3] = 0.0f;
2188 object->exponent = 0.0f;
2189 object->cutoff = 180.0f;
2190 break;
2192 case WINED3DLIGHT_SPOT:
2193 /* Position */
2194 object->lightPosn[0] = pLight->Position.x;
2195 object->lightPosn[1] = pLight->Position.y;
2196 object->lightPosn[2] = pLight->Position.z;
2197 object->lightPosn[3] = 1.0f;
2199 /* Direction */
2200 object->lightDirn[0] = pLight->Direction.x;
2201 object->lightDirn[1] = pLight->Direction.y;
2202 object->lightDirn[2] = pLight->Direction.z;
2203 object->lightDirn[3] = 1.0f;
2206 * opengl-ish and d3d-ish spot lights use too different models for the
2207 * light "intensity" as a function of the angle towards the main light direction,
2208 * so we only can approximate very roughly.
2209 * however spot lights are rather rarely used in games (if ever used at all).
2210 * furthermore if still used, probably nobody pays attention to such details.
2212 if (pLight->Falloff == 0) {
2213 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2214 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2215 * will always be 1.0 for both of them, and we don't have to care for the
2216 * rest of the rather complex calculation
2218 object->exponent = 0.0f;
2219 } else {
2220 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2221 if (rho < 0.0001f) rho = 0.0001f;
2222 object->exponent = -0.3f/logf(cosf(rho/2));
2224 if (object->exponent > 128.0f)
2226 object->exponent = 128.0f;
2228 object->cutoff = pLight->Phi*90/M_PI;
2230 /* FIXME: Range */
2231 break;
2233 default:
2234 FIXME("Unrecognized light type %d\n", pLight->Type);
2237 /* Update the live definitions if the light is currently assigned a glIndex */
2238 if (object->glIndex != -1 && !This->isRecordingState) {
2239 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2241 return WINED3D_OK;
2244 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2246 struct wined3d_light_info *lightInfo = NULL;
2247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2248 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2249 struct list *e;
2250 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2252 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2254 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2255 if(lightInfo->OriginalIndex == Index) break;
2256 lightInfo = NULL;
2259 if (lightInfo == NULL) {
2260 TRACE("Light information requested but light not defined\n");
2261 return WINED3DERR_INVALIDCALL;
2264 *pLight = lightInfo->OriginalParms;
2265 return WINED3D_OK;
2268 /*****
2269 * Get / Set Light Enable
2270 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2271 *****/
2272 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2274 struct wined3d_light_info *lightInfo = NULL;
2275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2276 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2277 struct list *e;
2278 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2280 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2282 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2283 if(lightInfo->OriginalIndex == Index) break;
2284 lightInfo = NULL;
2286 TRACE("Found light: %p\n", lightInfo);
2288 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2289 if (lightInfo == NULL) {
2291 TRACE("Light enabled requested but light not defined, so defining one!\n");
2292 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2294 /* Search for it again! Should be fairly quick as near head of list */
2295 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2297 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2298 if(lightInfo->OriginalIndex == Index) break;
2299 lightInfo = NULL;
2301 if (lightInfo == NULL) {
2302 FIXME("Adding default lights has failed dismally\n");
2303 return WINED3DERR_INVALIDCALL;
2307 if(!Enable) {
2308 if(lightInfo->glIndex != -1) {
2309 if(!This->isRecordingState) {
2310 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2313 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2314 lightInfo->glIndex = -1;
2315 } else {
2316 TRACE("Light already disabled, nothing to do\n");
2318 lightInfo->enabled = FALSE;
2319 } else {
2320 lightInfo->enabled = TRUE;
2321 if (lightInfo->glIndex != -1) {
2322 /* nop */
2323 TRACE("Nothing to do as light was enabled\n");
2324 } else {
2325 int i;
2326 /* Find a free gl light */
2327 for(i = 0; i < This->maxConcurrentLights; i++) {
2328 if(This->updateStateBlock->activeLights[i] == NULL) {
2329 This->updateStateBlock->activeLights[i] = lightInfo;
2330 lightInfo->glIndex = i;
2331 break;
2334 if(lightInfo->glIndex == -1) {
2335 /* Our tests show that Windows returns D3D_OK in this situation, even with
2336 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2337 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2338 * as well for those lights.
2340 * TODO: Test how this affects rendering
2342 WARN("Too many concurrently active lights\n");
2343 return WINED3D_OK;
2346 /* i == lightInfo->glIndex */
2347 if(!This->isRecordingState) {
2348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2353 return WINED3D_OK;
2356 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2358 struct wined3d_light_info *lightInfo = NULL;
2359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2360 struct list *e;
2361 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2362 TRACE("(%p) : for idx(%d)\n", This, Index);
2364 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2366 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2367 if(lightInfo->OriginalIndex == Index) break;
2368 lightInfo = NULL;
2371 if (lightInfo == NULL) {
2372 TRACE("Light enabled state requested but light not defined\n");
2373 return WINED3DERR_INVALIDCALL;
2375 /* true is 128 according to SetLightEnable */
2376 *pEnable = lightInfo->enabled ? 128 : 0;
2377 return WINED3D_OK;
2380 /*****
2381 * Get / Set Clip Planes
2382 *****/
2383 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2385 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2387 /* Validate Index */
2388 if (Index >= This->adapter->gl_info.limits.clipplanes)
2390 TRACE("Application has requested clipplane this device doesn't support\n");
2391 return WINED3DERR_INVALIDCALL;
2394 This->updateStateBlock->changed.clipplane |= 1 << Index;
2396 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2397 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2398 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2399 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2400 TRACE("Application is setting old values over, nothing to do\n");
2401 return WINED3D_OK;
2404 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2405 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2406 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2407 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2409 /* Handle recording of state blocks */
2410 if (This->isRecordingState) {
2411 TRACE("Recording... not performing anything\n");
2412 return WINED3D_OK;
2415 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2417 return WINED3D_OK;
2420 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2422 TRACE("(%p) : for idx %d\n", This, Index);
2424 /* Validate Index */
2425 if (Index >= This->adapter->gl_info.limits.clipplanes)
2427 TRACE("Application has requested clipplane this device doesn't support\n");
2428 return WINED3DERR_INVALIDCALL;
2431 pPlane[0] = This->stateBlock->clipplane[Index][0];
2432 pPlane[1] = This->stateBlock->clipplane[Index][1];
2433 pPlane[2] = This->stateBlock->clipplane[Index][2];
2434 pPlane[3] = This->stateBlock->clipplane[Index][3];
2435 return WINED3D_OK;
2438 /*****
2439 * Get / Set Clip Plane Status
2440 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2441 *****/
2442 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2444 FIXME("(%p) : stub\n", This);
2445 if (NULL == pClipStatus) {
2446 return WINED3DERR_INVALIDCALL;
2448 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2449 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2450 return WINED3D_OK;
2453 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2455 FIXME("(%p) : stub\n", This);
2456 if (NULL == pClipStatus) {
2457 return WINED3DERR_INVALIDCALL;
2459 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2460 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2461 return WINED3D_OK;
2464 /*****
2465 * Get / Set Material
2466 *****/
2467 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2470 This->updateStateBlock->changed.material = TRUE;
2471 This->updateStateBlock->material = *pMaterial;
2473 /* Handle recording of state blocks */
2474 if (This->isRecordingState) {
2475 TRACE("Recording... not performing anything\n");
2476 return WINED3D_OK;
2479 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2480 return WINED3D_OK;
2483 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2485 *pMaterial = This->updateStateBlock->material;
2486 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2487 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2488 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2489 pMaterial->Ambient.b, pMaterial->Ambient.a);
2490 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2491 pMaterial->Specular.b, pMaterial->Specular.a);
2492 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2493 pMaterial->Emissive.b, pMaterial->Emissive.a);
2494 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2496 return WINED3D_OK;
2499 /*****
2500 * Get / Set Indices
2501 *****/
2502 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2503 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2506 IWineD3DBuffer *oldIdxs;
2508 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2509 oldIdxs = This->updateStateBlock->pIndexData;
2511 This->updateStateBlock->changed.indices = TRUE;
2512 This->updateStateBlock->pIndexData = pIndexData;
2513 This->updateStateBlock->IndexFmt = fmt;
2515 /* Handle recording of state blocks */
2516 if (This->isRecordingState) {
2517 TRACE("Recording... not performing anything\n");
2518 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2519 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2520 return WINED3D_OK;
2523 if(oldIdxs != pIndexData) {
2524 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2525 if(pIndexData) {
2526 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2527 IWineD3DBuffer_AddRef(pIndexData);
2529 if(oldIdxs) {
2530 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2531 IWineD3DBuffer_Release(oldIdxs);
2535 return WINED3D_OK;
2538 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2540 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2542 *ppIndexData = This->stateBlock->pIndexData;
2544 /* up ref count on ppindexdata */
2545 if (*ppIndexData) {
2546 IWineD3DBuffer_AddRef(*ppIndexData);
2547 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2548 }else{
2549 TRACE("(%p) No index data set\n", This);
2551 TRACE("Returning %p\n", *ppIndexData);
2553 return WINED3D_OK;
2556 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2557 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2559 TRACE("(%p)->(%d)\n", This, BaseIndex);
2561 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2562 TRACE("Application is setting the old value over, nothing to do\n");
2563 return WINED3D_OK;
2566 This->updateStateBlock->baseVertexIndex = BaseIndex;
2568 if (This->isRecordingState) {
2569 TRACE("Recording... not performing anything\n");
2570 return WINED3D_OK;
2572 /* The base vertex index affects the stream sources */
2573 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2574 return WINED3D_OK;
2577 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2579 TRACE("(%p) : base_index %p\n", This, base_index);
2581 *base_index = This->stateBlock->baseVertexIndex;
2583 TRACE("Returning %u\n", *base_index);
2585 return WINED3D_OK;
2588 /*****
2589 * Get / Set Viewports
2590 *****/
2591 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2594 TRACE("(%p)\n", This);
2595 This->updateStateBlock->changed.viewport = TRUE;
2596 This->updateStateBlock->viewport = *pViewport;
2598 /* Handle recording of state blocks */
2599 if (This->isRecordingState) {
2600 TRACE("Recording... not performing anything\n");
2601 return WINED3D_OK;
2604 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2605 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2607 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2608 return WINED3D_OK;
2612 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2614 TRACE("(%p)\n", This);
2615 *pViewport = This->stateBlock->viewport;
2616 return WINED3D_OK;
2619 /*****
2620 * Get / Set Render States
2621 * TODO: Verify against dx9 definitions
2622 *****/
2623 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2626 DWORD oldValue = This->stateBlock->renderState[State];
2628 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2630 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2631 This->updateStateBlock->renderState[State] = Value;
2633 /* Handle recording of state blocks */
2634 if (This->isRecordingState) {
2635 TRACE("Recording... not performing anything\n");
2636 return WINED3D_OK;
2639 /* Compared here and not before the assignment to allow proper stateblock recording */
2640 if(Value == oldValue) {
2641 TRACE("Application is setting the old value over, nothing to do\n");
2642 } else {
2643 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2646 return WINED3D_OK;
2649 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2651 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2652 *pValue = This->stateBlock->renderState[State];
2653 return WINED3D_OK;
2656 /*****
2657 * Get / Set Sampler States
2658 * TODO: Verify against dx9 definitions
2659 *****/
2661 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2663 DWORD oldValue;
2665 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2666 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2668 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2669 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2672 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2673 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2674 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2677 * SetSampler is designed to allow for more than the standard up to 8 textures
2678 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2679 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2681 * http://developer.nvidia.com/object/General_FAQ.html#t6
2683 * There are two new settings for GForce
2684 * the sampler one:
2685 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2686 * and the texture one:
2687 * GL_MAX_TEXTURE_COORDS_ARB.
2688 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2689 ******************/
2691 oldValue = This->stateBlock->samplerState[Sampler][Type];
2692 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2693 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2695 /* Handle recording of state blocks */
2696 if (This->isRecordingState) {
2697 TRACE("Recording... not performing anything\n");
2698 return WINED3D_OK;
2701 if(oldValue == Value) {
2702 TRACE("Application is setting the old value over, nothing to do\n");
2703 return WINED3D_OK;
2706 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2708 return WINED3D_OK;
2711 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2714 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2715 This, Sampler, debug_d3dsamplerstate(Type), Type);
2717 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2718 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2721 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2722 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2723 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2725 *Value = This->stateBlock->samplerState[Sampler][Type];
2726 TRACE("(%p) : Returning %#x\n", This, *Value);
2728 return WINED3D_OK;
2731 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2734 This->updateStateBlock->changed.scissorRect = TRUE;
2735 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2736 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2737 return WINED3D_OK;
2739 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2741 if(This->isRecordingState) {
2742 TRACE("Recording... not performing anything\n");
2743 return WINED3D_OK;
2746 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2748 return WINED3D_OK;
2751 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2754 *pRect = This->updateStateBlock->scissorRect;
2755 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2756 return WINED3D_OK;
2759 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2761 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2763 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2765 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2766 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2768 This->updateStateBlock->vertexDecl = pDecl;
2769 This->updateStateBlock->changed.vertexDecl = TRUE;
2771 if (This->isRecordingState) {
2772 TRACE("Recording... not performing anything\n");
2773 return WINED3D_OK;
2774 } else if(pDecl == oldDecl) {
2775 /* Checked after the assignment to allow proper stateblock recording */
2776 TRACE("Application is setting the old declaration over, nothing to do\n");
2777 return WINED3D_OK;
2780 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2781 return WINED3D_OK;
2784 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2787 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2789 *ppDecl = This->stateBlock->vertexDecl;
2790 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2791 return WINED3D_OK;
2794 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2796 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2798 This->updateStateBlock->vertexShader = pShader;
2799 This->updateStateBlock->changed.vertexShader = TRUE;
2801 if (This->isRecordingState) {
2802 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2803 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2804 TRACE("Recording... not performing anything\n");
2805 return WINED3D_OK;
2806 } else if(oldShader == pShader) {
2807 /* Checked here to allow proper stateblock recording */
2808 TRACE("App is setting the old shader over, nothing to do\n");
2809 return WINED3D_OK;
2812 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2813 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2814 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2816 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2818 return WINED3D_OK;
2821 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2824 if (NULL == ppShader) {
2825 return WINED3DERR_INVALIDCALL;
2827 *ppShader = This->stateBlock->vertexShader;
2828 if( NULL != *ppShader)
2829 IWineD3DVertexShader_AddRef(*ppShader);
2831 TRACE("(%p) : returning %p\n", This, *ppShader);
2832 return WINED3D_OK;
2835 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2836 IWineD3DDevice *iface,
2837 UINT start,
2838 CONST BOOL *srcData,
2839 UINT count) {
2841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2842 unsigned int i, cnt = min(count, MAX_CONST_B - start);
2844 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2845 iface, srcData, start, count);
2847 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
2849 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2850 for (i = 0; i < cnt; i++)
2851 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2853 for (i = start; i < cnt + start; ++i) {
2854 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
2857 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2859 return WINED3D_OK;
2862 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2863 IWineD3DDevice *iface,
2864 UINT start,
2865 BOOL *dstData,
2866 UINT count) {
2868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2869 int cnt = min(count, MAX_CONST_B - start);
2871 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2872 iface, dstData, start, count);
2874 if (dstData == NULL || cnt < 0)
2875 return WINED3DERR_INVALIDCALL;
2877 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2878 return WINED3D_OK;
2881 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2882 IWineD3DDevice *iface,
2883 UINT start,
2884 CONST int *srcData,
2885 UINT count) {
2887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2888 unsigned int i, cnt = min(count, MAX_CONST_I - start);
2890 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2891 iface, srcData, start, count);
2893 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
2895 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2896 for (i = 0; i < cnt; i++)
2897 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2898 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2900 for (i = start; i < cnt + start; ++i) {
2901 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
2904 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2906 return WINED3D_OK;
2909 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2910 IWineD3DDevice *iface,
2911 UINT start,
2912 int *dstData,
2913 UINT count) {
2915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2916 int cnt = min(count, MAX_CONST_I - start);
2918 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2919 iface, dstData, start, count);
2921 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2922 return WINED3DERR_INVALIDCALL;
2924 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
2925 return WINED3D_OK;
2928 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
2929 IWineD3DDevice *iface,
2930 UINT start,
2931 CONST float *srcData,
2932 UINT count) {
2934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2935 UINT i;
2937 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2938 iface, srcData, start, count);
2940 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
2941 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
2942 return WINED3DERR_INVALIDCALL;
2944 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
2945 if(TRACE_ON(d3d)) {
2946 for (i = 0; i < count; i++)
2947 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
2948 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2951 if (!This->isRecordingState)
2953 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
2954 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2957 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
2958 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
2960 return WINED3D_OK;
2963 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
2964 IWineD3DDevice *iface,
2965 UINT start,
2966 float *dstData,
2967 UINT count) {
2969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2970 int cnt = min(count, This->d3d_vshader_constantF - start);
2972 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2973 iface, dstData, start, count);
2975 if (dstData == NULL || cnt < 0)
2976 return WINED3DERR_INVALIDCALL;
2978 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
2979 return WINED3D_OK;
2982 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
2983 DWORD i;
2984 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
2986 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
2990 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
2992 DWORD i = This->rev_tex_unit_map[unit];
2993 DWORD j = This->texUnitMap[stage];
2995 This->texUnitMap[stage] = unit;
2996 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
2998 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3001 This->rev_tex_unit_map[unit] = stage;
3002 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3004 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3008 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3009 int i;
3011 This->fixed_function_usage_map = 0;
3012 for (i = 0; i < MAX_TEXTURES; ++i) {
3013 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3014 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3015 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3016 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3017 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3018 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3019 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3020 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3022 if (color_op == WINED3DTOP_DISABLE) {
3023 /* Not used, and disable higher stages */
3024 break;
3027 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3028 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3029 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3030 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3031 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3032 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3033 This->fixed_function_usage_map |= (1 << i);
3036 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3037 This->fixed_function_usage_map |= (1 << (i + 1));
3042 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3043 unsigned int i, tex;
3044 WORD ffu_map;
3046 device_update_fixed_function_usage_map(This);
3047 ffu_map = This->fixed_function_usage_map;
3049 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3050 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3051 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3053 if (!(ffu_map & 1)) continue;
3055 if (This->texUnitMap[i] != i) {
3056 device_map_stage(This, i, i);
3057 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3058 markTextureStagesDirty(This, i);
3061 return;
3064 /* Now work out the mapping */
3065 tex = 0;
3066 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3068 if (!(ffu_map & 1)) continue;
3070 if (This->texUnitMap[i] != tex) {
3071 device_map_stage(This, i, tex);
3072 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3073 markTextureStagesDirty(This, i);
3076 ++tex;
3080 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3081 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3082 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3083 unsigned int i;
3085 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3086 if (sampler_type[i] && This->texUnitMap[i] != i)
3088 device_map_stage(This, i, i);
3089 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3090 if (i < MAX_TEXTURES) {
3091 markTextureStagesDirty(This, i);
3097 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3098 const DWORD *vshader_sampler_tokens, DWORD unit)
3100 DWORD current_mapping = This->rev_tex_unit_map[unit];
3102 /* Not currently used */
3103 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3105 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3106 /* Used by a fragment sampler */
3108 if (!pshader_sampler_tokens) {
3109 /* No pixel shader, check fixed function */
3110 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3113 /* Pixel shader, check the shader's sampler map */
3114 return !pshader_sampler_tokens[current_mapping];
3117 /* Used by a vertex sampler */
3118 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3121 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3122 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3123 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3124 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3125 int start = min(MAX_COMBINED_SAMPLERS, This->adapter->gl_info.limits.combined_samplers) - 1;
3126 int i;
3128 if (ps) {
3129 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3131 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3132 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3133 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3136 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3137 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3138 if (vshader_sampler_type[i])
3140 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3142 /* Already mapped somewhere */
3143 continue;
3146 while (start >= 0) {
3147 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3149 device_map_stage(This, vsampler_idx, start);
3150 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3152 --start;
3153 break;
3156 --start;
3162 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3163 BOOL vs = use_vs(This->stateBlock);
3164 BOOL ps = use_ps(This->stateBlock);
3166 * Rules are:
3167 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3168 * that would be really messy and require shader recompilation
3169 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3170 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3172 if (ps) {
3173 device_map_psamplers(This);
3174 } else {
3175 device_map_fixed_function_samplers(This);
3178 if (vs) {
3179 device_map_vsamplers(This, ps);
3183 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3185 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3186 This->updateStateBlock->pixelShader = pShader;
3187 This->updateStateBlock->changed.pixelShader = TRUE;
3189 /* Handle recording of state blocks */
3190 if (This->isRecordingState) {
3191 TRACE("Recording... not performing anything\n");
3194 if (This->isRecordingState) {
3195 TRACE("Recording... not performing anything\n");
3196 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3197 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3198 return WINED3D_OK;
3201 if(pShader == oldShader) {
3202 TRACE("App is setting the old pixel shader over, nothing to do\n");
3203 return WINED3D_OK;
3206 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3207 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3209 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3210 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3212 return WINED3D_OK;
3215 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3218 if (NULL == ppShader) {
3219 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3220 return WINED3DERR_INVALIDCALL;
3223 *ppShader = This->stateBlock->pixelShader;
3224 if (NULL != *ppShader) {
3225 IWineD3DPixelShader_AddRef(*ppShader);
3227 TRACE("(%p) : returning %p\n", This, *ppShader);
3228 return WINED3D_OK;
3231 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3232 IWineD3DDevice *iface,
3233 UINT start,
3234 CONST BOOL *srcData,
3235 UINT count) {
3237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3238 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3240 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3241 iface, srcData, start, count);
3243 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3245 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3246 for (i = 0; i < cnt; i++)
3247 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3249 for (i = start; i < cnt + start; ++i) {
3250 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3253 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3255 return WINED3D_OK;
3258 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3259 IWineD3DDevice *iface,
3260 UINT start,
3261 BOOL *dstData,
3262 UINT count) {
3264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3265 int cnt = min(count, MAX_CONST_B - start);
3267 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3268 iface, dstData, start, count);
3270 if (dstData == NULL || cnt < 0)
3271 return WINED3DERR_INVALIDCALL;
3273 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3274 return WINED3D_OK;
3277 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3278 IWineD3DDevice *iface,
3279 UINT start,
3280 CONST int *srcData,
3281 UINT count) {
3283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3284 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3286 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3287 iface, srcData, start, count);
3289 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3291 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3292 for (i = 0; i < cnt; i++)
3293 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3294 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3296 for (i = start; i < cnt + start; ++i) {
3297 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3300 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3302 return WINED3D_OK;
3305 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3306 IWineD3DDevice *iface,
3307 UINT start,
3308 int *dstData,
3309 UINT count) {
3311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3312 int cnt = min(count, MAX_CONST_I - start);
3314 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3315 iface, dstData, start, count);
3317 if (dstData == NULL || cnt < 0)
3318 return WINED3DERR_INVALIDCALL;
3320 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3321 return WINED3D_OK;
3324 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3325 IWineD3DDevice *iface,
3326 UINT start,
3327 CONST float *srcData,
3328 UINT count) {
3330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3331 UINT i;
3333 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3334 iface, srcData, start, count);
3336 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3337 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3338 return WINED3DERR_INVALIDCALL;
3340 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3341 if(TRACE_ON(d3d)) {
3342 for (i = 0; i < count; i++)
3343 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3344 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3347 if (!This->isRecordingState)
3349 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3350 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3353 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3354 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3356 return WINED3D_OK;
3359 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3360 IWineD3DDevice *iface,
3361 UINT start,
3362 float *dstData,
3363 UINT count) {
3365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3366 int cnt = min(count, This->d3d_pshader_constantF - start);
3368 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3369 iface, dstData, start, count);
3371 if (dstData == NULL || cnt < 0)
3372 return WINED3DERR_INVALIDCALL;
3374 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3375 return WINED3D_OK;
3378 /* Context activation is done by the caller. */
3379 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3380 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3381 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3382 DWORD DestFVF)
3384 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3385 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3386 unsigned int i;
3387 WINED3DVIEWPORT vp;
3388 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3389 BOOL doClip;
3390 DWORD numTextures;
3392 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3394 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3397 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3399 ERR("Source has no position mask\n");
3400 return WINED3DERR_INVALIDCALL;
3403 /* We might access VBOs from this code, so hold the lock */
3404 ENTER_GL();
3406 if (dest->resource.allocatedMemory == NULL) {
3407 buffer_get_sysmem(dest);
3410 /* Get a pointer into the destination vbo(create one if none exists) and
3411 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3413 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3415 dest->flags |= WINED3D_BUFFER_CREATEBO;
3416 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3419 if (dest->buffer_object)
3421 unsigned char extrabytes = 0;
3422 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3423 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3424 * this may write 4 extra bytes beyond the area that should be written
3426 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3427 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3428 if(!dest_conv_addr) {
3429 ERR("Out of memory\n");
3430 /* Continue without storing converted vertices */
3432 dest_conv = dest_conv_addr;
3435 /* Should I clip?
3436 * a) WINED3DRS_CLIPPING is enabled
3437 * b) WINED3DVOP_CLIP is passed
3439 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3440 static BOOL warned = FALSE;
3442 * The clipping code is not quite correct. Some things need
3443 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3444 * so disable clipping for now.
3445 * (The graphics in Half-Life are broken, and my processvertices
3446 * test crashes with IDirect3DDevice3)
3447 doClip = TRUE;
3449 doClip = FALSE;
3450 if(!warned) {
3451 warned = TRUE;
3452 FIXME("Clipping is broken and disabled for now\n");
3454 } else doClip = FALSE;
3455 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3457 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3458 WINED3DTS_VIEW,
3459 &view_mat);
3460 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3461 WINED3DTS_PROJECTION,
3462 &proj_mat);
3463 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3464 WINED3DTS_WORLDMATRIX(0),
3465 &world_mat);
3467 TRACE("View mat:\n");
3468 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);
3469 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);
3470 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);
3471 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);
3473 TRACE("Proj mat:\n");
3474 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);
3475 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);
3476 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);
3477 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);
3479 TRACE("World mat:\n");
3480 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);
3481 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);
3482 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);
3483 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);
3485 /* Get the viewport */
3486 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3487 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3488 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3490 multiply_matrix(&mat,&view_mat,&world_mat);
3491 multiply_matrix(&mat,&proj_mat,&mat);
3493 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3495 for (i = 0; i < dwCount; i+= 1) {
3496 unsigned int tex_index;
3498 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3499 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3500 /* The position first */
3501 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3502 const float *p = (const float *)(element->data + i * element->stride);
3503 float x, y, z, rhw;
3504 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3506 /* Multiplication with world, view and projection matrix */
3507 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);
3508 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);
3509 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);
3510 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);
3512 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3514 /* WARNING: The following things are taken from d3d7 and were not yet checked
3515 * against d3d8 or d3d9!
3518 /* Clipping conditions: From msdn
3520 * A vertex is clipped if it does not match the following requirements
3521 * -rhw < x <= rhw
3522 * -rhw < y <= rhw
3523 * 0 < z <= rhw
3524 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3526 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3527 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3531 if( !doClip ||
3532 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3533 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3534 ( rhw > eps ) ) ) {
3536 /* "Normal" viewport transformation (not clipped)
3537 * 1) The values are divided by rhw
3538 * 2) The y axis is negative, so multiply it with -1
3539 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3540 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3541 * 4) Multiply x with Width/2 and add Width/2
3542 * 5) The same for the height
3543 * 6) Add the viewpoint X and Y to the 2D coordinates and
3544 * The minimum Z value to z
3545 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3547 * Well, basically it's simply a linear transformation into viewport
3548 * coordinates
3551 x /= rhw;
3552 y /= rhw;
3553 z /= rhw;
3555 y *= -1;
3557 x *= vp.Width / 2;
3558 y *= vp.Height / 2;
3559 z *= vp.MaxZ - vp.MinZ;
3561 x += vp.Width / 2 + vp.X;
3562 y += vp.Height / 2 + vp.Y;
3563 z += vp.MinZ;
3565 rhw = 1 / rhw;
3566 } else {
3567 /* That vertex got clipped
3568 * Contrary to OpenGL it is not dropped completely, it just
3569 * undergoes a different calculation.
3571 TRACE("Vertex got clipped\n");
3572 x += rhw;
3573 y += rhw;
3575 x /= 2;
3576 y /= 2;
3578 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3579 * outside of the main vertex buffer memory. That needs some more
3580 * investigation...
3584 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3587 ( (float *) dest_ptr)[0] = x;
3588 ( (float *) dest_ptr)[1] = y;
3589 ( (float *) dest_ptr)[2] = z;
3590 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3592 dest_ptr += 3 * sizeof(float);
3594 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3595 dest_ptr += sizeof(float);
3598 if(dest_conv) {
3599 float w = 1 / rhw;
3600 ( (float *) dest_conv)[0] = x * w;
3601 ( (float *) dest_conv)[1] = y * w;
3602 ( (float *) dest_conv)[2] = z * w;
3603 ( (float *) dest_conv)[3] = w;
3605 dest_conv += 3 * sizeof(float);
3607 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3608 dest_conv += sizeof(float);
3612 if (DestFVF & WINED3DFVF_PSIZE) {
3613 dest_ptr += sizeof(DWORD);
3614 if(dest_conv) dest_conv += sizeof(DWORD);
3616 if (DestFVF & WINED3DFVF_NORMAL) {
3617 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3618 const float *normal = (const float *)(element->data + i * element->stride);
3619 /* AFAIK this should go into the lighting information */
3620 FIXME("Didn't expect the destination to have a normal\n");
3621 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3622 if(dest_conv) {
3623 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3627 if (DestFVF & WINED3DFVF_DIFFUSE) {
3628 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3629 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3630 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3632 static BOOL warned = FALSE;
3634 if(!warned) {
3635 ERR("No diffuse color in source, but destination has one\n");
3636 warned = TRUE;
3639 *( (DWORD *) dest_ptr) = 0xffffffff;
3640 dest_ptr += sizeof(DWORD);
3642 if(dest_conv) {
3643 *( (DWORD *) dest_conv) = 0xffffffff;
3644 dest_conv += sizeof(DWORD);
3647 else {
3648 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3649 if(dest_conv) {
3650 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3651 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3652 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3653 dest_conv += sizeof(DWORD);
3658 if (DestFVF & WINED3DFVF_SPECULAR)
3660 /* What's the color value in the feedback buffer? */
3661 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3662 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3663 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3665 static BOOL warned = FALSE;
3667 if(!warned) {
3668 ERR("No specular color in source, but destination has one\n");
3669 warned = TRUE;
3672 *( (DWORD *) dest_ptr) = 0xFF000000;
3673 dest_ptr += sizeof(DWORD);
3675 if(dest_conv) {
3676 *( (DWORD *) dest_conv) = 0xFF000000;
3677 dest_conv += sizeof(DWORD);
3680 else {
3681 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3682 if(dest_conv) {
3683 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3684 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3685 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3686 dest_conv += sizeof(DWORD);
3691 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3692 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3693 const float *tex_coord = (const float *)(element->data + i * element->stride);
3694 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3696 ERR("No source texture, but destination requests one\n");
3697 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3698 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3700 else {
3701 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3702 if(dest_conv) {
3703 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3709 if(dest_conv) {
3710 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3711 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3712 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3713 dwCount * get_flexible_vertex_size(DestFVF),
3714 dest_conv_addr));
3715 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3716 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3719 LEAVE_GL();
3721 return WINED3D_OK;
3723 #undef copy_and_next
3725 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3726 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3727 DWORD DestFVF)
3729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3730 struct wined3d_stream_info stream_info;
3731 struct wined3d_context *context;
3732 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3733 HRESULT hr;
3735 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3737 if(pVertexDecl) {
3738 ERR("Output vertex declaration not implemented yet\n");
3741 /* Need any context to write to the vbo. */
3742 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
3744 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3745 * control the streamIsUP flag, thus restore it afterwards.
3747 This->stateBlock->streamIsUP = FALSE;
3748 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3749 This->stateBlock->streamIsUP = streamWasUP;
3751 if(vbo || SrcStartIndex) {
3752 unsigned int i;
3753 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3754 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3756 * Also get the start index in, but only loop over all elements if there's something to add at all.
3758 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3760 struct wined3d_stream_info_element *e;
3762 if (!(stream_info.use_map & (1 << i))) continue;
3764 e = &stream_info.elements[i];
3765 if (e->buffer_object)
3767 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3768 e->buffer_object = 0;
3769 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3770 ENTER_GL();
3771 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3772 vb->buffer_object = 0;
3773 LEAVE_GL();
3775 if (e->data) e->data += e->stride * SrcStartIndex;
3779 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3780 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3782 context_release(context);
3784 return hr;
3787 /*****
3788 * Get / Set Texture Stage States
3789 * TODO: Verify against dx9 definitions
3790 *****/
3791 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3793 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3795 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3797 if (Stage >= MAX_TEXTURES) {
3798 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
3799 return WINED3D_OK;
3802 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3803 This->updateStateBlock->textureState[Stage][Type] = Value;
3805 if (This->isRecordingState) {
3806 TRACE("Recording... not performing anything\n");
3807 return WINED3D_OK;
3810 /* Checked after the assignments to allow proper stateblock recording */
3811 if(oldValue == Value) {
3812 TRACE("App is setting the old value over, nothing to do\n");
3813 return WINED3D_OK;
3816 if(Stage > This->stateBlock->lowest_disabled_stage &&
3817 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3818 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3819 * Changes in other states are important on disabled stages too
3821 return WINED3D_OK;
3824 if(Type == WINED3DTSS_COLOROP) {
3825 unsigned int i;
3827 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3828 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3829 * they have to be disabled
3831 * The current stage is dirtified below.
3833 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3834 TRACE("Additionally dirtifying stage %u\n", i);
3835 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3837 This->stateBlock->lowest_disabled_stage = Stage;
3838 TRACE("New lowest disabled: %u\n", Stage);
3839 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3840 /* Previously disabled stage enabled. Stages above it may need enabling
3841 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3842 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3844 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3847 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
3849 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3850 break;
3852 TRACE("Additionally dirtifying stage %u due to enable\n", i);
3853 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3855 This->stateBlock->lowest_disabled_stage = i;
3856 TRACE("New lowest disabled: %u\n", i);
3860 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3862 return WINED3D_OK;
3865 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3867 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3868 *pValue = This->updateStateBlock->textureState[Stage][Type];
3869 return WINED3D_OK;
3872 /*****
3873 * Get / Set Texture
3874 *****/
3875 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
3876 DWORD stage, IWineD3DBaseTexture *texture)
3878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3879 IWineD3DBaseTexture *prev;
3881 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
3883 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
3884 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3886 /* Windows accepts overflowing this array... we do not. */
3887 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
3889 WARN("Ignoring invalid stage %u.\n", stage);
3890 return WINED3D_OK;
3893 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
3894 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
3896 WARN("Rejecting attempt to set scratch texture.\n");
3897 return WINED3DERR_INVALIDCALL;
3900 This->updateStateBlock->changed.textures |= 1 << stage;
3902 prev = This->updateStateBlock->textures[stage];
3903 TRACE("Previous texture %p.\n", prev);
3905 if (texture == prev)
3907 TRACE("App is setting the same texture again, nothing to do.\n");
3908 return WINED3D_OK;
3911 TRACE("Setting new texture to %p.\n", texture);
3912 This->updateStateBlock->textures[stage] = texture;
3914 if (This->isRecordingState)
3916 TRACE("Recording... not performing anything\n");
3918 if (texture) IWineD3DBaseTexture_AddRef(texture);
3919 if (prev) IWineD3DBaseTexture_Release(prev);
3921 return WINED3D_OK;
3924 if (texture)
3926 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
3927 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
3928 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
3930 IWineD3DBaseTexture_AddRef(texture);
3932 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
3934 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3937 if (!prev && stage < MAX_TEXTURES)
3939 /* The source arguments for color and alpha ops have different
3940 * meanings when a NULL texture is bound, so the COLOROP and
3941 * ALPHAOP have to be dirtified. */
3942 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
3943 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
3946 if (bind_count == 1) t->baseTexture.sampler = stage;
3949 if (prev)
3951 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
3952 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
3954 IWineD3DBaseTexture_Release(prev);
3956 if (!texture && stage < MAX_TEXTURES)
3958 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
3959 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
3962 if (bind_count && t->baseTexture.sampler == stage)
3964 unsigned int i;
3966 /* Search for other stages the texture is bound to. Shouldn't
3967 * happen if applications bind textures to a single stage only. */
3968 TRACE("Searching for other stages the texture is bound to.\n");
3969 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
3971 if (This->updateStateBlock->textures[i] == prev)
3973 TRACE("Texture is also bound to stage %u.\n", i);
3974 t->baseTexture.sampler = i;
3975 break;
3981 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
3983 return WINED3D_OK;
3986 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
3987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3989 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
3991 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
3992 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3995 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
3996 ERR("Current stage overflows textures array (stage %d)\n", Stage);
3997 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4000 *ppTexture=This->stateBlock->textures[Stage];
4001 if (*ppTexture)
4002 IWineD3DBaseTexture_AddRef(*ppTexture);
4004 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4006 return WINED3D_OK;
4009 /*****
4010 * Get Back Buffer
4011 *****/
4012 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4013 IWineD3DSurface **ppBackBuffer) {
4014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4015 IWineD3DSwapChain *swapChain;
4016 HRESULT hr;
4018 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4020 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4021 if (hr == WINED3D_OK) {
4022 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4023 IWineD3DSwapChain_Release(swapChain);
4024 } else {
4025 *ppBackBuffer = NULL;
4027 return hr;
4030 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4032 WARN("(%p) : stub, calling idirect3d for now\n", This);
4033 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4036 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4038 IWineD3DSwapChain *swapChain;
4039 HRESULT hr;
4041 if(iSwapChain > 0) {
4042 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4043 if (hr == WINED3D_OK) {
4044 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4045 IWineD3DSwapChain_Release(swapChain);
4046 } else {
4047 FIXME("(%p) Error getting display mode\n", This);
4049 } else {
4050 /* Don't read the real display mode,
4051 but return the stored mode instead. X11 can't change the color
4052 depth, and some apps are pretty angry if they SetDisplayMode from
4053 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4055 Also don't relay to the swapchain because with ddraw it's possible
4056 that there isn't a swapchain at all */
4057 pMode->Width = This->ddraw_width;
4058 pMode->Height = This->ddraw_height;
4059 pMode->Format = This->ddraw_format;
4060 pMode->RefreshRate = 0;
4061 hr = WINED3D_OK;
4064 return hr;
4067 /*****
4068 * Stateblock related functions
4069 *****/
4071 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4072 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4073 IWineD3DStateBlock *stateblock;
4074 HRESULT hr;
4076 TRACE("(%p)\n", This);
4078 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4080 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4081 if (FAILED(hr)) return hr;
4083 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4084 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4085 This->isRecordingState = TRUE;
4087 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4089 return WINED3D_OK;
4092 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4094 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4096 if (!This->isRecordingState) {
4097 WARN("(%p) not recording! returning error\n", This);
4098 *ppStateBlock = NULL;
4099 return WINED3DERR_INVALIDCALL;
4102 stateblock_init_contained_states(object);
4104 *ppStateBlock = (IWineD3DStateBlock*) object;
4105 This->isRecordingState = FALSE;
4106 This->updateStateBlock = This->stateBlock;
4107 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4108 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4109 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4110 return WINED3D_OK;
4113 /*****
4114 * Scene related functions
4115 *****/
4116 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4117 /* At the moment we have no need for any functionality at the beginning
4118 of a scene */
4119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4120 TRACE("(%p)\n", This);
4122 if(This->inScene) {
4123 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4124 return WINED3DERR_INVALIDCALL;
4126 This->inScene = TRUE;
4127 return WINED3D_OK;
4130 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4133 struct wined3d_context *context;
4135 TRACE("(%p)\n", This);
4137 if(!This->inScene) {
4138 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4139 return WINED3DERR_INVALIDCALL;
4142 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4143 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4144 wglFlush();
4145 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4146 * fails. */
4147 context_release(context);
4149 This->inScene = FALSE;
4150 return WINED3D_OK;
4153 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4154 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4155 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4157 IWineD3DSwapChain *swapChain = NULL;
4158 int i;
4159 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4161 TRACE("(%p) Presenting the frame\n", This);
4163 for(i = 0 ; i < swapchains ; i ++) {
4165 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4166 TRACE("presentinng chain %d, %p\n", i, swapChain);
4167 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4168 IWineD3DSwapChain_Release(swapChain);
4171 return WINED3D_OK;
4174 /* Not called from the VTable (internal subroutine) */
4175 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4176 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4177 float Z, DWORD Stencil) {
4178 GLbitfield glMask = 0;
4179 unsigned int i;
4180 WINED3DRECT curRect;
4181 RECT vp_rect;
4182 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4183 UINT drawable_width, drawable_height;
4184 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4185 IWineD3DSwapChainImpl *swapchain = NULL;
4186 struct wined3d_context *context;
4188 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4189 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4190 * for the cleared parts, and the untouched parts.
4192 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4193 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4194 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4195 * checking all this if the dest surface is in the drawable anyway.
4197 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4198 while(1) {
4199 if(vp->X != 0 || vp->Y != 0 ||
4200 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4201 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4202 break;
4204 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4205 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4206 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4207 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4208 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4209 break;
4211 if(Count > 0 && pRects && (
4212 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4213 pRects[0].x2 < target->currentDesc.Width ||
4214 pRects[0].y2 < target->currentDesc.Height)) {
4215 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4216 break;
4218 break;
4222 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4224 target->get_drawable_size(context, &drawable_width, &drawable_height);
4226 ENTER_GL();
4228 /* Only set the values up once, as they are not changing */
4229 if (Flags & WINED3DCLEAR_STENCIL) {
4230 glClearStencil(Stencil);
4231 checkGLcall("glClearStencil");
4232 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4233 glStencilMask(0xFFFFFFFF);
4236 if (Flags & WINED3DCLEAR_ZBUFFER) {
4237 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4238 glDepthMask(GL_TRUE);
4239 glClearDepth(Z);
4240 checkGLcall("glClearDepth");
4241 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4242 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4244 if (vp->X != 0 || vp->Y != 0 ||
4245 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4246 surface_load_ds_location(This->stencilBufferTarget, context, location);
4248 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4249 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4250 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4251 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4252 surface_load_ds_location(This->stencilBufferTarget, context, location);
4254 else if (Count > 0 && pRects && (
4255 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4256 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4257 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4258 surface_load_ds_location(This->stencilBufferTarget, context, location);
4262 if (Flags & WINED3DCLEAR_TARGET) {
4263 TRACE("Clearing screen with glClear to color %x\n", Color);
4264 glClearColor(D3DCOLOR_R(Color),
4265 D3DCOLOR_G(Color),
4266 D3DCOLOR_B(Color),
4267 D3DCOLOR_A(Color));
4268 checkGLcall("glClearColor");
4270 /* Clear ALL colors! */
4271 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4272 glMask = glMask | GL_COLOR_BUFFER_BIT;
4275 vp_rect.left = vp->X;
4276 vp_rect.top = vp->Y;
4277 vp_rect.right = vp->X + vp->Width;
4278 vp_rect.bottom = vp->Y + vp->Height;
4279 if (!(Count > 0 && pRects)) {
4280 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4281 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4283 if (context->render_offscreen)
4285 glScissor(vp_rect.left, vp_rect.top,
4286 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4287 } else {
4288 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4289 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4291 checkGLcall("glScissor");
4292 glClear(glMask);
4293 checkGLcall("glClear");
4294 } else {
4295 /* Now process each rect in turn */
4296 for (i = 0; i < Count; i++) {
4297 /* Note gl uses lower left, width/height */
4298 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4299 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4300 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4302 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4303 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4304 curRect.x1, (target->currentDesc.Height - curRect.y2),
4305 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4307 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4308 * The rectangle is not cleared, no error is returned, but further rectanlges are
4309 * still cleared if they are valid
4311 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4312 TRACE("Rectangle with negative dimensions, ignoring\n");
4313 continue;
4316 if (context->render_offscreen)
4318 glScissor(curRect.x1, curRect.y1,
4319 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4320 } else {
4321 glScissor(curRect.x1, drawable_height - curRect.y2,
4322 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4324 checkGLcall("glScissor");
4326 glClear(glMask);
4327 checkGLcall("glClear");
4331 /* Restore the old values (why..?) */
4332 if (Flags & WINED3DCLEAR_STENCIL) {
4333 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4335 if (Flags & WINED3DCLEAR_TARGET) {
4336 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4337 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4338 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4339 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4340 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4342 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4343 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4345 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4347 if (Flags & WINED3DCLEAR_ZBUFFER) {
4348 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4349 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4350 surface_modify_ds_location(This->stencilBufferTarget, location);
4353 LEAVE_GL();
4355 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
4356 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
4357 wglFlush();
4359 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
4362 context_release(context);
4364 return WINED3D_OK;
4367 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4368 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4370 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4372 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4373 Count, pRects, Flags, Color, Z, Stencil);
4375 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4376 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4377 /* TODO: What about depth stencil buffers without stencil bits? */
4378 return WINED3DERR_INVALIDCALL;
4381 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4384 /*****
4385 * Drawing functions
4386 *****/
4388 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4389 WINED3DPRIMITIVETYPE primitive_type)
4391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4393 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4395 This->updateStateBlock->changed.primitive_type = TRUE;
4396 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4399 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4400 WINED3DPRIMITIVETYPE *primitive_type)
4402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4404 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4406 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4408 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4411 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4415 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4417 if(!This->stateBlock->vertexDecl) {
4418 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4419 return WINED3DERR_INVALIDCALL;
4422 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4423 if(This->stateBlock->streamIsUP) {
4424 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4425 This->stateBlock->streamIsUP = FALSE;
4428 if(This->stateBlock->loadBaseVertexIndex != 0) {
4429 This->stateBlock->loadBaseVertexIndex = 0;
4430 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4432 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4433 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4434 return WINED3D_OK;
4437 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4440 UINT idxStride = 2;
4441 IWineD3DBuffer *pIB;
4442 GLuint vbo;
4444 pIB = This->stateBlock->pIndexData;
4445 if (!pIB) {
4446 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4447 * without an index buffer set. (The first time at least...)
4448 * D3D8 simply dies, but I doubt it can do much harm to return
4449 * D3DERR_INVALIDCALL there as well. */
4450 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4451 return WINED3DERR_INVALIDCALL;
4454 if(!This->stateBlock->vertexDecl) {
4455 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4456 return WINED3DERR_INVALIDCALL;
4459 if(This->stateBlock->streamIsUP) {
4460 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4461 This->stateBlock->streamIsUP = FALSE;
4463 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4465 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4467 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4468 idxStride = 2;
4469 } else {
4470 idxStride = 4;
4473 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4474 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4475 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4478 drawPrimitive(iface, index_count, startIndex, idxStride,
4479 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4481 return WINED3D_OK;
4484 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4485 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4488 IWineD3DBuffer *vb;
4490 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4491 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4493 if(!This->stateBlock->vertexDecl) {
4494 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4495 return WINED3DERR_INVALIDCALL;
4498 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4499 vb = This->stateBlock->streamSource[0];
4500 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4501 if (vb) IWineD3DBuffer_Release(vb);
4502 This->stateBlock->streamOffset[0] = 0;
4503 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4504 This->stateBlock->streamIsUP = TRUE;
4505 This->stateBlock->loadBaseVertexIndex = 0;
4507 /* TODO: Only mark dirty if drawing from a different UP address */
4508 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4510 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4512 /* MSDN specifies stream zero settings must be set to NULL */
4513 This->stateBlock->streamStride[0] = 0;
4514 This->stateBlock->streamSource[0] = NULL;
4516 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4517 * the new stream sources or use UP drawing again
4519 return WINED3D_OK;
4522 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4523 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4524 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4526 int idxStride;
4527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4528 IWineD3DBuffer *vb;
4529 IWineD3DBuffer *ib;
4531 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4532 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4534 if(!This->stateBlock->vertexDecl) {
4535 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4536 return WINED3DERR_INVALIDCALL;
4539 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4540 idxStride = 2;
4541 } else {
4542 idxStride = 4;
4545 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4546 vb = This->stateBlock->streamSource[0];
4547 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4548 if (vb) IWineD3DBuffer_Release(vb);
4549 This->stateBlock->streamIsUP = TRUE;
4550 This->stateBlock->streamOffset[0] = 0;
4551 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4553 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4554 This->stateBlock->baseVertexIndex = 0;
4555 This->stateBlock->loadBaseVertexIndex = 0;
4556 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4557 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4558 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4560 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4562 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4563 This->stateBlock->streamSource[0] = NULL;
4564 This->stateBlock->streamStride[0] = 0;
4565 ib = This->stateBlock->pIndexData;
4566 if(ib) {
4567 IWineD3DBuffer_Release(ib);
4568 This->stateBlock->pIndexData = NULL;
4570 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4571 * SetStreamSource to specify a vertex buffer
4574 return WINED3D_OK;
4577 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4578 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4582 /* Mark the state dirty until we have nicer tracking
4583 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4584 * that value.
4586 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4587 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4588 This->stateBlock->baseVertexIndex = 0;
4589 This->up_strided = DrawPrimStrideData;
4590 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4591 This->up_strided = NULL;
4592 return WINED3D_OK;
4595 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4596 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4597 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4600 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4602 /* Mark the state dirty until we have nicer tracking
4603 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4604 * that value.
4606 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4607 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4608 This->stateBlock->streamIsUP = TRUE;
4609 This->stateBlock->baseVertexIndex = 0;
4610 This->up_strided = DrawPrimStrideData;
4611 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4612 This->up_strided = NULL;
4613 return WINED3D_OK;
4616 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
4617 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
4618 * not callable by the app directly no parameter validation checks are needed here.
4620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4621 WINED3DLOCKED_BOX src;
4622 WINED3DLOCKED_BOX dst;
4623 HRESULT hr;
4624 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
4626 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4627 * dirtification to improve loading performance.
4629 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4630 if(FAILED(hr)) return hr;
4631 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4632 if(FAILED(hr)) {
4633 IWineD3DVolume_UnlockBox(pSourceVolume);
4634 return hr;
4637 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4639 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4640 if(FAILED(hr)) {
4641 IWineD3DVolume_UnlockBox(pSourceVolume);
4642 } else {
4643 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4645 return hr;
4648 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4649 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4651 unsigned int level_count, i;
4652 WINED3DRESOURCETYPE type;
4653 HRESULT hr;
4655 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4657 /* Verify that the source and destination textures are non-NULL. */
4658 if (!src_texture || !dst_texture)
4660 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4661 return WINED3DERR_INVALIDCALL;
4664 if (src_texture == dst_texture)
4666 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4667 return WINED3DERR_INVALIDCALL;
4670 /* Verify that the source and destination textures are the same type. */
4671 type = IWineD3DBaseTexture_GetType(src_texture);
4672 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4674 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4675 return WINED3DERR_INVALIDCALL;
4678 /* Check that both textures have the identical numbers of levels. */
4679 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4680 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4682 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4683 return WINED3DERR_INVALIDCALL;
4686 /* Make sure that the destination texture is loaded. */
4687 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4689 /* Update every surface level of the texture. */
4690 switch (type)
4692 case WINED3DRTYPE_TEXTURE:
4694 IWineD3DSurface *src_surface;
4695 IWineD3DSurface *dst_surface;
4697 for (i = 0; i < level_count; ++i)
4699 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4700 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4701 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4702 IWineD3DSurface_Release(dst_surface);
4703 IWineD3DSurface_Release(src_surface);
4704 if (FAILED(hr))
4706 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4707 return hr;
4710 break;
4713 case WINED3DRTYPE_CUBETEXTURE:
4715 IWineD3DSurface *src_surface;
4716 IWineD3DSurface *dst_surface;
4717 WINED3DCUBEMAP_FACES face;
4719 for (i = 0; i < level_count; ++i)
4721 /* Update each cube face. */
4722 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4724 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4725 face, i, &src_surface);
4726 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4727 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4728 face, i, &dst_surface);
4729 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4730 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4731 IWineD3DSurface_Release(dst_surface);
4732 IWineD3DSurface_Release(src_surface);
4733 if (FAILED(hr))
4735 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4736 return hr;
4740 break;
4743 case WINED3DRTYPE_VOLUMETEXTURE:
4745 IWineD3DVolume *src_volume;
4746 IWineD3DVolume *dst_volume;
4748 for (i = 0; i < level_count; ++i)
4750 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4751 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4752 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4753 IWineD3DVolume_Release(dst_volume);
4754 IWineD3DVolume_Release(src_volume);
4755 if (FAILED(hr))
4757 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4758 return hr;
4761 break;
4764 default:
4765 FIXME("Unsupported texture type %#x.\n", type);
4766 return WINED3DERR_INVALIDCALL;
4769 return WINED3D_OK;
4772 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4773 IWineD3DSwapChain *swapChain;
4774 HRESULT hr;
4775 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4776 if(hr == WINED3D_OK) {
4777 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4778 IWineD3DSwapChain_Release(swapChain);
4780 return hr;
4783 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4785 IWineD3DBaseTextureImpl *texture;
4786 DWORD i;
4788 TRACE("(%p) : %p\n", This, pNumPasses);
4790 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4791 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
4792 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4793 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4795 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
4796 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4797 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4800 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
4801 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
4803 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
4804 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4805 return E_FAIL;
4807 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
4808 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4809 return E_FAIL;
4811 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
4812 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
4813 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4814 return E_FAIL;
4818 /* return a sensible default */
4819 *pNumPasses = 1;
4821 TRACE("returning D3D_OK\n");
4822 return WINED3D_OK;
4825 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
4827 int i;
4829 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4831 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
4832 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
4833 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
4835 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
4840 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4842 int j;
4843 UINT NewSize;
4844 PALETTEENTRY **palettes;
4846 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4848 if (PaletteNumber >= MAX_PALETTES) {
4849 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4850 return WINED3DERR_INVALIDCALL;
4853 if (PaletteNumber >= This->NumberOfPalettes) {
4854 NewSize = This->NumberOfPalettes;
4855 do {
4856 NewSize *= 2;
4857 } while(PaletteNumber >= NewSize);
4858 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
4859 if (!palettes) {
4860 ERR("Out of memory!\n");
4861 return E_OUTOFMEMORY;
4863 This->palettes = palettes;
4864 This->NumberOfPalettes = NewSize;
4867 if (!This->palettes[PaletteNumber]) {
4868 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
4869 if (!This->palettes[PaletteNumber]) {
4870 ERR("Out of memory!\n");
4871 return E_OUTOFMEMORY;
4875 for (j = 0; j < 256; ++j) {
4876 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4877 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4878 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4879 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4881 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
4882 TRACE("(%p) : returning\n", This);
4883 return WINED3D_OK;
4886 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4888 int j;
4889 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4890 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
4891 /* What happens in such situation isn't documented; Native seems to silently abort
4892 on such conditions. Return Invalid Call. */
4893 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
4894 return WINED3DERR_INVALIDCALL;
4896 for (j = 0; j < 256; ++j) {
4897 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4898 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4899 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4900 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4902 TRACE("(%p) : returning\n", This);
4903 return WINED3D_OK;
4906 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4907 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4908 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4909 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
4910 (tested with reference rasterizer). Return Invalid Call. */
4911 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
4912 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
4913 return WINED3DERR_INVALIDCALL;
4915 /*TODO: stateblocks */
4916 if (This->currentPalette != PaletteNumber) {
4917 This->currentPalette = PaletteNumber;
4918 dirtify_p8_texture_samplers(This);
4920 TRACE("(%p) : returning\n", This);
4921 return WINED3D_OK;
4924 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4926 if (PaletteNumber == NULL) {
4927 WARN("(%p) : returning Invalid Call\n", This);
4928 return WINED3DERR_INVALIDCALL;
4930 /*TODO: stateblocks */
4931 *PaletteNumber = This->currentPalette;
4932 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4933 return WINED3D_OK;
4936 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4938 static BOOL warned;
4939 if (!warned)
4941 FIXME("(%p) : stub\n", This);
4942 warned = TRUE;
4945 This->softwareVertexProcessing = bSoftware;
4946 return WINED3D_OK;
4950 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4952 static BOOL warned;
4953 if (!warned)
4955 FIXME("(%p) : stub\n", This);
4956 warned = TRUE;
4958 return This->softwareVertexProcessing;
4962 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4964 IWineD3DSwapChain *swapChain;
4965 HRESULT hr;
4967 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4969 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4970 if(hr == WINED3D_OK){
4971 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4972 IWineD3DSwapChain_Release(swapChain);
4973 }else{
4974 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4976 return hr;
4980 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4982 static BOOL warned;
4983 if(nSegments != 0.0f) {
4984 if (!warned)
4986 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4987 warned = TRUE;
4990 return WINED3D_OK;
4993 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4995 static BOOL warned;
4996 if (!warned)
4998 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4999 warned = TRUE;
5001 return 0.0f;
5004 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5006 /** TODO: remove casts to IWineD3DSurfaceImpl
5007 * NOTE: move code to surface to accomplish this
5008 ****************************************/
5009 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5010 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5011 int srcWidth, srcHeight;
5012 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5013 WINED3DFORMAT destFormat, srcFormat;
5014 UINT destSize;
5015 int srcLeft, destLeft, destTop;
5016 WINED3DPOOL srcPool, destPool;
5017 int offset = 0;
5018 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5019 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5020 GLenum dummy;
5021 DWORD sampler;
5022 int bpp;
5023 CONVERT_TYPES convert = NO_CONVERSION;
5024 struct wined3d_context *context;
5026 WINED3DSURFACE_DESC winedesc;
5028 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5030 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5031 srcSurfaceWidth = winedesc.width;
5032 srcSurfaceHeight = winedesc.height;
5033 srcPool = winedesc.pool;
5034 srcFormat = winedesc.format;
5036 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5037 destSurfaceWidth = winedesc.width;
5038 destSurfaceHeight = winedesc.height;
5039 destPool = winedesc.pool;
5040 destFormat = winedesc.format;
5041 destSize = winedesc.size;
5043 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5044 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5045 return WINED3DERR_INVALIDCALL;
5048 /* This call loads the opengl surface directly, instead of copying the surface to the
5049 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5050 * copy in sysmem and use regular surface loading.
5052 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5053 if(convert != NO_CONVERSION) {
5054 return IWineD3DSurface_BltFast(pDestinationSurface,
5055 pDestPoint ? pDestPoint->x : 0,
5056 pDestPoint ? pDestPoint->y : 0,
5057 pSourceSurface, pSourceRect, 0);
5060 if (destFormat == WINED3DFMT_UNKNOWN) {
5061 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5062 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5064 /* Get the update surface description */
5065 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5068 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5070 ENTER_GL();
5071 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5072 checkGLcall("glActiveTextureARB");
5073 LEAVE_GL();
5075 /* Make sure the surface is loaded and up to date */
5076 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5077 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5079 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5080 dst_format_desc = dst_impl->resource.format_desc;
5082 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5083 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5084 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5085 srcLeft = pSourceRect ? pSourceRect->left : 0;
5086 destLeft = pDestPoint ? pDestPoint->x : 0;
5087 destTop = pDestPoint ? pDestPoint->y : 0;
5090 /* This function doesn't support compressed textures
5091 the pitch is just bytesPerPixel * width */
5092 if(srcWidth != srcSurfaceWidth || srcLeft ){
5093 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5094 offset += srcLeft * src_format_desc->byte_count;
5095 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5097 /* TODO DXT formats */
5099 if(pSourceRect != NULL && pSourceRect->top != 0){
5100 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5102 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5103 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5104 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5106 /* Sanity check */
5107 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5109 /* need to lock the surface to get the data */
5110 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5113 ENTER_GL();
5115 /* TODO: Cube and volume support */
5116 if(rowoffset != 0){
5117 /* not a whole row so we have to do it a line at a time */
5118 int j;
5120 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5121 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5123 for (j = destTop; j < (srcHeight + destTop); ++j)
5125 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5126 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5127 data += rowoffset;
5130 } else { /* Full width, so just write out the whole texture */
5131 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5133 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5135 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5137 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5138 FIXME("Updating part of a compressed texture is not supported.\n");
5140 if (destFormat != srcFormat)
5142 FIXME("Updating mixed format compressed textures is not supported.\n");
5144 else
5146 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5147 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5150 else
5152 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5153 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5156 checkGLcall("glTexSubImage2D");
5158 LEAVE_GL();
5159 context_release(context);
5161 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5162 sampler = This->rev_tex_unit_map[0];
5163 if (sampler != WINED3D_UNMAPPED_STAGE)
5165 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5168 return WINED3D_OK;
5171 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5173 struct WineD3DRectPatch *patch;
5174 GLenum old_primitive_type;
5175 unsigned int i;
5176 struct list *e;
5177 BOOL found;
5178 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5180 if(!(Handle || pRectPatchInfo)) {
5181 /* TODO: Write a test for the return value, thus the FIXME */
5182 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5183 return WINED3DERR_INVALIDCALL;
5186 if(Handle) {
5187 i = PATCHMAP_HASHFUNC(Handle);
5188 found = FALSE;
5189 LIST_FOR_EACH(e, &This->patches[i]) {
5190 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5191 if(patch->Handle == Handle) {
5192 found = TRUE;
5193 break;
5197 if(!found) {
5198 TRACE("Patch does not exist. Creating a new one\n");
5199 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5200 patch->Handle = Handle;
5201 list_add_head(&This->patches[i], &patch->entry);
5202 } else {
5203 TRACE("Found existing patch %p\n", patch);
5205 } else {
5206 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5207 * attributes we have to tesselate, read back, and draw. This needs a patch
5208 * management structure instance. Create one.
5210 * A possible improvement is to check if a vertex shader is used, and if not directly
5211 * draw the patch.
5213 FIXME("Drawing an uncached patch. This is slow\n");
5214 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5217 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5218 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5219 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5220 HRESULT hr;
5221 TRACE("Tesselation density or patch info changed, retesselating\n");
5223 if(pRectPatchInfo) {
5224 patch->RectPatchInfo = *pRectPatchInfo;
5226 patch->numSegs[0] = pNumSegs[0];
5227 patch->numSegs[1] = pNumSegs[1];
5228 patch->numSegs[2] = pNumSegs[2];
5229 patch->numSegs[3] = pNumSegs[3];
5231 hr = tesselate_rectpatch(This, patch);
5232 if(FAILED(hr)) {
5233 WARN("Patch tesselation failed\n");
5235 /* Do not release the handle to store the params of the patch */
5236 if(!Handle) {
5237 HeapFree(GetProcessHeap(), 0, patch);
5239 return hr;
5243 This->currentPatch = patch;
5244 old_primitive_type = This->stateBlock->gl_primitive_type;
5245 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5246 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5247 This->stateBlock->gl_primitive_type = old_primitive_type;
5248 This->currentPatch = NULL;
5250 /* Destroy uncached patches */
5251 if(!Handle) {
5252 HeapFree(GetProcessHeap(), 0, patch->mem);
5253 HeapFree(GetProcessHeap(), 0, patch);
5255 return WINED3D_OK;
5258 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5260 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5261 FIXME("(%p) : Stub\n", This);
5262 return WINED3D_OK;
5265 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5267 int i;
5268 struct WineD3DRectPatch *patch;
5269 struct list *e;
5270 TRACE("(%p) Handle(%d)\n", This, Handle);
5272 i = PATCHMAP_HASHFUNC(Handle);
5273 LIST_FOR_EACH(e, &This->patches[i]) {
5274 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5275 if(patch->Handle == Handle) {
5276 TRACE("Deleting patch %p\n", patch);
5277 list_remove(&patch->entry);
5278 HeapFree(GetProcessHeap(), 0, patch->mem);
5279 HeapFree(GetProcessHeap(), 0, patch);
5280 return WINED3D_OK;
5284 /* TODO: Write a test for the return value */
5285 FIXME("Attempt to destroy nonexistent patch\n");
5286 return WINED3DERR_INVALIDCALL;
5289 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5290 HRESULT hr;
5291 IWineD3DSwapChain *swapchain;
5293 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5294 if (SUCCEEDED(hr)) {
5295 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5296 return swapchain;
5299 return NULL;
5302 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5303 const WINED3DRECT *rect, const float color[4])
5305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5306 struct wined3d_context *context;
5308 if (!surface_is_offscreen(surface))
5310 TRACE("Surface %p is onscreen\n", surface);
5312 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5313 ENTER_GL();
5314 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5315 context_set_draw_buffer(context, surface_get_gl_buffer(surface));
5317 else
5319 TRACE("Surface %p is offscreen\n", surface);
5321 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5322 ENTER_GL();
5323 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5324 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5325 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5328 if (rect) {
5329 glEnable(GL_SCISSOR_TEST);
5330 if(surface_is_offscreen(surface)) {
5331 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5332 } else {
5333 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5334 rect->x2 - rect->x1, rect->y2 - rect->y1);
5336 checkGLcall("glScissor");
5337 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5338 } else {
5339 glDisable(GL_SCISSOR_TEST);
5341 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5343 glDisable(GL_BLEND);
5344 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5346 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5347 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5349 glClearColor(color[0], color[1], color[2], color[3]);
5350 glClear(GL_COLOR_BUFFER_BIT);
5351 checkGLcall("glClear");
5353 LEAVE_GL();
5354 context_release(context);
5357 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5358 unsigned int r, g, b, a;
5359 DWORD ret;
5361 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5362 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5363 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5364 return color;
5366 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5368 a = (color & 0xff000000) >> 24;
5369 r = (color & 0x00ff0000) >> 16;
5370 g = (color & 0x0000ff00) >> 8;
5371 b = (color & 0x000000ff) >> 0;
5373 switch(destfmt)
5375 case WINED3DFMT_B5G6R5_UNORM:
5376 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5377 r = (r * 32) / 256;
5378 g = (g * 64) / 256;
5379 b = (b * 32) / 256;
5380 ret = r << 11;
5381 ret |= g << 5;
5382 ret |= b;
5383 TRACE("Returning %08x\n", ret);
5384 return ret;
5386 case WINED3DFMT_B5G5R5X1_UNORM:
5387 case WINED3DFMT_B5G5R5A1_UNORM:
5388 a = (a * 2) / 256;
5389 r = (r * 32) / 256;
5390 g = (g * 32) / 256;
5391 b = (b * 32) / 256;
5392 ret = a << 15;
5393 ret |= r << 10;
5394 ret |= g << 5;
5395 ret |= b << 0;
5396 TRACE("Returning %08x\n", ret);
5397 return ret;
5399 case WINED3DFMT_A8_UNORM:
5400 TRACE("Returning %08x\n", a);
5401 return a;
5403 case WINED3DFMT_B4G4R4X4_UNORM:
5404 case WINED3DFMT_B4G4R4A4_UNORM:
5405 a = (a * 16) / 256;
5406 r = (r * 16) / 256;
5407 g = (g * 16) / 256;
5408 b = (b * 16) / 256;
5409 ret = a << 12;
5410 ret |= r << 8;
5411 ret |= g << 4;
5412 ret |= b << 0;
5413 TRACE("Returning %08x\n", ret);
5414 return ret;
5416 case WINED3DFMT_B2G3R3_UNORM:
5417 r = (r * 8) / 256;
5418 g = (g * 8) / 256;
5419 b = (b * 4) / 256;
5420 ret = r << 5;
5421 ret |= g << 2;
5422 ret |= b << 0;
5423 TRACE("Returning %08x\n", ret);
5424 return ret;
5426 case WINED3DFMT_R8G8B8X8_UNORM:
5427 case WINED3DFMT_R8G8B8A8_UNORM:
5428 ret = a << 24;
5429 ret |= b << 16;
5430 ret |= g << 8;
5431 ret |= r << 0;
5432 TRACE("Returning %08x\n", ret);
5433 return ret;
5435 case WINED3DFMT_B10G10R10A2_UNORM:
5436 a = (a * 4) / 256;
5437 r = (r * 1024) / 256;
5438 g = (g * 1024) / 256;
5439 b = (b * 1024) / 256;
5440 ret = a << 30;
5441 ret |= r << 20;
5442 ret |= g << 10;
5443 ret |= b << 0;
5444 TRACE("Returning %08x\n", ret);
5445 return ret;
5447 case WINED3DFMT_R10G10B10A2_UNORM:
5448 a = (a * 4) / 256;
5449 r = (r * 1024) / 256;
5450 g = (g * 1024) / 256;
5451 b = (b * 1024) / 256;
5452 ret = a << 30;
5453 ret |= b << 20;
5454 ret |= g << 10;
5455 ret |= r << 0;
5456 TRACE("Returning %08x\n", ret);
5457 return ret;
5459 default:
5460 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5461 return 0;
5465 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5467 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5468 WINEDDBLTFX BltFx;
5469 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5471 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5472 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5473 return WINED3DERR_INVALIDCALL;
5476 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5477 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5478 color_fill_fbo(iface, pSurface, pRect, c);
5479 return WINED3D_OK;
5480 } else {
5481 /* Just forward this to the DirectDraw blitting engine */
5482 memset(&BltFx, 0, sizeof(BltFx));
5483 BltFx.dwSize = sizeof(BltFx);
5484 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5485 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5486 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5490 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5491 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5493 IWineD3DResource *resource;
5494 IWineD3DSurface *surface;
5495 HRESULT hr;
5497 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5498 if (FAILED(hr))
5500 ERR("Failed to get resource, hr %#x\n", hr);
5501 return;
5504 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5506 FIXME("Only supported on surface resources\n");
5507 IWineD3DResource_Release(resource);
5508 return;
5511 surface = (IWineD3DSurface *)resource;
5513 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5515 color_fill_fbo(iface, surface, NULL, color);
5517 else
5519 WINEDDBLTFX BltFx;
5520 WINED3DCOLOR c;
5522 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5524 c = ((DWORD)(color[2] * 255.0f));
5525 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5526 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5527 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5529 /* Just forward this to the DirectDraw blitting engine */
5530 memset(&BltFx, 0, sizeof(BltFx));
5531 BltFx.dwSize = sizeof(BltFx);
5532 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5533 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5534 if (FAILED(hr))
5536 ERR("Blt failed, hr %#x\n", hr);
5540 IWineD3DResource_Release(resource);
5543 /* rendertarget and depth stencil functions */
5544 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5547 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5549 ERR("(%p) : Only %d render targets are supported.\n",
5550 This, This->adapter->gl_info.limits.buffers);
5551 return WINED3DERR_INVALIDCALL;
5554 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5555 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5556 /* Note inc ref on returned surface */
5557 if(*ppRenderTarget != NULL)
5558 IWineD3DSurface_AddRef(*ppRenderTarget);
5559 return WINED3D_OK;
5562 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5564 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5565 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5566 IWineD3DSwapChainImpl *Swapchain;
5567 HRESULT hr;
5569 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5571 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5572 if(hr != WINED3D_OK) {
5573 ERR("Can't get the swapchain\n");
5574 return hr;
5577 /* Make sure to release the swapchain */
5578 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5580 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5581 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5582 return WINED3DERR_INVALIDCALL;
5584 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5585 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5586 return WINED3DERR_INVALIDCALL;
5589 if(Swapchain->frontBuffer != Front) {
5590 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5592 if(Swapchain->frontBuffer)
5594 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5595 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5597 Swapchain->frontBuffer = Front;
5599 if(Swapchain->frontBuffer) {
5600 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5601 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5605 if(Back && !Swapchain->backBuffer) {
5606 /* We need memory for the back buffer array - only one back buffer this way */
5607 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5608 if(!Swapchain->backBuffer) {
5609 ERR("Out of memory\n");
5610 return E_OUTOFMEMORY;
5614 if(Swapchain->backBuffer[0] != Back) {
5615 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5617 /* What to do about the context here in the case of multithreading? Not sure.
5618 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5620 WARN("No active context?\n");
5622 ENTER_GL();
5623 if(!Swapchain->backBuffer[0]) {
5624 /* GL was told to draw to the front buffer at creation,
5625 * undo that
5627 glDrawBuffer(GL_BACK);
5628 checkGLcall("glDrawBuffer(GL_BACK)");
5629 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5630 Swapchain->presentParms.BackBufferCount = 1;
5631 } else if (!Back) {
5632 /* That makes problems - disable for now */
5633 /* glDrawBuffer(GL_FRONT); */
5634 checkGLcall("glDrawBuffer(GL_FRONT)");
5635 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5636 Swapchain->presentParms.BackBufferCount = 0;
5638 LEAVE_GL();
5640 if(Swapchain->backBuffer[0])
5642 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5643 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5645 Swapchain->backBuffer[0] = Back;
5647 if(Swapchain->backBuffer[0]) {
5648 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5649 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
5650 } else {
5651 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5652 Swapchain->backBuffer = NULL;
5657 return WINED3D_OK;
5660 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5662 *ppZStencilSurface = This->stencilBufferTarget;
5663 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5665 if(*ppZStencilSurface != NULL) {
5666 /* Note inc ref on returned surface */
5667 IWineD3DSurface_AddRef(*ppZStencilSurface);
5668 return WINED3D_OK;
5669 } else {
5670 return WINED3DERR_NOTFOUND;
5674 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5675 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
5677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5678 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5679 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5680 const struct wined3d_gl_info *gl_info;
5681 struct wined3d_context *context;
5682 GLenum gl_filter;
5683 POINT offset = {0, 0};
5685 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5686 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5687 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5688 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5690 switch (filter) {
5691 case WINED3DTEXF_LINEAR:
5692 gl_filter = GL_LINEAR;
5693 break;
5695 default:
5696 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5697 case WINED3DTEXF_NONE:
5698 case WINED3DTEXF_POINT:
5699 gl_filter = GL_NEAREST;
5700 break;
5703 /* Attach src surface to src fbo */
5704 src_swapchain = get_swapchain(src_surface);
5705 dst_swapchain = get_swapchain(dst_surface);
5707 if (src_swapchain) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
5708 else if (dst_swapchain) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5709 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5711 gl_info = context->gl_info;
5713 if (!surface_is_offscreen(src_surface))
5715 GLenum buffer = surface_get_gl_buffer(src_surface);
5717 TRACE("Source surface %p is onscreen\n", src_surface);
5718 /* Make sure the drawable is up to date. In the offscreen case
5719 * attach_surface_fbo() implicitly takes care of this. */
5720 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
5722 if(buffer == GL_FRONT) {
5723 RECT windowsize;
5724 UINT h;
5725 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
5726 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
5727 h = windowsize.bottom - windowsize.top;
5728 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
5729 src_rect->y1 = offset.y + h - src_rect->y1;
5730 src_rect->y2 = offset.y + h - src_rect->y2;
5731 } else {
5732 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5733 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5736 ENTER_GL();
5737 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5738 glReadBuffer(buffer);
5739 checkGLcall("glReadBuffer()");
5740 } else {
5741 TRACE("Source surface %p is offscreen\n", src_surface);
5742 ENTER_GL();
5743 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5744 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
5745 glReadBuffer(GL_COLOR_ATTACHMENT0);
5746 checkGLcall("glReadBuffer()");
5747 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5749 LEAVE_GL();
5751 /* Attach dst surface to dst fbo */
5752 if (!surface_is_offscreen(dst_surface))
5754 GLenum buffer = surface_get_gl_buffer(dst_surface);
5756 TRACE("Destination surface %p is onscreen\n", dst_surface);
5757 /* Make sure the drawable is up to date. In the offscreen case
5758 * attach_surface_fbo() implicitly takes care of this. */
5759 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
5761 if(buffer == GL_FRONT) {
5762 RECT windowsize;
5763 UINT h;
5764 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
5765 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
5766 h = windowsize.bottom - windowsize.top;
5767 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
5768 dst_rect->y1 = offset.y + h - dst_rect->y1;
5769 dst_rect->y2 = offset.y + h - dst_rect->y2;
5770 } else {
5771 /* Screen coords = window coords, surface height = window height */
5772 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5773 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5776 ENTER_GL();
5777 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5778 context_set_draw_buffer(context, buffer);
5780 else
5782 TRACE("Destination surface %p is offscreen\n", dst_surface);
5784 ENTER_GL();
5785 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5786 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
5787 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5788 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5790 glDisable(GL_SCISSOR_TEST);
5791 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5793 if (flip) {
5794 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5795 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
5796 checkGLcall("glBlitFramebuffer()");
5797 } else {
5798 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5799 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
5800 checkGLcall("glBlitFramebuffer()");
5803 LEAVE_GL();
5804 context_release(context);
5806 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
5809 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5810 BOOL set_viewport) {
5811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5813 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5815 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5817 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5818 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5819 return WINED3DERR_INVALIDCALL;
5822 /* MSDN says that null disables the render target
5823 but a device must always be associated with a render target
5824 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5826 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5827 FIXME("Trying to set render target 0 to NULL\n");
5828 return WINED3DERR_INVALIDCALL;
5830 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5831 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);
5832 return WINED3DERR_INVALIDCALL;
5835 /* If we are trying to set what we already have, don't bother */
5836 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5837 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5838 return WINED3D_OK;
5840 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5841 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5842 This->render_targets[RenderTargetIndex] = pRenderTarget;
5844 /* Render target 0 is special */
5845 if(RenderTargetIndex == 0 && set_viewport) {
5846 /* Finally, reset the viewport and scissor rect as the MSDN states.
5847 * Tests show that stateblock recording is ignored, the change goes
5848 * directly into the primary stateblock.
5850 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5851 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5852 This->stateBlock->viewport.X = 0;
5853 This->stateBlock->viewport.Y = 0;
5854 This->stateBlock->viewport.MaxZ = 1.0f;
5855 This->stateBlock->viewport.MinZ = 0.0f;
5856 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5858 This->stateBlock->scissorRect.top = 0;
5859 This->stateBlock->scissorRect.left = 0;
5860 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5861 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5862 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5864 return WINED3D_OK;
5867 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5869 HRESULT hr = WINED3D_OK;
5870 IWineD3DSurface *tmp;
5872 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
5874 if (pNewZStencil == This->stencilBufferTarget) {
5875 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5876 } else {
5877 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
5878 * depending on the renter target implementation being used.
5879 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5880 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5881 * stencil buffer and incur an extra memory overhead
5882 ******************************************************/
5884 if (This->stencilBufferTarget) {
5885 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5886 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
5887 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
5888 } else {
5889 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5890 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
5891 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
5892 context_release(context);
5896 tmp = This->stencilBufferTarget;
5897 This->stencilBufferTarget = pNewZStencil;
5898 /* should we be calling the parent or the wined3d surface? */
5899 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5900 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5901 hr = WINED3D_OK;
5903 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5904 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5905 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5906 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5907 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5911 return hr;
5914 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5915 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5917 /* TODO: the use of Impl is deprecated. */
5918 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5919 WINED3DLOCKED_RECT lockedRect;
5921 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5923 /* some basic validation checks */
5924 if(This->cursorTexture) {
5925 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5926 ENTER_GL();
5927 glDeleteTextures(1, &This->cursorTexture);
5928 LEAVE_GL();
5929 context_release(context);
5930 This->cursorTexture = 0;
5933 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5934 This->haveHardwareCursor = TRUE;
5935 else
5936 This->haveHardwareCursor = FALSE;
5938 if(pCursorBitmap) {
5939 WINED3DLOCKED_RECT rect;
5941 /* MSDN: Cursor must be A8R8G8B8 */
5942 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
5944 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5945 return WINED3DERR_INVALIDCALL;
5948 /* MSDN: Cursor must be smaller than the display mode */
5949 if(pSur->currentDesc.Width > This->ddraw_width ||
5950 pSur->currentDesc.Height > This->ddraw_height) {
5951 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);
5952 return WINED3DERR_INVALIDCALL;
5955 if (!This->haveHardwareCursor) {
5956 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5958 /* Do not store the surface's pointer because the application may
5959 * release it after setting the cursor image. Windows doesn't
5960 * addref the set surface, so we can't do this either without
5961 * creating circular refcount dependencies. Copy out the gl texture
5962 * instead.
5964 This->cursorWidth = pSur->currentDesc.Width;
5965 This->cursorHeight = pSur->currentDesc.Height;
5966 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5968 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5969 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
5970 struct wined3d_context *context;
5971 char *mem, *bits = rect.pBits;
5972 GLint intfmt = glDesc->glInternal;
5973 GLint format = glDesc->glFormat;
5974 GLint type = glDesc->glType;
5975 INT height = This->cursorHeight;
5976 INT width = This->cursorWidth;
5977 INT bpp = glDesc->byte_count;
5978 DWORD sampler;
5979 INT i;
5981 /* Reformat the texture memory (pitch and width can be
5982 * different) */
5983 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5984 for(i = 0; i < height; i++)
5985 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5986 IWineD3DSurface_UnlockRect(pCursorBitmap);
5988 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5990 ENTER_GL();
5992 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5994 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5995 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5998 /* Make sure that a proper texture unit is selected */
5999 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6000 checkGLcall("glActiveTextureARB");
6001 sampler = This->rev_tex_unit_map[0];
6002 if (sampler != WINED3D_UNMAPPED_STAGE)
6004 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6006 /* Create a new cursor texture */
6007 glGenTextures(1, &This->cursorTexture);
6008 checkGLcall("glGenTextures");
6009 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6010 checkGLcall("glBindTexture");
6011 /* Copy the bitmap memory into the cursor texture */
6012 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6013 HeapFree(GetProcessHeap(), 0, mem);
6014 checkGLcall("glTexImage2D");
6016 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6018 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6019 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6022 LEAVE_GL();
6024 context_release(context);
6026 else
6028 FIXME("A cursor texture was not returned.\n");
6029 This->cursorTexture = 0;
6032 else
6034 /* Draw a hardware cursor */
6035 ICONINFO cursorInfo;
6036 HCURSOR cursor;
6037 /* Create and clear maskBits because it is not needed for
6038 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6039 * chunks. */
6040 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6041 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6042 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6043 WINED3DLOCK_NO_DIRTY_UPDATE |
6044 WINED3DLOCK_READONLY
6046 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6047 pSur->currentDesc.Height);
6049 cursorInfo.fIcon = FALSE;
6050 cursorInfo.xHotspot = XHotSpot;
6051 cursorInfo.yHotspot = YHotSpot;
6052 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6053 1, 1, maskBits);
6054 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6055 1, 32, lockedRect.pBits);
6056 IWineD3DSurface_UnlockRect(pCursorBitmap);
6057 /* Create our cursor and clean up. */
6058 cursor = CreateIconIndirect(&cursorInfo);
6059 SetCursor(cursor);
6060 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6061 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6062 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6063 This->hardwareCursor = cursor;
6064 HeapFree(GetProcessHeap(), 0, maskBits);
6068 This->xHotSpot = XHotSpot;
6069 This->yHotSpot = YHotSpot;
6070 return WINED3D_OK;
6073 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6075 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6077 This->xScreenSpace = XScreenSpace;
6078 This->yScreenSpace = YScreenSpace;
6080 return;
6084 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6086 BOOL oldVisible = This->bCursorVisible;
6087 POINT pt;
6089 TRACE("(%p) : visible(%d)\n", This, bShow);
6092 * When ShowCursor is first called it should make the cursor appear at the OS's last
6093 * known cursor position. Because of this, some applications just repetitively call
6094 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6096 GetCursorPos(&pt);
6097 This->xScreenSpace = pt.x;
6098 This->yScreenSpace = pt.y;
6100 if (This->haveHardwareCursor) {
6101 This->bCursorVisible = bShow;
6102 if (bShow)
6103 SetCursor(This->hardwareCursor);
6104 else
6105 SetCursor(NULL);
6107 else
6109 if (This->cursorTexture)
6110 This->bCursorVisible = bShow;
6113 return oldVisible;
6116 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6117 TRACE("checking resource %p for eviction\n", resource);
6118 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6119 TRACE("Evicting %p\n", resource);
6120 IWineD3DResource_UnLoad(resource);
6122 IWineD3DResource_Release(resource);
6123 return S_OK;
6126 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6128 TRACE("(%p)\n", This);
6130 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6131 return WINED3D_OK;
6134 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6136 IWineD3DDeviceImpl *device = surface->resource.device;
6137 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6139 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6140 if(surface->Flags & SFLAG_DIBSECTION) {
6141 /* Release the DC */
6142 SelectObject(surface->hDC, surface->dib.holdbitmap);
6143 DeleteDC(surface->hDC);
6144 /* Release the DIB section */
6145 DeleteObject(surface->dib.DIBsection);
6146 surface->dib.bitmap_data = NULL;
6147 surface->resource.allocatedMemory = NULL;
6148 surface->Flags &= ~SFLAG_DIBSECTION;
6150 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6151 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6152 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6153 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6155 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6156 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6157 } else {
6158 surface->pow2Width = surface->pow2Height = 1;
6159 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6160 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6162 surface->glRect.left = 0;
6163 surface->glRect.top = 0;
6164 surface->glRect.right = surface->pow2Width;
6165 surface->glRect.bottom = surface->pow2Height;
6167 if (surface->texture_name)
6169 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6170 ENTER_GL();
6171 glDeleteTextures(1, &surface->texture_name);
6172 LEAVE_GL();
6173 context_release(context);
6174 surface->texture_name = 0;
6175 surface->Flags &= ~SFLAG_CLIENT;
6177 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6178 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6179 surface->Flags |= SFLAG_NONPOW2;
6180 } else {
6181 surface->Flags &= ~SFLAG_NONPOW2;
6183 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6184 surface->resource.allocatedMemory = NULL;
6185 surface->resource.heapMemory = NULL;
6186 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6188 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6189 * to a FBO */
6190 if(!surface_init_sysmem((IWineD3DSurface *) surface))
6192 return E_OUTOFMEMORY;
6194 return WINED3D_OK;
6197 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6198 TRACE("Unloading resource %p\n", resource);
6199 IWineD3DResource_UnLoad(resource);
6200 IWineD3DResource_Release(resource);
6201 return S_OK;
6204 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6206 UINT i, count;
6207 WINED3DDISPLAYMODE m;
6208 HRESULT hr;
6210 /* All Windowed modes are supported, as is leaving the current mode */
6211 if(pp->Windowed) return TRUE;
6212 if(!pp->BackBufferWidth) return TRUE;
6213 if(!pp->BackBufferHeight) return TRUE;
6215 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6216 for(i = 0; i < count; i++) {
6217 memset(&m, 0, sizeof(m));
6218 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6219 if(FAILED(hr)) {
6220 ERR("EnumAdapterModes failed\n");
6222 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6223 /* Mode found, it is supported */
6224 return TRUE;
6227 /* Mode not found -> not supported */
6228 return FALSE;
6231 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6233 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6234 const struct wined3d_gl_info *gl_info;
6235 struct wined3d_context *context;
6236 UINT i;
6237 IWineD3DBaseShaderImpl *shader;
6239 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6240 gl_info = context->gl_info;
6242 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6243 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6244 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6247 ENTER_GL();
6248 if(This->depth_blt_texture) {
6249 glDeleteTextures(1, &This->depth_blt_texture);
6250 This->depth_blt_texture = 0;
6252 if (This->depth_blt_rb) {
6253 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6254 This->depth_blt_rb = 0;
6255 This->depth_blt_rb_w = 0;
6256 This->depth_blt_rb_h = 0;
6258 LEAVE_GL();
6260 This->blitter->free_private(iface);
6261 This->frag_pipe->free_private(iface);
6262 This->shader_backend->shader_free_private(iface);
6264 ENTER_GL();
6265 for (i = 0; i < This->adapter->gl_info.limits.textures; ++i)
6267 /* Textures are recreated below */
6268 glDeleteTextures(1, &This->dummyTextureName[i]);
6269 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6270 This->dummyTextureName[i] = 0;
6272 LEAVE_GL();
6274 context_release(context);
6276 while (This->numContexts)
6278 context_destroy(This, This->contexts[0]);
6280 HeapFree(GetProcessHeap(), 0, swapchain->context);
6281 swapchain->context = NULL;
6282 swapchain->num_contexts = 0;
6285 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6287 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6288 HRESULT hr;
6289 IWineD3DSurfaceImpl *target;
6291 /* Recreate the primary swapchain's context */
6292 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6293 if(swapchain->backBuffer) {
6294 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6295 } else {
6296 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6298 swapchain->context[0] = context_create(This, target, swapchain->win_handle, FALSE, &swapchain->presentParms);
6299 swapchain->num_contexts = 1;
6301 create_dummy_textures(This);
6303 context_release(swapchain->context[0]);
6305 hr = This->shader_backend->shader_alloc_private(iface);
6306 if(FAILED(hr)) {
6307 ERR("Failed to recreate shader private data\n");
6308 goto err_out;
6310 hr = This->frag_pipe->alloc_private(iface);
6311 if(FAILED(hr)) {
6312 TRACE("Fragment pipeline private data couldn't be allocated\n");
6313 goto err_out;
6315 hr = This->blitter->alloc_private(iface);
6316 if(FAILED(hr)) {
6317 TRACE("Blitter private data couldn't be allocated\n");
6318 goto err_out;
6321 return WINED3D_OK;
6323 err_out:
6324 This->blitter->free_private(iface);
6325 This->frag_pipe->free_private(iface);
6326 This->shader_backend->shader_free_private(iface);
6327 return hr;
6330 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6332 IWineD3DSwapChainImpl *swapchain;
6333 HRESULT hr;
6334 BOOL DisplayModeChanged = FALSE;
6335 WINED3DDISPLAYMODE mode;
6336 TRACE("(%p)\n", This);
6338 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6339 if(FAILED(hr)) {
6340 ERR("Failed to get the first implicit swapchain\n");
6341 return hr;
6344 if(!is_display_mode_supported(This, pPresentationParameters)) {
6345 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6346 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6347 pPresentationParameters->BackBufferHeight);
6348 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6349 return WINED3DERR_INVALIDCALL;
6352 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6353 * on an existing gl context, so there's no real need for recreation.
6355 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6357 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6359 TRACE("New params:\n");
6360 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6361 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6362 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6363 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6364 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6365 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6366 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6367 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6368 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6369 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6370 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6371 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6372 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6374 /* No special treatment of these parameters. Just store them */
6375 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6376 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6377 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6378 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6380 /* What to do about these? */
6381 if(pPresentationParameters->BackBufferCount != 0 &&
6382 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6383 ERR("Cannot change the back buffer count yet\n");
6385 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6386 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6387 ERR("Cannot change the back buffer format yet\n");
6389 if(pPresentationParameters->hDeviceWindow != NULL &&
6390 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6391 ERR("Cannot change the device window yet\n");
6393 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6394 HRESULT hrc;
6396 TRACE("Creating the depth stencil buffer\n");
6398 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6399 This->parent,
6400 pPresentationParameters->BackBufferWidth,
6401 pPresentationParameters->BackBufferHeight,
6402 pPresentationParameters->AutoDepthStencilFormat,
6403 pPresentationParameters->MultiSampleType,
6404 pPresentationParameters->MultiSampleQuality,
6405 FALSE,
6406 &This->auto_depth_stencil_buffer);
6408 if (FAILED(hrc)) {
6409 ERR("Failed to create the depth stencil buffer\n");
6410 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6411 return WINED3DERR_INVALIDCALL;
6415 /* Reset the depth stencil */
6416 if (pPresentationParameters->EnableAutoDepthStencil)
6417 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6418 else
6419 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6421 TRACE("Resetting stateblock\n");
6422 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6423 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6425 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6427 if(pPresentationParameters->Windowed) {
6428 mode.Width = swapchain->orig_width;
6429 mode.Height = swapchain->orig_height;
6430 mode.RefreshRate = 0;
6431 mode.Format = swapchain->presentParms.BackBufferFormat;
6432 } else {
6433 mode.Width = pPresentationParameters->BackBufferWidth;
6434 mode.Height = pPresentationParameters->BackBufferHeight;
6435 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6436 mode.Format = swapchain->presentParms.BackBufferFormat;
6439 /* Should Width == 800 && Height == 0 set 800x600? */
6440 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6441 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6442 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6444 UINT i;
6446 if(!pPresentationParameters->Windowed) {
6447 DisplayModeChanged = TRUE;
6449 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6450 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6452 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6453 if(FAILED(hr))
6455 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6456 return hr;
6459 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6460 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6461 if(FAILED(hr))
6463 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6464 return hr;
6467 if(This->auto_depth_stencil_buffer) {
6468 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6469 if(FAILED(hr))
6471 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6472 return hr;
6477 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6478 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6479 DisplayModeChanged) {
6481 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6483 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
6484 if(swapchain->presentParms.Windowed) {
6485 /* switch from windowed to fs */
6486 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6487 pPresentationParameters->BackBufferHeight);
6488 } else {
6489 /* Fullscreen -> fullscreen mode change */
6490 MoveWindow(swapchain->win_handle, 0, 0,
6491 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6492 TRUE);
6494 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
6495 /* Fullscreen -> windowed switch */
6496 swapchain_restore_fullscreen_window(swapchain);
6498 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6499 } else if(!pPresentationParameters->Windowed) {
6500 DWORD style = This->style, exStyle = This->exStyle;
6501 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6502 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6503 * Reset to clear up their mess. Guild Wars also loses the device during that.
6505 This->style = 0;
6506 This->exStyle = 0;
6507 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6508 pPresentationParameters->BackBufferHeight);
6509 This->style = style;
6510 This->exStyle = exStyle;
6513 /* Note: No parent needed for initial internal stateblock */
6514 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6515 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6516 else TRACE("Created stateblock %p\n", This->stateBlock);
6517 This->updateStateBlock = This->stateBlock;
6518 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6520 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6521 if(FAILED(hr)) {
6522 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6525 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6527 RECT client_rect;
6528 GetClientRect(swapchain->win_handle, &client_rect);
6530 if(!swapchain->presentParms.BackBufferCount)
6532 TRACE("Single buffered rendering\n");
6533 swapchain->render_to_fbo = FALSE;
6535 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6536 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6538 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6539 swapchain->presentParms.BackBufferWidth,
6540 swapchain->presentParms.BackBufferHeight,
6541 client_rect.right, client_rect.bottom);
6542 swapchain->render_to_fbo = TRUE;
6544 else
6546 TRACE("Rendering directly to GL_BACK\n");
6547 swapchain->render_to_fbo = FALSE;
6551 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6552 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6554 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6555 * first use
6557 return hr;
6560 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6562 /** FIXME: always true at the moment **/
6563 if(!bEnableDialogs) {
6564 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6566 return WINED3D_OK;
6570 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6572 TRACE("(%p) : pParameters %p\n", This, pParameters);
6574 *pParameters = This->createParms;
6575 return WINED3D_OK;
6578 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6579 IWineD3DSwapChain *swapchain;
6581 TRACE("Relaying to swapchain\n");
6583 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6584 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6585 IWineD3DSwapChain_Release(swapchain);
6587 return;
6590 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6591 IWineD3DSwapChain *swapchain;
6593 TRACE("Relaying to swapchain\n");
6595 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6596 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6597 IWineD3DSwapChain_Release(swapchain);
6599 return;
6603 /** ********************************************************
6604 * Notification functions
6605 ** ********************************************************/
6606 /** This function must be called in the release of a resource when ref == 0,
6607 * the contents of resource must still be correct,
6608 * any handles to other resource held by the caller must be closed
6609 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6610 *****************************************************/
6611 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6613 TRACE("(%p) : Adding resource %p\n", This, resource);
6615 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6618 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6620 TRACE("(%p) : Removing resource %p\n", This, resource);
6622 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6625 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6627 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6628 int counter;
6630 TRACE("(%p) : resource %p\n", This, resource);
6632 context_resource_released((IWineD3DDevice *)This, resource, type);
6634 switch (type) {
6635 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6636 case WINED3DRTYPE_SURFACE: {
6637 unsigned int i;
6639 if (This->d3d_initialized)
6641 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6643 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6644 This->render_targets[i] = NULL;
6647 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6648 This->stencilBufferTarget = NULL;
6652 break;
6654 case WINED3DRTYPE_TEXTURE:
6655 case WINED3DRTYPE_CUBETEXTURE:
6656 case WINED3DRTYPE_VOLUMETEXTURE:
6657 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6658 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6659 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6660 This->stateBlock->textures[counter] = NULL;
6662 if (This->updateStateBlock != This->stateBlock ){
6663 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6664 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6665 This->updateStateBlock->textures[counter] = NULL;
6669 break;
6670 case WINED3DRTYPE_VOLUME:
6671 /* TODO: nothing really? */
6672 break;
6673 case WINED3DRTYPE_BUFFER:
6675 int streamNumber;
6676 TRACE("Cleaning up stream pointers\n");
6678 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6679 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6680 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6682 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6683 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6684 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6685 This->updateStateBlock->streamSource[streamNumber] = 0;
6686 /* Set changed flag? */
6689 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) */
6690 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6691 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6692 This->stateBlock->streamSource[streamNumber] = 0;
6697 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6698 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6699 This->updateStateBlock->pIndexData = NULL;
6702 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6703 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6704 This->stateBlock->pIndexData = NULL;
6708 break;
6710 default:
6711 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6712 break;
6716 /* Remove the resource from the resourceStore */
6717 device_resource_remove(This, resource);
6719 TRACE("Resource released\n");
6723 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6725 IWineD3DResourceImpl *resource, *cursor;
6726 HRESULT ret;
6727 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6729 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6730 TRACE("enumerating resource %p\n", resource);
6731 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6732 ret = pCallback((IWineD3DResource *) resource, pData);
6733 if(ret == S_FALSE) {
6734 TRACE("Canceling enumeration\n");
6735 break;
6738 return WINED3D_OK;
6741 /**********************************************************
6742 * IWineD3DDevice VTbl follows
6743 **********************************************************/
6745 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6747 /*** IUnknown methods ***/
6748 IWineD3DDeviceImpl_QueryInterface,
6749 IWineD3DDeviceImpl_AddRef,
6750 IWineD3DDeviceImpl_Release,
6751 /*** IWineD3DDevice methods ***/
6752 IWineD3DDeviceImpl_GetParent,
6753 /*** Creation methods**/
6754 IWineD3DDeviceImpl_CreateBuffer,
6755 IWineD3DDeviceImpl_CreateVertexBuffer,
6756 IWineD3DDeviceImpl_CreateIndexBuffer,
6757 IWineD3DDeviceImpl_CreateStateBlock,
6758 IWineD3DDeviceImpl_CreateSurface,
6759 IWineD3DDeviceImpl_CreateRendertargetView,
6760 IWineD3DDeviceImpl_CreateTexture,
6761 IWineD3DDeviceImpl_CreateVolumeTexture,
6762 IWineD3DDeviceImpl_CreateVolume,
6763 IWineD3DDeviceImpl_CreateCubeTexture,
6764 IWineD3DDeviceImpl_CreateQuery,
6765 IWineD3DDeviceImpl_CreateSwapChain,
6766 IWineD3DDeviceImpl_CreateVertexDeclaration,
6767 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6768 IWineD3DDeviceImpl_CreateVertexShader,
6769 IWineD3DDeviceImpl_CreatePixelShader,
6770 IWineD3DDeviceImpl_CreatePalette,
6771 /*** Odd functions **/
6772 IWineD3DDeviceImpl_Init3D,
6773 IWineD3DDeviceImpl_InitGDI,
6774 IWineD3DDeviceImpl_Uninit3D,
6775 IWineD3DDeviceImpl_UninitGDI,
6776 IWineD3DDeviceImpl_SetMultithreaded,
6777 IWineD3DDeviceImpl_EvictManagedResources,
6778 IWineD3DDeviceImpl_GetAvailableTextureMem,
6779 IWineD3DDeviceImpl_GetBackBuffer,
6780 IWineD3DDeviceImpl_GetCreationParameters,
6781 IWineD3DDeviceImpl_GetDeviceCaps,
6782 IWineD3DDeviceImpl_GetDirect3D,
6783 IWineD3DDeviceImpl_GetDisplayMode,
6784 IWineD3DDeviceImpl_SetDisplayMode,
6785 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6786 IWineD3DDeviceImpl_GetRasterStatus,
6787 IWineD3DDeviceImpl_GetSwapChain,
6788 IWineD3DDeviceImpl_Reset,
6789 IWineD3DDeviceImpl_SetDialogBoxMode,
6790 IWineD3DDeviceImpl_SetCursorProperties,
6791 IWineD3DDeviceImpl_SetCursorPosition,
6792 IWineD3DDeviceImpl_ShowCursor,
6793 /*** Getters and setters **/
6794 IWineD3DDeviceImpl_SetClipPlane,
6795 IWineD3DDeviceImpl_GetClipPlane,
6796 IWineD3DDeviceImpl_SetClipStatus,
6797 IWineD3DDeviceImpl_GetClipStatus,
6798 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6799 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6800 IWineD3DDeviceImpl_SetDepthStencilSurface,
6801 IWineD3DDeviceImpl_GetDepthStencilSurface,
6802 IWineD3DDeviceImpl_SetGammaRamp,
6803 IWineD3DDeviceImpl_GetGammaRamp,
6804 IWineD3DDeviceImpl_SetIndexBuffer,
6805 IWineD3DDeviceImpl_GetIndexBuffer,
6806 IWineD3DDeviceImpl_SetBaseVertexIndex,
6807 IWineD3DDeviceImpl_GetBaseVertexIndex,
6808 IWineD3DDeviceImpl_SetLight,
6809 IWineD3DDeviceImpl_GetLight,
6810 IWineD3DDeviceImpl_SetLightEnable,
6811 IWineD3DDeviceImpl_GetLightEnable,
6812 IWineD3DDeviceImpl_SetMaterial,
6813 IWineD3DDeviceImpl_GetMaterial,
6814 IWineD3DDeviceImpl_SetNPatchMode,
6815 IWineD3DDeviceImpl_GetNPatchMode,
6816 IWineD3DDeviceImpl_SetPaletteEntries,
6817 IWineD3DDeviceImpl_GetPaletteEntries,
6818 IWineD3DDeviceImpl_SetPixelShader,
6819 IWineD3DDeviceImpl_GetPixelShader,
6820 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6821 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6822 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6823 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6824 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6825 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6826 IWineD3DDeviceImpl_SetRenderState,
6827 IWineD3DDeviceImpl_GetRenderState,
6828 IWineD3DDeviceImpl_SetRenderTarget,
6829 IWineD3DDeviceImpl_GetRenderTarget,
6830 IWineD3DDeviceImpl_SetFrontBackBuffers,
6831 IWineD3DDeviceImpl_SetSamplerState,
6832 IWineD3DDeviceImpl_GetSamplerState,
6833 IWineD3DDeviceImpl_SetScissorRect,
6834 IWineD3DDeviceImpl_GetScissorRect,
6835 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6836 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6837 IWineD3DDeviceImpl_SetStreamSource,
6838 IWineD3DDeviceImpl_GetStreamSource,
6839 IWineD3DDeviceImpl_SetStreamSourceFreq,
6840 IWineD3DDeviceImpl_GetStreamSourceFreq,
6841 IWineD3DDeviceImpl_SetTexture,
6842 IWineD3DDeviceImpl_GetTexture,
6843 IWineD3DDeviceImpl_SetTextureStageState,
6844 IWineD3DDeviceImpl_GetTextureStageState,
6845 IWineD3DDeviceImpl_SetTransform,
6846 IWineD3DDeviceImpl_GetTransform,
6847 IWineD3DDeviceImpl_SetVertexDeclaration,
6848 IWineD3DDeviceImpl_GetVertexDeclaration,
6849 IWineD3DDeviceImpl_SetVertexShader,
6850 IWineD3DDeviceImpl_GetVertexShader,
6851 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6852 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6853 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6854 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6855 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6856 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6857 IWineD3DDeviceImpl_SetViewport,
6858 IWineD3DDeviceImpl_GetViewport,
6859 IWineD3DDeviceImpl_MultiplyTransform,
6860 IWineD3DDeviceImpl_ValidateDevice,
6861 IWineD3DDeviceImpl_ProcessVertices,
6862 /*** State block ***/
6863 IWineD3DDeviceImpl_BeginStateBlock,
6864 IWineD3DDeviceImpl_EndStateBlock,
6865 /*** Scene management ***/
6866 IWineD3DDeviceImpl_BeginScene,
6867 IWineD3DDeviceImpl_EndScene,
6868 IWineD3DDeviceImpl_Present,
6869 IWineD3DDeviceImpl_Clear,
6870 IWineD3DDeviceImpl_ClearRendertargetView,
6871 /*** Drawing ***/
6872 IWineD3DDeviceImpl_SetPrimitiveType,
6873 IWineD3DDeviceImpl_GetPrimitiveType,
6874 IWineD3DDeviceImpl_DrawPrimitive,
6875 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6876 IWineD3DDeviceImpl_DrawPrimitiveUP,
6877 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6878 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6879 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6880 IWineD3DDeviceImpl_DrawRectPatch,
6881 IWineD3DDeviceImpl_DrawTriPatch,
6882 IWineD3DDeviceImpl_DeletePatch,
6883 IWineD3DDeviceImpl_ColorFill,
6884 IWineD3DDeviceImpl_UpdateTexture,
6885 IWineD3DDeviceImpl_UpdateSurface,
6886 IWineD3DDeviceImpl_GetFrontBufferData,
6887 /*** object tracking ***/
6888 IWineD3DDeviceImpl_EnumResources
6891 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6892 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6893 IUnknown *parent, IWineD3DDeviceParent *device_parent)
6895 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6896 const struct fragment_pipeline *fragment_pipeline;
6897 struct shader_caps shader_caps;
6898 struct fragment_caps ffp_caps;
6899 WINED3DDISPLAYMODE mode;
6900 unsigned int i;
6901 HRESULT hr;
6903 device->lpVtbl = &IWineD3DDevice_Vtbl;
6904 device->ref = 1;
6905 device->wined3d = (IWineD3D *)wined3d;
6906 IWineD3D_AddRef(device->wined3d);
6907 device->adapter = wined3d->adapter_count ? adapter : NULL;
6908 device->parent = parent;
6909 device->device_parent = device_parent;
6910 list_init(&device->resources);
6911 list_init(&device->shaders);
6913 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6914 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6916 /* Get the initial screen setup for ddraw. */
6917 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6918 if (FAILED(hr))
6920 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6921 IWineD3D_Release(device->wined3d);
6922 return hr;
6924 device->ddraw_width = mode.Width;
6925 device->ddraw_height = mode.Height;
6926 device->ddraw_format = mode.Format;
6928 /* Save the creation parameters. */
6929 device->createParms.AdapterOrdinal = adapter_idx;
6930 device->createParms.DeviceType = device_type;
6931 device->createParms.hFocusWindow = focus_window;
6932 device->createParms.BehaviorFlags = flags;
6934 device->devType = device_type;
6935 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6937 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6938 device->shader_backend = select_shader_backend(adapter, device_type);
6940 memset(&shader_caps, 0, sizeof(shader_caps));
6941 device->shader_backend->shader_get_caps(device_type, &adapter->gl_info, &shader_caps);
6942 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6943 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6944 device->vs_clipping = shader_caps.VSClipping;
6946 memset(&ffp_caps, 0, sizeof(ffp_caps));
6947 fragment_pipeline = select_fragment_implementation(adapter, device_type);
6948 device->frag_pipe = fragment_pipeline;
6949 fragment_pipeline->get_caps(device_type, &adapter->gl_info, &ffp_caps);
6950 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6951 device->max_ffp_texture_stages = ffp_caps.MaxTextureBlendStages;
6953 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6954 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6955 if (FAILED(hr))
6957 ERR("Failed to compile state table, hr %#x.\n", hr);
6958 IWineD3D_Release(device->wined3d);
6959 return hr;
6962 device->blitter = select_blit_implementation(adapter, device_type);
6964 return WINED3D_OK;
6968 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6969 DWORD rep = This->StateTable[state].representative;
6970 struct wined3d_context *context;
6971 DWORD idx;
6972 BYTE shift;
6973 UINT i;
6975 for(i = 0; i < This->numContexts; i++) {
6976 context = This->contexts[i];
6977 if(isStateDirty(context, rep)) continue;
6979 context->dirtyArray[context->numDirtyEntries++] = rep;
6980 idx = rep >> 5;
6981 shift = rep & 0x1f;
6982 context->isStateDirty[idx] |= (1 << shift);
6986 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6988 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.device;
6989 /* The drawable size of a pbuffer render target is the current pbuffer size. */
6990 *width = device->pbufferWidth;
6991 *height = device->pbufferHeight;
6994 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6996 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
6997 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6998 *width = surface->pow2Width;
6999 *height = surface->pow2Height;
7002 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7004 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7005 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7006 * current context's drawable, which is the size of the back buffer of the swapchain
7007 * the active context belongs to. The back buffer of the swapchain is stored as the
7008 * surface the context belongs to. */
7009 *width = surface->currentDesc.Width;
7010 *height = surface->currentDesc.Height;