wined3d: Use the element size to create "isStateDirty" bitmap indices.
[wine.git] / dlls / wined3d / device.c
blobd0660b43efd8c40b46f653729e0b4a0498981a94
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,
483 UINT Size, DWORD Usage, 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;
490 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
491 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
493 if (Pool == WINED3DPOOL_SCRATCH)
495 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
496 * anyway, SCRATCH vertex buffers aren't usable anywhere
498 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
499 *ppVertexBuffer = NULL;
500 return WINED3DERR_INVALIDCALL;
503 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
504 if (!object)
506 ERR("Out of memory\n");
507 *ppVertexBuffer = NULL;
508 return WINED3DERR_OUTOFVIDEOMEMORY;
511 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
512 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
513 if (FAILED(hr))
515 WARN("Failed to initialize buffer, hr %#x.\n", hr);
516 HeapFree(GetProcessHeap(), 0, object);
517 return hr;
520 TRACE("Created buffer %p.\n", object);
521 *ppVertexBuffer = (IWineD3DBuffer *)object;
523 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
524 * drawStridedFast (half-life 2).
526 * Basically converting the vertices in the buffer is quite expensive, and observations
527 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
528 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
530 if (!This->adapter->gl_info.supported[ARB_VERTEX_BUFFER_OBJECT])
532 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
533 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
534 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
535 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
536 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
537 } else {
538 object->flags |= WINED3D_BUFFER_CREATEBO;
540 return WINED3D_OK;
543 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
544 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
545 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
548 struct wined3d_buffer *object;
549 HRESULT hr;
551 TRACE("(%p) Creating index buffer\n", This);
553 /* Allocate the storage for the device */
554 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
555 if (!object)
557 ERR("Out of memory\n");
558 *ppIndexBuffer = NULL;
559 return WINED3DERR_OUTOFVIDEOMEMORY;
562 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
563 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
564 if (FAILED(hr))
566 WARN("Failed to initialize buffer, hr %#x\n", hr);
567 HeapFree(GetProcessHeap(), 0, object);
568 return hr;
571 TRACE("Created buffer %p.\n", object);
573 if (Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC)
574 && This->adapter->gl_info.supported[ARB_VERTEX_BUFFER_OBJECT])
576 object->flags |= WINED3D_BUFFER_CREATEBO;
579 *ppIndexBuffer = (IWineD3DBuffer *) object;
581 return WINED3D_OK;
584 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
585 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
588 IWineD3DStateBlockImpl *object;
589 HRESULT hr;
591 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
592 if(!object)
594 ERR("Failed to allocate stateblock memory.\n");
595 return E_OUTOFMEMORY;
598 hr = stateblock_init(object, This, type);
599 if (FAILED(hr))
601 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
602 HeapFree(GetProcessHeap(), 0, object);
603 return hr;
606 TRACE("Created stateblock %p.\n", object);
607 *stateblock = (IWineD3DStateBlock *)object;
609 return WINED3D_OK;
612 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
613 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
614 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
615 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
618 IWineD3DSurfaceImpl *object;
619 HRESULT hr;
621 TRACE("(%p) Create surface\n",This);
623 if (Impl == SURFACE_OPENGL && !This->adapter)
625 ERR("OpenGL surfaces are not available without OpenGL.\n");
626 return WINED3DERR_NOTAVAILABLE;
629 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
630 if (!object)
632 ERR("Failed to allocate surface memory.\n");
633 return WINED3DERR_OUTOFVIDEOMEMORY;
636 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
637 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
638 if (FAILED(hr))
640 WARN("Failed to initialize surface, returning %#x.\n", hr);
641 HeapFree(GetProcessHeap(), 0, object);
642 return hr;
645 TRACE("(%p) : Created surface %p\n", This, object);
647 *ppSurface = (IWineD3DSurface *)object;
649 return hr;
652 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
653 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
655 struct wined3d_rendertarget_view *object;
657 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
658 if (!object)
660 ERR("Failed to allocate memory\n");
661 return E_OUTOFMEMORY;
664 object->vtbl = &wined3d_rendertarget_view_vtbl;
665 object->refcount = 1;
666 IWineD3DResource_AddRef(resource);
667 object->resource = resource;
668 object->parent = parent;
670 *rendertarget_view = (IWineD3DRendertargetView *)object;
672 return WINED3D_OK;
675 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
676 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
677 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
680 IWineD3DTextureImpl *object;
681 HRESULT hr;
683 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
684 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
685 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
687 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
688 if (!object)
690 ERR("Out of memory\n");
691 *ppTexture = NULL;
692 return WINED3DERR_OUTOFVIDEOMEMORY;
695 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
696 if (FAILED(hr))
698 WARN("Failed to initialize texture, returning %#x\n", hr);
699 HeapFree(GetProcessHeap(), 0, object);
700 *ppTexture = NULL;
701 return hr;
704 *ppTexture = (IWineD3DTexture *)object;
706 TRACE("(%p) : Created texture %p\n", This, object);
708 return WINED3D_OK;
711 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
712 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
713 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
716 IWineD3DVolumeTextureImpl *object;
717 HRESULT hr;
719 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
720 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
722 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
723 if (!object)
725 ERR("Out of memory\n");
726 *ppVolumeTexture = NULL;
727 return WINED3DERR_OUTOFVIDEOMEMORY;
730 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
731 if (FAILED(hr))
733 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
734 HeapFree(GetProcessHeap(), 0, object);
735 *ppVolumeTexture = NULL;
736 return hr;
739 TRACE("(%p) : Created volume texture %p.\n", This, object);
740 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
742 return WINED3D_OK;
745 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
746 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
747 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
749 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
750 IWineD3DVolumeImpl *object;
751 HRESULT hr;
753 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
754 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
756 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
757 if (!object)
759 ERR("Out of memory\n");
760 *ppVolume = NULL;
761 return WINED3DERR_OUTOFVIDEOMEMORY;
764 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
765 if (FAILED(hr))
767 WARN("Failed to initialize volume, returning %#x.\n", hr);
768 HeapFree(GetProcessHeap(), 0, object);
769 return hr;
772 TRACE("(%p) : Created volume %p.\n", This, object);
773 *ppVolume = (IWineD3DVolume *)object;
775 return WINED3D_OK;
778 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
779 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
780 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
783 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
784 HRESULT hr;
786 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
787 if (!object)
789 ERR("Out of memory\n");
790 *ppCubeTexture = NULL;
791 return WINED3DERR_OUTOFVIDEOMEMORY;
794 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
795 if (FAILED(hr))
797 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
798 HeapFree(GetProcessHeap(), 0, object);
799 *ppCubeTexture = NULL;
800 return hr;
803 TRACE("(%p) : Created Cube Texture %p\n", This, object);
804 *ppCubeTexture = (IWineD3DCubeTexture *)object;
806 return WINED3D_OK;
809 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
811 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
812 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
813 HRESULT hr = WINED3DERR_NOTAVAILABLE;
814 const IWineD3DQueryVtbl *vtable;
816 /* Just a check to see if we support this type of query */
817 switch(Type) {
818 case WINED3DQUERYTYPE_OCCLUSION:
819 TRACE("(%p) occlusion query\n", This);
820 if (gl_info->supported[ARB_OCCLUSION_QUERY])
821 hr = WINED3D_OK;
822 else
823 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
825 vtable = &IWineD3DOcclusionQuery_Vtbl;
826 break;
828 case WINED3DQUERYTYPE_EVENT:
829 if (!gl_info->supported[NV_FENCE] && !gl_info->supported[APPLE_FENCE])
831 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
832 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
834 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
836 vtable = &IWineD3DEventQuery_Vtbl;
837 hr = WINED3D_OK;
838 break;
840 case WINED3DQUERYTYPE_VCACHE:
841 case WINED3DQUERYTYPE_RESOURCEMANAGER:
842 case WINED3DQUERYTYPE_VERTEXSTATS:
843 case WINED3DQUERYTYPE_TIMESTAMP:
844 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
845 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
846 case WINED3DQUERYTYPE_PIPELINETIMINGS:
847 case WINED3DQUERYTYPE_INTERFACETIMINGS:
848 case WINED3DQUERYTYPE_VERTEXTIMINGS:
849 case WINED3DQUERYTYPE_PIXELTIMINGS:
850 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
851 case WINED3DQUERYTYPE_CACHEUTILIZATION:
852 default:
853 /* Use the base Query vtable until we have a special one for each query */
854 vtable = &IWineD3DQuery_Vtbl;
855 FIXME("(%p) Unhandled query type %d\n", This, Type);
857 if(NULL == ppQuery || hr != WINED3D_OK) {
858 return hr;
861 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
862 if(!object)
864 ERR("Out of memory\n");
865 *ppQuery = NULL;
866 return WINED3DERR_OUTOFVIDEOMEMORY;
869 object->lpVtbl = vtable;
870 object->type = Type;
871 object->state = QUERY_CREATED;
872 object->device = This;
873 object->parent = parent;
874 object->ref = 1;
876 *ppQuery = (IWineD3DQuery *)object;
878 /* allocated the 'extended' data based on the type of query requested */
879 switch(Type){
880 case WINED3DQUERYTYPE_OCCLUSION:
881 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
882 ((struct wined3d_occlusion_query *)object->extendedData)->context = NULL;
883 break;
885 case WINED3DQUERYTYPE_EVENT:
886 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query));
887 ((struct wined3d_event_query *)object->extendedData)->context = NULL;
888 break;
890 case WINED3DQUERYTYPE_VCACHE:
891 case WINED3DQUERYTYPE_RESOURCEMANAGER:
892 case WINED3DQUERYTYPE_VERTEXSTATS:
893 case WINED3DQUERYTYPE_TIMESTAMP:
894 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
895 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
896 case WINED3DQUERYTYPE_PIPELINETIMINGS:
897 case WINED3DQUERYTYPE_INTERFACETIMINGS:
898 case WINED3DQUERYTYPE_VERTEXTIMINGS:
899 case WINED3DQUERYTYPE_PIXELTIMINGS:
900 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
901 case WINED3DQUERYTYPE_CACHEUTILIZATION:
902 default:
903 object->extendedData = 0;
904 FIXME("(%p) Unhandled query type %d\n",This , Type);
906 TRACE("(%p) : Created Query %p\n", This, object);
907 return WINED3D_OK;
910 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
911 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
912 IUnknown *parent, WINED3DSURFTYPE surface_type)
914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
915 IWineD3DSwapChainImpl *object;
916 HRESULT hr;
918 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
919 iface, present_parameters, swapchain, parent, surface_type);
921 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
922 if (!object)
924 ERR("Failed to allocate swapchain memory.\n");
925 return E_OUTOFMEMORY;
928 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
929 if (FAILED(hr))
931 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
932 HeapFree(GetProcessHeap(), 0, object);
933 return hr;
936 TRACE("Created swapchain %p.\n", object);
937 *swapchain = (IWineD3DSwapChain *)object;
939 return WINED3D_OK;
942 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
943 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
945 TRACE("(%p)\n", This);
947 return This->NumberOfSwapChains;
950 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
952 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
954 if(iSwapChain < This->NumberOfSwapChains) {
955 *pSwapChain = This->swapchains[iSwapChain];
956 IWineD3DSwapChain_AddRef(*pSwapChain);
957 TRACE("(%p) returning %p\n", This, *pSwapChain);
958 return WINED3D_OK;
959 } else {
960 TRACE("Swapchain out of range\n");
961 *pSwapChain = NULL;
962 return WINED3DERR_INVALIDCALL;
966 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
967 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
968 const WINED3DVERTEXELEMENT *elements, UINT element_count)
970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
971 IWineD3DVertexDeclarationImpl *object = NULL;
972 HRESULT hr;
974 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
975 iface, declaration, parent, elements, element_count);
977 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
978 if(!object)
980 ERR("Failed to allocate vertex declaration memory.\n");
981 return E_OUTOFMEMORY;
984 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
985 if (FAILED(hr))
987 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
988 HeapFree(GetProcessHeap(), 0, object);
989 return hr;
992 TRACE("Created vertex declaration %p.\n", object);
993 *declaration = (IWineD3DVertexDeclaration *)object;
995 return WINED3D_OK;
998 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
999 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1001 unsigned int idx, idx2;
1002 unsigned int offset;
1003 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1004 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1005 BOOL has_blend_idx = has_blend &&
1006 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1007 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1008 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1009 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1010 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1011 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1012 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1014 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1015 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1016 WINED3DVERTEXELEMENT *elements = NULL;
1018 unsigned int size;
1019 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1020 if (has_blend_idx) num_blends--;
1022 /* Compute declaration size */
1023 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1024 has_psize + has_diffuse + has_specular + num_textures;
1026 /* convert the declaration */
1027 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1028 if (!elements) return ~0U;
1030 idx = 0;
1031 if (has_pos) {
1032 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1033 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1034 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1036 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1037 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1038 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1040 else {
1041 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1042 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1044 elements[idx].usage_idx = 0;
1045 idx++;
1047 if (has_blend && (num_blends > 0)) {
1048 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1049 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1050 else {
1051 switch(num_blends) {
1052 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1053 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1054 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1055 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1056 default:
1057 ERR("Unexpected amount of blend values: %u\n", num_blends);
1060 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1061 elements[idx].usage_idx = 0;
1062 idx++;
1064 if (has_blend_idx) {
1065 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1066 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1067 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1068 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1069 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1070 else
1071 elements[idx].format = WINED3DFMT_R32_FLOAT;
1072 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1073 elements[idx].usage_idx = 0;
1074 idx++;
1076 if (has_normal) {
1077 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1078 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1079 elements[idx].usage_idx = 0;
1080 idx++;
1082 if (has_psize) {
1083 elements[idx].format = WINED3DFMT_R32_FLOAT;
1084 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1085 elements[idx].usage_idx = 0;
1086 idx++;
1088 if (has_diffuse) {
1089 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1090 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1091 elements[idx].usage_idx = 0;
1092 idx++;
1094 if (has_specular) {
1095 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1096 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1097 elements[idx].usage_idx = 1;
1098 idx++;
1100 for (idx2 = 0; idx2 < num_textures; idx2++) {
1101 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1102 switch (numcoords) {
1103 case WINED3DFVF_TEXTUREFORMAT1:
1104 elements[idx].format = WINED3DFMT_R32_FLOAT;
1105 break;
1106 case WINED3DFVF_TEXTUREFORMAT2:
1107 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1108 break;
1109 case WINED3DFVF_TEXTUREFORMAT3:
1110 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1111 break;
1112 case WINED3DFVF_TEXTUREFORMAT4:
1113 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1114 break;
1116 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1117 elements[idx].usage_idx = idx2;
1118 idx++;
1121 /* Now compute offsets, and initialize the rest of the fields */
1122 for (idx = 0, offset = 0; idx < size; ++idx)
1124 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1125 elements[idx].input_slot = 0;
1126 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1127 elements[idx].offset = offset;
1128 offset += format_desc->component_count * format_desc->component_size;
1131 *ppVertexElements = elements;
1132 return size;
1135 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1136 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1137 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1140 WINED3DVERTEXELEMENT *elements;
1141 unsigned int size;
1142 DWORD hr;
1144 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1146 size = ConvertFvfToDeclaration(This, fvf, &elements);
1147 if (size == ~0U) return E_OUTOFMEMORY;
1149 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1150 HeapFree(GetProcessHeap(), 0, elements);
1151 return hr;
1154 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1155 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1156 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1157 const struct wined3d_parent_ops *parent_ops)
1159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1160 IWineD3DVertexShaderImpl *object;
1161 HRESULT hr;
1163 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1164 if (!object)
1166 ERR("Failed to allocate shader memory.\n");
1167 return E_OUTOFMEMORY;
1170 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1171 if (FAILED(hr))
1173 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1174 HeapFree(GetProcessHeap(), 0, object);
1175 return hr;
1178 TRACE("Created vertex shader %p.\n", object);
1179 *ppVertexShader = (IWineD3DVertexShader *)object;
1181 return WINED3D_OK;
1184 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1185 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1186 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1187 const struct wined3d_parent_ops *parent_ops)
1189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1190 IWineD3DPixelShaderImpl *object;
1191 HRESULT hr;
1193 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1194 if (!object)
1196 ERR("Failed to allocate shader memory.\n");
1197 return E_OUTOFMEMORY;
1200 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1201 if (FAILED(hr))
1203 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1204 HeapFree(GetProcessHeap(), 0, object);
1205 return hr;
1208 TRACE("Created pixel shader %p.\n", object);
1209 *ppPixelShader = (IWineD3DPixelShader *)object;
1211 return WINED3D_OK;
1214 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1215 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1218 IWineD3DPaletteImpl *object;
1219 HRESULT hr;
1220 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1222 /* Create the new object */
1223 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1224 if(!object) {
1225 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1226 return E_OUTOFMEMORY;
1229 object->lpVtbl = &IWineD3DPalette_Vtbl;
1230 object->ref = 1;
1231 object->Flags = Flags;
1232 object->parent = Parent;
1233 object->device = This;
1234 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1235 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1237 if(!object->hpal) {
1238 HeapFree( GetProcessHeap(), 0, object);
1239 return E_OUTOFMEMORY;
1242 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1243 if(FAILED(hr)) {
1244 IWineD3DPalette_Release((IWineD3DPalette *) object);
1245 return hr;
1248 *Palette = (IWineD3DPalette *) object;
1250 return WINED3D_OK;
1253 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1254 HBITMAP hbm;
1255 BITMAP bm;
1256 HRESULT hr;
1257 HDC dcb = NULL, dcs = NULL;
1258 WINEDDCOLORKEY colorkey;
1260 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1261 if(hbm)
1263 GetObjectA(hbm, sizeof(BITMAP), &bm);
1264 dcb = CreateCompatibleDC(NULL);
1265 if(!dcb) goto out;
1266 SelectObject(dcb, hbm);
1268 else
1270 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1271 * couldn't be loaded
1273 memset(&bm, 0, sizeof(bm));
1274 bm.bmWidth = 32;
1275 bm.bmHeight = 32;
1278 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1279 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1280 NULL, &wined3d_null_parent_ops);
1281 if(FAILED(hr)) {
1282 ERR("Wine logo requested, but failed to create surface\n");
1283 goto out;
1286 if(dcb) {
1287 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1288 if(FAILED(hr)) goto out;
1289 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1290 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1292 colorkey.dwColorSpaceLowValue = 0;
1293 colorkey.dwColorSpaceHighValue = 0;
1294 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1295 } else {
1296 /* Fill the surface with a white color to show that wined3d is there */
1297 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1300 out:
1301 if (dcb) DeleteDC(dcb);
1302 if (hbm) DeleteObject(hbm);
1305 /* Context activation is done by the caller. */
1306 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1308 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1309 unsigned int i;
1310 /* Under DirectX you can have texture stage operations even if no texture is
1311 bound, whereas opengl will only do texture operations when a valid texture is
1312 bound. We emulate this by creating dummy textures and binding them to each
1313 texture stage, but disable all stages by default. Hence if a stage is enabled
1314 then the default texture will kick in until replaced by a SetTexture call */
1315 ENTER_GL();
1317 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1319 /* The dummy texture does not have client storage backing */
1320 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1321 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1324 for (i = 0; i < gl_info->limits.textures; ++i)
1326 GLubyte white = 255;
1328 /* Make appropriate texture active */
1329 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1330 checkGLcall("glActiveTextureARB");
1332 /* Generate an opengl texture name */
1333 glGenTextures(1, &This->dummyTextureName[i]);
1334 checkGLcall("glGenTextures");
1335 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1337 /* Generate a dummy 2d texture (not using 1d because they cause many
1338 * DRI drivers fall back to sw) */
1339 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1340 checkGLcall("glBindTexture");
1342 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1343 checkGLcall("glTexImage2D");
1346 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1348 /* Reenable because if supported it is enabled by default */
1349 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1350 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1353 LEAVE_GL();
1356 /* Context activation is done by the caller. */
1357 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1359 ENTER_GL();
1360 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1361 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1362 LEAVE_GL();
1364 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1367 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1368 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1370 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1371 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1372 IWineD3DSwapChainImpl *swapchain = NULL;
1373 struct wined3d_context *context;
1374 HRESULT hr;
1375 DWORD state;
1376 unsigned int i;
1378 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1380 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1381 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1383 if (!pPresentationParameters->Windowed)
1385 This->focus_window = This->createParms.hFocusWindow;
1386 if (!This->focus_window) This->focus_window = pPresentationParameters->hDeviceWindow;
1387 if (!wined3d_register_window(This->focus_window, This))
1389 ERR("Failed to register window %p.\n", This->focus_window);
1390 return E_FAIL;
1394 TRACE("(%p) : Creating stateblock\n", This);
1395 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1396 hr = IWineD3DDevice_CreateStateBlock(iface,
1397 WINED3DSBT_INIT,
1398 (IWineD3DStateBlock **)&This->stateBlock,
1399 NULL);
1400 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1401 WARN("Failed to create stateblock\n");
1402 goto err_out;
1404 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1405 This->updateStateBlock = This->stateBlock;
1406 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1408 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1409 sizeof(IWineD3DSurface *) * gl_info->limits.buffers);
1410 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1411 sizeof(GLenum) * gl_info->limits.buffers);
1413 This->NumberOfPalettes = 1;
1414 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1415 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1416 ERR("Out of memory!\n");
1417 hr = E_OUTOFMEMORY;
1418 goto err_out;
1420 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1421 if(!This->palettes[0]) {
1422 ERR("Out of memory!\n");
1423 hr = E_OUTOFMEMORY;
1424 goto err_out;
1426 for (i = 0; i < 256; ++i) {
1427 This->palettes[0][i].peRed = 0xFF;
1428 This->palettes[0][i].peGreen = 0xFF;
1429 This->palettes[0][i].peBlue = 0xFF;
1430 This->palettes[0][i].peFlags = 0xFF;
1432 This->currentPalette = 0;
1434 /* Initialize the texture unit mapping to a 1:1 mapping */
1435 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1437 if (state < gl_info->limits.fragment_samplers)
1439 This->texUnitMap[state] = state;
1440 This->rev_tex_unit_map[state] = state;
1441 } else {
1442 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1443 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1447 if (This->focus_window) SetFocus(This->focus_window);
1449 /* Setup the implicit swapchain. This also initializes a context. */
1450 TRACE("Creating implicit swapchain\n");
1451 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1452 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1453 if (FAILED(hr))
1455 WARN("Failed to create implicit swapchain\n");
1456 goto err_out;
1459 This->NumberOfSwapChains = 1;
1460 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1461 if(!This->swapchains) {
1462 ERR("Out of memory!\n");
1463 goto err_out;
1465 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1467 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1468 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1469 This->render_targets[0] = swapchain->backBuffer[0];
1471 else {
1472 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1473 This->render_targets[0] = swapchain->frontBuffer;
1475 IWineD3DSurface_AddRef(This->render_targets[0]);
1477 /* Depth Stencil support */
1478 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1479 if (NULL != This->stencilBufferTarget) {
1480 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1483 hr = This->shader_backend->shader_alloc_private(iface);
1484 if(FAILED(hr)) {
1485 TRACE("Shader private data couldn't be allocated\n");
1486 goto err_out;
1488 hr = This->frag_pipe->alloc_private(iface);
1489 if(FAILED(hr)) {
1490 TRACE("Fragment pipeline private data couldn't be allocated\n");
1491 goto err_out;
1493 hr = This->blitter->alloc_private(iface);
1494 if(FAILED(hr)) {
1495 TRACE("Blitter private data couldn't be allocated\n");
1496 goto err_out;
1499 /* Set up some starting GL setup */
1501 /* Setup all the devices defaults */
1502 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1504 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1506 create_dummy_textures(This);
1508 ENTER_GL();
1510 /* Initialize the current view state */
1511 This->view_ident = 1;
1512 This->contexts[0]->last_was_rhw = 0;
1513 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1514 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1516 switch(wined3d_settings.offscreen_rendering_mode) {
1517 case ORM_FBO:
1518 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1519 break;
1521 case ORM_PBUFFER:
1522 This->offscreenBuffer = GL_BACK;
1523 break;
1525 case ORM_BACKBUFFER:
1527 if (context_get_current()->aux_buffers > 0)
1529 TRACE("Using auxilliary buffer for offscreen rendering\n");
1530 This->offscreenBuffer = GL_AUX0;
1531 } else {
1532 TRACE("Using back buffer for offscreen rendering\n");
1533 This->offscreenBuffer = GL_BACK;
1538 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1539 LEAVE_GL();
1541 context_release(context);
1543 /* Clear the screen */
1544 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1545 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1546 0x00, 1.0f, 0);
1548 This->d3d_initialized = TRUE;
1550 if(wined3d_settings.logo) {
1551 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1553 This->highest_dirty_ps_const = 0;
1554 This->highest_dirty_vs_const = 0;
1555 return WINED3D_OK;
1557 err_out:
1558 HeapFree(GetProcessHeap(), 0, This->render_targets);
1559 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1560 HeapFree(GetProcessHeap(), 0, This->swapchains);
1561 This->NumberOfSwapChains = 0;
1562 if(This->palettes) {
1563 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1564 HeapFree(GetProcessHeap(), 0, This->palettes);
1566 This->NumberOfPalettes = 0;
1567 if(swapchain) {
1568 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1570 if(This->stateBlock) {
1571 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1572 This->stateBlock = NULL;
1574 if (This->blit_priv) {
1575 This->blitter->free_private(iface);
1577 if (This->fragment_priv) {
1578 This->frag_pipe->free_private(iface);
1580 if (This->shader_priv) {
1581 This->shader_backend->shader_free_private(iface);
1583 if (This->focus_window) wined3d_unregister_window(This->focus_window);
1584 return hr;
1587 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1588 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1591 IWineD3DSwapChainImpl *swapchain = NULL;
1592 HRESULT hr;
1594 /* Setup the implicit swapchain */
1595 TRACE("Creating implicit swapchain\n");
1596 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1597 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1598 if (FAILED(hr))
1600 WARN("Failed to create implicit swapchain\n");
1601 goto err_out;
1604 This->NumberOfSwapChains = 1;
1605 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1606 if(!This->swapchains) {
1607 ERR("Out of memory!\n");
1608 goto err_out;
1610 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1611 return WINED3D_OK;
1613 err_out:
1614 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1615 return hr;
1618 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1620 IWineD3DResource_UnLoad(resource);
1621 IWineD3DResource_Release(resource);
1622 return WINED3D_OK;
1625 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1626 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1629 const struct wined3d_gl_info *gl_info;
1630 struct wined3d_context *context;
1631 int sampler;
1632 UINT i;
1633 TRACE("(%p)\n", This);
1635 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1637 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1638 * it was created. Thus make sure a context is active for the glDelete* calls
1640 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1641 gl_info = context->gl_info;
1643 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1645 /* Unload resources */
1646 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1648 TRACE("Deleting high order patches\n");
1649 for(i = 0; i < PATCHMAP_SIZE; i++) {
1650 struct list *e1, *e2;
1651 struct WineD3DRectPatch *patch;
1652 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1653 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1654 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1658 /* Delete the palette conversion shader if it is around */
1659 if(This->paletteConversionShader) {
1660 ENTER_GL();
1661 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
1662 LEAVE_GL();
1663 This->paletteConversionShader = 0;
1666 /* Delete the pbuffer context if there is any */
1667 if(This->pbufferContext) context_destroy(This, This->pbufferContext);
1669 /* Delete the mouse cursor texture */
1670 if(This->cursorTexture) {
1671 ENTER_GL();
1672 glDeleteTextures(1, &This->cursorTexture);
1673 LEAVE_GL();
1674 This->cursorTexture = 0;
1677 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1678 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1680 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1681 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1684 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1685 * private data, it might contain opengl pointers
1687 if(This->depth_blt_texture) {
1688 ENTER_GL();
1689 glDeleteTextures(1, &This->depth_blt_texture);
1690 LEAVE_GL();
1691 This->depth_blt_texture = 0;
1693 if (This->depth_blt_rb) {
1694 ENTER_GL();
1695 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1696 LEAVE_GL();
1697 This->depth_blt_rb = 0;
1698 This->depth_blt_rb_w = 0;
1699 This->depth_blt_rb_h = 0;
1702 /* Release the update stateblock */
1703 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1704 if(This->updateStateBlock != This->stateBlock)
1705 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1707 This->updateStateBlock = NULL;
1709 { /* because were not doing proper internal refcounts releasing the primary state block
1710 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1711 to set this->stateBlock = NULL; first */
1712 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1713 This->stateBlock = NULL;
1715 /* Release the stateblock */
1716 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1717 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1721 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1722 This->blitter->free_private(iface);
1723 This->frag_pipe->free_private(iface);
1724 This->shader_backend->shader_free_private(iface);
1726 /* Release the buffers (with sanity checks)*/
1727 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1728 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1729 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
1730 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
1732 This->stencilBufferTarget = NULL;
1734 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1735 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1736 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1738 TRACE("Setting rendertarget to NULL\n");
1739 This->render_targets[0] = NULL;
1741 if (This->auto_depth_stencil_buffer) {
1742 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
1744 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1746 This->auto_depth_stencil_buffer = NULL;
1749 context_release(context);
1751 for(i=0; i < This->NumberOfSwapChains; i++) {
1752 TRACE("Releasing the implicit swapchain %d\n", i);
1753 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1754 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1758 HeapFree(GetProcessHeap(), 0, This->swapchains);
1759 This->swapchains = NULL;
1760 This->NumberOfSwapChains = 0;
1762 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1763 HeapFree(GetProcessHeap(), 0, This->palettes);
1764 This->palettes = NULL;
1765 This->NumberOfPalettes = 0;
1767 HeapFree(GetProcessHeap(), 0, This->render_targets);
1768 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1769 This->render_targets = NULL;
1770 This->draw_buffers = NULL;
1772 This->d3d_initialized = FALSE;
1774 if (This->focus_window) wined3d_unregister_window(This->focus_window);
1776 return WINED3D_OK;
1779 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1781 unsigned int i;
1783 for(i=0; i < This->NumberOfSwapChains; i++) {
1784 TRACE("Releasing the implicit swapchain %d\n", i);
1785 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1786 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1790 HeapFree(GetProcessHeap(), 0, This->swapchains);
1791 This->swapchains = NULL;
1792 This->NumberOfSwapChains = 0;
1793 return WINED3D_OK;
1796 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1797 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1798 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1800 * There is no way to deactivate thread safety once it is enabled.
1802 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1805 /*For now just store the flag(needed in case of ddraw) */
1806 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1809 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1810 const WINED3DDISPLAYMODE* pMode) {
1811 DEVMODEW devmode;
1812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1813 LONG ret;
1814 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1815 RECT clip_rc;
1817 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1819 /* Resize the screen even without a window:
1820 * The app could have unset it with SetCooperativeLevel, but not called
1821 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1822 * but we don't have any hwnd
1825 memset(&devmode, 0, sizeof(devmode));
1826 devmode.dmSize = sizeof(devmode);
1827 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1828 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1829 devmode.dmPelsWidth = pMode->Width;
1830 devmode.dmPelsHeight = pMode->Height;
1832 devmode.dmDisplayFrequency = pMode->RefreshRate;
1833 if (pMode->RefreshRate != 0) {
1834 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1837 /* Only change the mode if necessary */
1838 if( (This->ddraw_width == pMode->Width) &&
1839 (This->ddraw_height == pMode->Height) &&
1840 (This->ddraw_format == pMode->Format) &&
1841 (pMode->RefreshRate == 0) ) {
1842 return WINED3D_OK;
1845 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1846 if (ret != DISP_CHANGE_SUCCESSFUL) {
1847 if(devmode.dmDisplayFrequency != 0) {
1848 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1849 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1850 devmode.dmDisplayFrequency = 0;
1851 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1853 if(ret != DISP_CHANGE_SUCCESSFUL) {
1854 return WINED3DERR_NOTAVAILABLE;
1858 /* Store the new values */
1859 This->ddraw_width = pMode->Width;
1860 This->ddraw_height = pMode->Height;
1861 This->ddraw_format = pMode->Format;
1863 /* And finally clip mouse to our screen */
1864 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1865 ClipCursor(&clip_rc);
1867 return WINED3D_OK;
1870 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1872 *ppD3D = This->wined3d;
1873 TRACE("Returning %p.\n", *ppD3D);
1874 IWineD3D_AddRef(*ppD3D);
1875 return WINED3D_OK;
1878 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1881 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1882 (This->adapter->TextureRam/(1024*1024)),
1883 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
1884 /* return simulated texture memory left */
1885 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
1888 /*****
1889 * Get / Set Stream Source
1890 *****/
1891 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
1892 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
1894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1895 IWineD3DBuffer *oldSrc;
1897 if (StreamNumber >= MAX_STREAMS) {
1898 WARN("Stream out of range %d\n", StreamNumber);
1899 return WINED3DERR_INVALIDCALL;
1900 } else if(OffsetInBytes & 0x3) {
1901 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
1902 return WINED3DERR_INVALIDCALL;
1905 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
1906 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
1908 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
1910 if(oldSrc == pStreamData &&
1911 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
1912 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
1913 TRACE("Application is setting the old values over, nothing to do\n");
1914 return WINED3D_OK;
1917 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
1918 if (pStreamData) {
1919 This->updateStateBlock->streamStride[StreamNumber] = Stride;
1920 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
1923 /* Handle recording of state blocks */
1924 if (This->isRecordingState) {
1925 TRACE("Recording... not performing anything\n");
1926 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
1927 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
1928 return WINED3D_OK;
1931 if (pStreamData != NULL) {
1932 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
1933 IWineD3DBuffer_AddRef(pStreamData);
1935 if (oldSrc != NULL) {
1936 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
1937 IWineD3DBuffer_Release(oldSrc);
1940 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
1942 return WINED3D_OK;
1945 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
1946 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
1948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1950 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
1951 This->stateBlock->streamSource[StreamNumber],
1952 This->stateBlock->streamOffset[StreamNumber],
1953 This->stateBlock->streamStride[StreamNumber]);
1955 if (StreamNumber >= MAX_STREAMS) {
1956 WARN("Stream out of range %d\n", StreamNumber);
1957 return WINED3DERR_INVALIDCALL;
1959 *pStream = This->stateBlock->streamSource[StreamNumber];
1960 *pStride = This->stateBlock->streamStride[StreamNumber];
1961 if (pOffset) {
1962 *pOffset = This->stateBlock->streamOffset[StreamNumber];
1965 if (*pStream != NULL) {
1966 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
1968 return WINED3D_OK;
1971 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
1972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1973 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
1974 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
1976 /* Verify input at least in d3d9 this is invalid*/
1977 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
1978 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
1979 return WINED3DERR_INVALIDCALL;
1981 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
1982 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
1983 return WINED3DERR_INVALIDCALL;
1985 if( Divider == 0 ){
1986 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
1987 return WINED3DERR_INVALIDCALL;
1990 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
1991 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
1993 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
1994 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
1996 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
1997 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
1998 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2001 return WINED3D_OK;
2004 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2007 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2008 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2010 TRACE("(%p) : returning %d\n", This, *Divider);
2012 return WINED3D_OK;
2015 /*****
2016 * Get / Set & Multiply Transform
2017 *****/
2018 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2021 /* Most of this routine, comments included copied from ddraw tree initially: */
2022 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2024 /* Handle recording of state blocks */
2025 if (This->isRecordingState) {
2026 TRACE("Recording... not performing anything\n");
2027 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2028 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2029 return WINED3D_OK;
2033 * If the new matrix is the same as the current one,
2034 * we cut off any further processing. this seems to be a reasonable
2035 * optimization because as was noticed, some apps (warcraft3 for example)
2036 * tend towards setting the same matrix repeatedly for some reason.
2038 * From here on we assume that the new matrix is different, wherever it matters.
2040 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2041 TRACE("The app is setting the same matrix over again\n");
2042 return WINED3D_OK;
2043 } else {
2044 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2048 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2049 where ViewMat = Camera space, WorldMat = world space.
2051 In OpenGL, camera and world space is combined into GL_MODELVIEW
2052 matrix. The Projection matrix stay projection matrix.
2055 /* Capture the times we can just ignore the change for now */
2056 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2057 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2058 /* Handled by the state manager */
2061 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2062 return WINED3D_OK;
2065 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2067 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2068 *pMatrix = This->stateBlock->transforms[State];
2069 return WINED3D_OK;
2072 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2073 const WINED3DMATRIX *mat = NULL;
2074 WINED3DMATRIX temp;
2076 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2077 * below means it will be recorded in a state block change, but it
2078 * works regardless where it is recorded.
2079 * If this is found to be wrong, change to StateBlock.
2081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2082 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2084 if (State <= HIGHEST_TRANSFORMSTATE)
2086 mat = &This->updateStateBlock->transforms[State];
2087 } else {
2088 FIXME("Unhandled transform state!!\n");
2091 multiply_matrix(&temp, mat, pMatrix);
2093 /* Apply change via set transform - will reapply to eg. lights this way */
2094 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2097 /*****
2098 * Get / Set Light
2099 *****/
2100 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2101 you can reference any indexes you want as long as that number max are enabled at any
2102 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2103 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2104 but when recording, just build a chain pretty much of commands to be replayed. */
2106 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2107 float rho;
2108 struct wined3d_light_info *object = NULL;
2109 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2110 struct list *e;
2112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2113 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2115 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2116 * the gl driver.
2118 if(!pLight) {
2119 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2120 return WINED3DERR_INVALIDCALL;
2123 switch(pLight->Type) {
2124 case WINED3DLIGHT_POINT:
2125 case WINED3DLIGHT_SPOT:
2126 case WINED3DLIGHT_PARALLELPOINT:
2127 case WINED3DLIGHT_GLSPOT:
2128 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2129 * most wanted
2131 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2133 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2134 return WINED3DERR_INVALIDCALL;
2136 break;
2138 case WINED3DLIGHT_DIRECTIONAL:
2139 /* Ignores attenuation */
2140 break;
2142 default:
2143 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2144 return WINED3DERR_INVALIDCALL;
2147 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2149 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2150 if(object->OriginalIndex == Index) break;
2151 object = NULL;
2154 if(!object) {
2155 TRACE("Adding new light\n");
2156 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2157 if(!object) {
2158 ERR("Out of memory error when allocating a light\n");
2159 return E_OUTOFMEMORY;
2161 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2162 object->glIndex = -1;
2163 object->OriginalIndex = Index;
2166 /* Initialize the object */
2167 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,
2168 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2169 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2170 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2171 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2172 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2173 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2175 /* Save away the information */
2176 object->OriginalParms = *pLight;
2178 switch (pLight->Type) {
2179 case WINED3DLIGHT_POINT:
2180 /* Position */
2181 object->lightPosn[0] = pLight->Position.x;
2182 object->lightPosn[1] = pLight->Position.y;
2183 object->lightPosn[2] = pLight->Position.z;
2184 object->lightPosn[3] = 1.0f;
2185 object->cutoff = 180.0f;
2186 /* FIXME: Range */
2187 break;
2189 case WINED3DLIGHT_DIRECTIONAL:
2190 /* Direction */
2191 object->lightPosn[0] = -pLight->Direction.x;
2192 object->lightPosn[1] = -pLight->Direction.y;
2193 object->lightPosn[2] = -pLight->Direction.z;
2194 object->lightPosn[3] = 0.0f;
2195 object->exponent = 0.0f;
2196 object->cutoff = 180.0f;
2197 break;
2199 case WINED3DLIGHT_SPOT:
2200 /* Position */
2201 object->lightPosn[0] = pLight->Position.x;
2202 object->lightPosn[1] = pLight->Position.y;
2203 object->lightPosn[2] = pLight->Position.z;
2204 object->lightPosn[3] = 1.0f;
2206 /* Direction */
2207 object->lightDirn[0] = pLight->Direction.x;
2208 object->lightDirn[1] = pLight->Direction.y;
2209 object->lightDirn[2] = pLight->Direction.z;
2210 object->lightDirn[3] = 1.0f;
2213 * opengl-ish and d3d-ish spot lights use too different models for the
2214 * light "intensity" as a function of the angle towards the main light direction,
2215 * so we only can approximate very roughly.
2216 * however spot lights are rather rarely used in games (if ever used at all).
2217 * furthermore if still used, probably nobody pays attention to such details.
2219 if (pLight->Falloff == 0) {
2220 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2221 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2222 * will always be 1.0 for both of them, and we don't have to care for the
2223 * rest of the rather complex calculation
2225 object->exponent = 0.0f;
2226 } else {
2227 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2228 if (rho < 0.0001f) rho = 0.0001f;
2229 object->exponent = -0.3f/logf(cosf(rho/2));
2231 if (object->exponent > 128.0f)
2233 object->exponent = 128.0f;
2235 object->cutoff = pLight->Phi*90/M_PI;
2237 /* FIXME: Range */
2238 break;
2240 default:
2241 FIXME("Unrecognized light type %d\n", pLight->Type);
2244 /* Update the live definitions if the light is currently assigned a glIndex */
2245 if (object->glIndex != -1 && !This->isRecordingState) {
2246 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2248 return WINED3D_OK;
2251 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2253 struct wined3d_light_info *lightInfo = NULL;
2254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2255 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2256 struct list *e;
2257 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2259 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2261 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2262 if(lightInfo->OriginalIndex == Index) break;
2263 lightInfo = NULL;
2266 if (lightInfo == NULL) {
2267 TRACE("Light information requested but light not defined\n");
2268 return WINED3DERR_INVALIDCALL;
2271 *pLight = lightInfo->OriginalParms;
2272 return WINED3D_OK;
2275 /*****
2276 * Get / Set Light Enable
2277 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2278 *****/
2279 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2281 struct wined3d_light_info *lightInfo = NULL;
2282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2283 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2284 struct list *e;
2285 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2287 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2289 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2290 if(lightInfo->OriginalIndex == Index) break;
2291 lightInfo = NULL;
2293 TRACE("Found light: %p\n", lightInfo);
2295 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2296 if (lightInfo == NULL) {
2298 TRACE("Light enabled requested but light not defined, so defining one!\n");
2299 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2301 /* Search for it again! Should be fairly quick as near head of list */
2302 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2304 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2305 if(lightInfo->OriginalIndex == Index) break;
2306 lightInfo = NULL;
2308 if (lightInfo == NULL) {
2309 FIXME("Adding default lights has failed dismally\n");
2310 return WINED3DERR_INVALIDCALL;
2314 if(!Enable) {
2315 if(lightInfo->glIndex != -1) {
2316 if(!This->isRecordingState) {
2317 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2320 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2321 lightInfo->glIndex = -1;
2322 } else {
2323 TRACE("Light already disabled, nothing to do\n");
2325 lightInfo->enabled = FALSE;
2326 } else {
2327 lightInfo->enabled = TRUE;
2328 if (lightInfo->glIndex != -1) {
2329 /* nop */
2330 TRACE("Nothing to do as light was enabled\n");
2331 } else {
2332 int i;
2333 /* Find a free gl light */
2334 for(i = 0; i < This->maxConcurrentLights; i++) {
2335 if(This->updateStateBlock->activeLights[i] == NULL) {
2336 This->updateStateBlock->activeLights[i] = lightInfo;
2337 lightInfo->glIndex = i;
2338 break;
2341 if(lightInfo->glIndex == -1) {
2342 /* Our tests show that Windows returns D3D_OK in this situation, even with
2343 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2344 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2345 * as well for those lights.
2347 * TODO: Test how this affects rendering
2349 WARN("Too many concurrently active lights\n");
2350 return WINED3D_OK;
2353 /* i == lightInfo->glIndex */
2354 if(!This->isRecordingState) {
2355 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2360 return WINED3D_OK;
2363 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2365 struct wined3d_light_info *lightInfo = NULL;
2366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2367 struct list *e;
2368 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2369 TRACE("(%p) : for idx(%d)\n", This, Index);
2371 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2373 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2374 if(lightInfo->OriginalIndex == Index) break;
2375 lightInfo = NULL;
2378 if (lightInfo == NULL) {
2379 TRACE("Light enabled state requested but light not defined\n");
2380 return WINED3DERR_INVALIDCALL;
2382 /* true is 128 according to SetLightEnable */
2383 *pEnable = lightInfo->enabled ? 128 : 0;
2384 return WINED3D_OK;
2387 /*****
2388 * Get / Set Clip Planes
2389 *****/
2390 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2392 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2394 /* Validate Index */
2395 if (Index >= This->adapter->gl_info.limits.clipplanes)
2397 TRACE("Application has requested clipplane this device doesn't support\n");
2398 return WINED3DERR_INVALIDCALL;
2401 This->updateStateBlock->changed.clipplane |= 1 << Index;
2403 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2404 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2405 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2406 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2407 TRACE("Application is setting old values over, nothing to do\n");
2408 return WINED3D_OK;
2411 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2412 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2413 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2414 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2416 /* Handle recording of state blocks */
2417 if (This->isRecordingState) {
2418 TRACE("Recording... not performing anything\n");
2419 return WINED3D_OK;
2422 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2424 return WINED3D_OK;
2427 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2429 TRACE("(%p) : for idx %d\n", This, Index);
2431 /* Validate Index */
2432 if (Index >= This->adapter->gl_info.limits.clipplanes)
2434 TRACE("Application has requested clipplane this device doesn't support\n");
2435 return WINED3DERR_INVALIDCALL;
2438 pPlane[0] = This->stateBlock->clipplane[Index][0];
2439 pPlane[1] = This->stateBlock->clipplane[Index][1];
2440 pPlane[2] = This->stateBlock->clipplane[Index][2];
2441 pPlane[3] = This->stateBlock->clipplane[Index][3];
2442 return WINED3D_OK;
2445 /*****
2446 * Get / Set Clip Plane Status
2447 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2448 *****/
2449 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2451 FIXME("(%p) : stub\n", This);
2452 if (NULL == pClipStatus) {
2453 return WINED3DERR_INVALIDCALL;
2455 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2456 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2457 return WINED3D_OK;
2460 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2461 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2462 FIXME("(%p) : stub\n", This);
2463 if (NULL == pClipStatus) {
2464 return WINED3DERR_INVALIDCALL;
2466 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2467 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2468 return WINED3D_OK;
2471 /*****
2472 * Get / Set Material
2473 *****/
2474 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2477 This->updateStateBlock->changed.material = TRUE;
2478 This->updateStateBlock->material = *pMaterial;
2480 /* Handle recording of state blocks */
2481 if (This->isRecordingState) {
2482 TRACE("Recording... not performing anything\n");
2483 return WINED3D_OK;
2486 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2487 return WINED3D_OK;
2490 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2492 *pMaterial = This->updateStateBlock->material;
2493 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2494 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2495 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2496 pMaterial->Ambient.b, pMaterial->Ambient.a);
2497 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2498 pMaterial->Specular.b, pMaterial->Specular.a);
2499 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2500 pMaterial->Emissive.b, pMaterial->Emissive.a);
2501 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2503 return WINED3D_OK;
2506 /*****
2507 * Get / Set Indices
2508 *****/
2509 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2510 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2513 IWineD3DBuffer *oldIdxs;
2515 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2516 oldIdxs = This->updateStateBlock->pIndexData;
2518 This->updateStateBlock->changed.indices = TRUE;
2519 This->updateStateBlock->pIndexData = pIndexData;
2520 This->updateStateBlock->IndexFmt = fmt;
2522 /* Handle recording of state blocks */
2523 if (This->isRecordingState) {
2524 TRACE("Recording... not performing anything\n");
2525 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2526 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2527 return WINED3D_OK;
2530 if(oldIdxs != pIndexData) {
2531 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2532 if(pIndexData) {
2533 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2534 IWineD3DBuffer_AddRef(pIndexData);
2536 if(oldIdxs) {
2537 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2538 IWineD3DBuffer_Release(oldIdxs);
2542 return WINED3D_OK;
2545 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2549 *ppIndexData = This->stateBlock->pIndexData;
2551 /* up ref count on ppindexdata */
2552 if (*ppIndexData) {
2553 IWineD3DBuffer_AddRef(*ppIndexData);
2554 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2555 }else{
2556 TRACE("(%p) No index data set\n", This);
2558 TRACE("Returning %p\n", *ppIndexData);
2560 return WINED3D_OK;
2563 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2564 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2566 TRACE("(%p)->(%d)\n", This, BaseIndex);
2568 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2569 TRACE("Application is setting the old value over, nothing to do\n");
2570 return WINED3D_OK;
2573 This->updateStateBlock->baseVertexIndex = BaseIndex;
2575 if (This->isRecordingState) {
2576 TRACE("Recording... not performing anything\n");
2577 return WINED3D_OK;
2579 /* The base vertex index affects the stream sources */
2580 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2581 return WINED3D_OK;
2584 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2586 TRACE("(%p) : base_index %p\n", This, base_index);
2588 *base_index = This->stateBlock->baseVertexIndex;
2590 TRACE("Returning %u\n", *base_index);
2592 return WINED3D_OK;
2595 /*****
2596 * Get / Set Viewports
2597 *****/
2598 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2601 TRACE("(%p)\n", This);
2602 This->updateStateBlock->changed.viewport = TRUE;
2603 This->updateStateBlock->viewport = *pViewport;
2605 /* Handle recording of state blocks */
2606 if (This->isRecordingState) {
2607 TRACE("Recording... not performing anything\n");
2608 return WINED3D_OK;
2611 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2612 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2614 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2615 return WINED3D_OK;
2619 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2621 TRACE("(%p)\n", This);
2622 *pViewport = This->stateBlock->viewport;
2623 return WINED3D_OK;
2626 /*****
2627 * Get / Set Render States
2628 * TODO: Verify against dx9 definitions
2629 *****/
2630 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2633 DWORD oldValue = This->stateBlock->renderState[State];
2635 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2637 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2638 This->updateStateBlock->renderState[State] = Value;
2640 /* Handle recording of state blocks */
2641 if (This->isRecordingState) {
2642 TRACE("Recording... not performing anything\n");
2643 return WINED3D_OK;
2646 /* Compared here and not before the assignment to allow proper stateblock recording */
2647 if(Value == oldValue) {
2648 TRACE("Application is setting the old value over, nothing to do\n");
2649 } else {
2650 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2653 return WINED3D_OK;
2656 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2658 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2659 *pValue = This->stateBlock->renderState[State];
2660 return WINED3D_OK;
2663 /*****
2664 * Get / Set Sampler States
2665 * TODO: Verify against dx9 definitions
2666 *****/
2668 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2670 DWORD oldValue;
2672 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2673 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2675 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2676 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2679 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2680 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2681 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2684 * SetSampler is designed to allow for more than the standard up to 8 textures
2685 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2686 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2688 * http://developer.nvidia.com/object/General_FAQ.html#t6
2690 * There are two new settings for GForce
2691 * the sampler one:
2692 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2693 * and the texture one:
2694 * GL_MAX_TEXTURE_COORDS_ARB.
2695 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2696 ******************/
2698 oldValue = This->stateBlock->samplerState[Sampler][Type];
2699 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2700 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2702 /* Handle recording of state blocks */
2703 if (This->isRecordingState) {
2704 TRACE("Recording... not performing anything\n");
2705 return WINED3D_OK;
2708 if(oldValue == Value) {
2709 TRACE("Application is setting the old value over, nothing to do\n");
2710 return WINED3D_OK;
2713 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2715 return WINED3D_OK;
2718 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2719 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2721 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2722 This, Sampler, debug_d3dsamplerstate(Type), Type);
2724 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2725 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2728 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2729 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2730 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2732 *Value = This->stateBlock->samplerState[Sampler][Type];
2733 TRACE("(%p) : Returning %#x\n", This, *Value);
2735 return WINED3D_OK;
2738 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2741 This->updateStateBlock->changed.scissorRect = TRUE;
2742 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2743 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2744 return WINED3D_OK;
2746 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2748 if(This->isRecordingState) {
2749 TRACE("Recording... not performing anything\n");
2750 return WINED3D_OK;
2753 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2755 return WINED3D_OK;
2758 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2761 *pRect = This->updateStateBlock->scissorRect;
2762 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2763 return WINED3D_OK;
2766 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2768 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2770 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2772 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2773 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2775 This->updateStateBlock->vertexDecl = pDecl;
2776 This->updateStateBlock->changed.vertexDecl = TRUE;
2778 if (This->isRecordingState) {
2779 TRACE("Recording... not performing anything\n");
2780 return WINED3D_OK;
2781 } else if(pDecl == oldDecl) {
2782 /* Checked after the assignment to allow proper stateblock recording */
2783 TRACE("Application is setting the old declaration over, nothing to do\n");
2784 return WINED3D_OK;
2787 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2788 return WINED3D_OK;
2791 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2794 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2796 *ppDecl = This->stateBlock->vertexDecl;
2797 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2798 return WINED3D_OK;
2801 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2803 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2805 This->updateStateBlock->vertexShader = pShader;
2806 This->updateStateBlock->changed.vertexShader = TRUE;
2808 if (This->isRecordingState) {
2809 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2810 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2811 TRACE("Recording... not performing anything\n");
2812 return WINED3D_OK;
2813 } else if(oldShader == pShader) {
2814 /* Checked here to allow proper stateblock recording */
2815 TRACE("App is setting the old shader over, nothing to do\n");
2816 return WINED3D_OK;
2819 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2820 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2821 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2823 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2825 return WINED3D_OK;
2828 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2831 if (NULL == ppShader) {
2832 return WINED3DERR_INVALIDCALL;
2834 *ppShader = This->stateBlock->vertexShader;
2835 if( NULL != *ppShader)
2836 IWineD3DVertexShader_AddRef(*ppShader);
2838 TRACE("(%p) : returning %p\n", This, *ppShader);
2839 return WINED3D_OK;
2842 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2843 IWineD3DDevice *iface,
2844 UINT start,
2845 CONST BOOL *srcData,
2846 UINT count) {
2848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2849 unsigned int i, cnt = min(count, MAX_CONST_B - start);
2851 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2852 iface, srcData, start, count);
2854 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
2856 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2857 for (i = 0; i < cnt; i++)
2858 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2860 for (i = start; i < cnt + start; ++i) {
2861 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
2864 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2866 return WINED3D_OK;
2869 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2870 IWineD3DDevice *iface,
2871 UINT start,
2872 BOOL *dstData,
2873 UINT count) {
2875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2876 int cnt = min(count, MAX_CONST_B - start);
2878 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2879 iface, dstData, start, count);
2881 if (dstData == NULL || cnt < 0)
2882 return WINED3DERR_INVALIDCALL;
2884 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2885 return WINED3D_OK;
2888 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2889 IWineD3DDevice *iface,
2890 UINT start,
2891 CONST int *srcData,
2892 UINT count) {
2894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2895 unsigned int i, cnt = min(count, MAX_CONST_I - start);
2897 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2898 iface, srcData, start, count);
2900 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
2902 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2903 for (i = 0; i < cnt; i++)
2904 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2905 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2907 for (i = start; i < cnt + start; ++i) {
2908 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
2911 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2913 return WINED3D_OK;
2916 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2917 IWineD3DDevice *iface,
2918 UINT start,
2919 int *dstData,
2920 UINT count) {
2922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2923 int cnt = min(count, MAX_CONST_I - start);
2925 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2926 iface, dstData, start, count);
2928 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2929 return WINED3DERR_INVALIDCALL;
2931 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
2932 return WINED3D_OK;
2935 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
2936 IWineD3DDevice *iface,
2937 UINT start,
2938 CONST float *srcData,
2939 UINT count) {
2941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2942 UINT i;
2944 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2945 iface, srcData, start, count);
2947 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
2948 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
2949 return WINED3DERR_INVALIDCALL;
2951 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
2952 if(TRACE_ON(d3d)) {
2953 for (i = 0; i < count; i++)
2954 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
2955 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2958 if (!This->isRecordingState)
2960 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
2961 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2964 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
2965 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
2967 return WINED3D_OK;
2970 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
2971 IWineD3DDevice *iface,
2972 UINT start,
2973 float *dstData,
2974 UINT count) {
2976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2977 int cnt = min(count, This->d3d_vshader_constantF - start);
2979 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2980 iface, dstData, start, count);
2982 if (dstData == NULL || cnt < 0)
2983 return WINED3DERR_INVALIDCALL;
2985 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
2986 return WINED3D_OK;
2989 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
2990 DWORD i;
2991 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
2993 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
2997 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
2999 DWORD i = This->rev_tex_unit_map[unit];
3000 DWORD j = This->texUnitMap[stage];
3002 This->texUnitMap[stage] = unit;
3003 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3005 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3008 This->rev_tex_unit_map[unit] = stage;
3009 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3011 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3015 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3016 int i;
3018 This->fixed_function_usage_map = 0;
3019 for (i = 0; i < MAX_TEXTURES; ++i) {
3020 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3021 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3022 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3023 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3024 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3025 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3026 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3027 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3029 if (color_op == WINED3DTOP_DISABLE) {
3030 /* Not used, and disable higher stages */
3031 break;
3034 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3035 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3036 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3037 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3038 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3039 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3040 This->fixed_function_usage_map |= (1 << i);
3043 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3044 This->fixed_function_usage_map |= (1 << (i + 1));
3049 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3050 unsigned int i, tex;
3051 WORD ffu_map;
3053 device_update_fixed_function_usage_map(This);
3054 ffu_map = This->fixed_function_usage_map;
3056 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3057 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3058 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3060 if (!(ffu_map & 1)) continue;
3062 if (This->texUnitMap[i] != i) {
3063 device_map_stage(This, i, i);
3064 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3065 markTextureStagesDirty(This, i);
3068 return;
3071 /* Now work out the mapping */
3072 tex = 0;
3073 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3075 if (!(ffu_map & 1)) continue;
3077 if (This->texUnitMap[i] != tex) {
3078 device_map_stage(This, i, tex);
3079 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3080 markTextureStagesDirty(This, i);
3083 ++tex;
3087 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3088 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3089 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3090 unsigned int i;
3092 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3093 if (sampler_type[i] && This->texUnitMap[i] != i)
3095 device_map_stage(This, i, i);
3096 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3097 if (i < MAX_TEXTURES) {
3098 markTextureStagesDirty(This, i);
3104 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3105 const DWORD *vshader_sampler_tokens, DWORD unit)
3107 DWORD current_mapping = This->rev_tex_unit_map[unit];
3109 /* Not currently used */
3110 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3112 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3113 /* Used by a fragment sampler */
3115 if (!pshader_sampler_tokens) {
3116 /* No pixel shader, check fixed function */
3117 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3120 /* Pixel shader, check the shader's sampler map */
3121 return !pshader_sampler_tokens[current_mapping];
3124 /* Used by a vertex sampler */
3125 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3128 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3129 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3130 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3131 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3132 int start = min(MAX_COMBINED_SAMPLERS, This->adapter->gl_info.limits.combined_samplers) - 1;
3133 int i;
3135 if (ps) {
3136 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3138 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3139 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3140 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3143 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3144 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3145 if (vshader_sampler_type[i])
3147 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3149 /* Already mapped somewhere */
3150 continue;
3153 while (start >= 0) {
3154 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3156 device_map_stage(This, vsampler_idx, start);
3157 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3159 --start;
3160 break;
3163 --start;
3169 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3170 BOOL vs = use_vs(This->stateBlock);
3171 BOOL ps = use_ps(This->stateBlock);
3173 * Rules are:
3174 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3175 * that would be really messy and require shader recompilation
3176 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3177 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3179 if (ps) {
3180 device_map_psamplers(This);
3181 } else {
3182 device_map_fixed_function_samplers(This);
3185 if (vs) {
3186 device_map_vsamplers(This, ps);
3190 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3192 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3193 This->updateStateBlock->pixelShader = pShader;
3194 This->updateStateBlock->changed.pixelShader = TRUE;
3196 /* Handle recording of state blocks */
3197 if (This->isRecordingState) {
3198 TRACE("Recording... not performing anything\n");
3201 if (This->isRecordingState) {
3202 TRACE("Recording... not performing anything\n");
3203 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3204 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3205 return WINED3D_OK;
3208 if(pShader == oldShader) {
3209 TRACE("App is setting the old pixel shader over, nothing to do\n");
3210 return WINED3D_OK;
3213 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3214 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3216 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3217 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3219 return WINED3D_OK;
3222 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3225 if (NULL == ppShader) {
3226 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3227 return WINED3DERR_INVALIDCALL;
3230 *ppShader = This->stateBlock->pixelShader;
3231 if (NULL != *ppShader) {
3232 IWineD3DPixelShader_AddRef(*ppShader);
3234 TRACE("(%p) : returning %p\n", This, *ppShader);
3235 return WINED3D_OK;
3238 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3239 IWineD3DDevice *iface,
3240 UINT start,
3241 CONST BOOL *srcData,
3242 UINT count) {
3244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3245 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3247 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3248 iface, srcData, start, count);
3250 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3252 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3253 for (i = 0; i < cnt; i++)
3254 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3256 for (i = start; i < cnt + start; ++i) {
3257 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3260 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3262 return WINED3D_OK;
3265 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3266 IWineD3DDevice *iface,
3267 UINT start,
3268 BOOL *dstData,
3269 UINT count) {
3271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3272 int cnt = min(count, MAX_CONST_B - start);
3274 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3275 iface, dstData, start, count);
3277 if (dstData == NULL || cnt < 0)
3278 return WINED3DERR_INVALIDCALL;
3280 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3281 return WINED3D_OK;
3284 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3285 IWineD3DDevice *iface,
3286 UINT start,
3287 CONST int *srcData,
3288 UINT count) {
3290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3291 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3293 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3294 iface, srcData, start, count);
3296 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3298 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3299 for (i = 0; i < cnt; i++)
3300 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3301 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3303 for (i = start; i < cnt + start; ++i) {
3304 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3307 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3309 return WINED3D_OK;
3312 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3313 IWineD3DDevice *iface,
3314 UINT start,
3315 int *dstData,
3316 UINT count) {
3318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3319 int cnt = min(count, MAX_CONST_I - start);
3321 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3322 iface, dstData, start, count);
3324 if (dstData == NULL || cnt < 0)
3325 return WINED3DERR_INVALIDCALL;
3327 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3328 return WINED3D_OK;
3331 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3332 IWineD3DDevice *iface,
3333 UINT start,
3334 CONST float *srcData,
3335 UINT count) {
3337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3338 UINT i;
3340 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3341 iface, srcData, start, count);
3343 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3344 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3345 return WINED3DERR_INVALIDCALL;
3347 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3348 if(TRACE_ON(d3d)) {
3349 for (i = 0; i < count; i++)
3350 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3351 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3354 if (!This->isRecordingState)
3356 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3357 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3360 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3361 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3363 return WINED3D_OK;
3366 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3367 IWineD3DDevice *iface,
3368 UINT start,
3369 float *dstData,
3370 UINT count) {
3372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3373 int cnt = min(count, This->d3d_pshader_constantF - start);
3375 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3376 iface, dstData, start, count);
3378 if (dstData == NULL || cnt < 0)
3379 return WINED3DERR_INVALIDCALL;
3381 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3382 return WINED3D_OK;
3385 /* Context activation is done by the caller. */
3386 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3387 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3388 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3389 DWORD DestFVF)
3391 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3392 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3393 unsigned int i;
3394 WINED3DVIEWPORT vp;
3395 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3396 BOOL doClip;
3397 DWORD numTextures;
3399 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3401 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3404 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3406 ERR("Source has no position mask\n");
3407 return WINED3DERR_INVALIDCALL;
3410 /* We might access VBOs from this code, so hold the lock */
3411 ENTER_GL();
3413 if (dest->resource.allocatedMemory == NULL) {
3414 buffer_get_sysmem(dest);
3417 /* Get a pointer into the destination vbo(create one if none exists) and
3418 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3420 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3422 dest->flags |= WINED3D_BUFFER_CREATEBO;
3423 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3426 if (dest->buffer_object)
3428 unsigned char extrabytes = 0;
3429 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3430 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3431 * this may write 4 extra bytes beyond the area that should be written
3433 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3434 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3435 if(!dest_conv_addr) {
3436 ERR("Out of memory\n");
3437 /* Continue without storing converted vertices */
3439 dest_conv = dest_conv_addr;
3442 /* Should I clip?
3443 * a) WINED3DRS_CLIPPING is enabled
3444 * b) WINED3DVOP_CLIP is passed
3446 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3447 static BOOL warned = FALSE;
3449 * The clipping code is not quite correct. Some things need
3450 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3451 * so disable clipping for now.
3452 * (The graphics in Half-Life are broken, and my processvertices
3453 * test crashes with IDirect3DDevice3)
3454 doClip = TRUE;
3456 doClip = FALSE;
3457 if(!warned) {
3458 warned = TRUE;
3459 FIXME("Clipping is broken and disabled for now\n");
3461 } else doClip = FALSE;
3462 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3464 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3465 WINED3DTS_VIEW,
3466 &view_mat);
3467 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3468 WINED3DTS_PROJECTION,
3469 &proj_mat);
3470 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3471 WINED3DTS_WORLDMATRIX(0),
3472 &world_mat);
3474 TRACE("View mat:\n");
3475 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);
3476 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);
3477 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);
3478 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);
3480 TRACE("Proj mat:\n");
3481 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);
3482 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);
3483 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);
3484 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);
3486 TRACE("World mat:\n");
3487 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);
3488 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);
3489 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);
3490 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);
3492 /* Get the viewport */
3493 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3494 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3495 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3497 multiply_matrix(&mat,&view_mat,&world_mat);
3498 multiply_matrix(&mat,&proj_mat,&mat);
3500 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3502 for (i = 0; i < dwCount; i+= 1) {
3503 unsigned int tex_index;
3505 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3506 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3507 /* The position first */
3508 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3509 const float *p = (const float *)(element->data + i * element->stride);
3510 float x, y, z, rhw;
3511 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3513 /* Multiplication with world, view and projection matrix */
3514 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);
3515 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);
3516 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);
3517 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);
3519 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3521 /* WARNING: The following things are taken from d3d7 and were not yet checked
3522 * against d3d8 or d3d9!
3525 /* Clipping conditions: From msdn
3527 * A vertex is clipped if it does not match the following requirements
3528 * -rhw < x <= rhw
3529 * -rhw < y <= rhw
3530 * 0 < z <= rhw
3531 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3533 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3534 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3538 if( !doClip ||
3539 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3540 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3541 ( rhw > eps ) ) ) {
3543 /* "Normal" viewport transformation (not clipped)
3544 * 1) The values are divided by rhw
3545 * 2) The y axis is negative, so multiply it with -1
3546 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3547 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3548 * 4) Multiply x with Width/2 and add Width/2
3549 * 5) The same for the height
3550 * 6) Add the viewpoint X and Y to the 2D coordinates and
3551 * The minimum Z value to z
3552 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3554 * Well, basically it's simply a linear transformation into viewport
3555 * coordinates
3558 x /= rhw;
3559 y /= rhw;
3560 z /= rhw;
3562 y *= -1;
3564 x *= vp.Width / 2;
3565 y *= vp.Height / 2;
3566 z *= vp.MaxZ - vp.MinZ;
3568 x += vp.Width / 2 + vp.X;
3569 y += vp.Height / 2 + vp.Y;
3570 z += vp.MinZ;
3572 rhw = 1 / rhw;
3573 } else {
3574 /* That vertex got clipped
3575 * Contrary to OpenGL it is not dropped completely, it just
3576 * undergoes a different calculation.
3578 TRACE("Vertex got clipped\n");
3579 x += rhw;
3580 y += rhw;
3582 x /= 2;
3583 y /= 2;
3585 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3586 * outside of the main vertex buffer memory. That needs some more
3587 * investigation...
3591 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3594 ( (float *) dest_ptr)[0] = x;
3595 ( (float *) dest_ptr)[1] = y;
3596 ( (float *) dest_ptr)[2] = z;
3597 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3599 dest_ptr += 3 * sizeof(float);
3601 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3602 dest_ptr += sizeof(float);
3605 if(dest_conv) {
3606 float w = 1 / rhw;
3607 ( (float *) dest_conv)[0] = x * w;
3608 ( (float *) dest_conv)[1] = y * w;
3609 ( (float *) dest_conv)[2] = z * w;
3610 ( (float *) dest_conv)[3] = w;
3612 dest_conv += 3 * sizeof(float);
3614 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3615 dest_conv += sizeof(float);
3619 if (DestFVF & WINED3DFVF_PSIZE) {
3620 dest_ptr += sizeof(DWORD);
3621 if(dest_conv) dest_conv += sizeof(DWORD);
3623 if (DestFVF & WINED3DFVF_NORMAL) {
3624 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3625 const float *normal = (const float *)(element->data + i * element->stride);
3626 /* AFAIK this should go into the lighting information */
3627 FIXME("Didn't expect the destination to have a normal\n");
3628 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3629 if(dest_conv) {
3630 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3634 if (DestFVF & WINED3DFVF_DIFFUSE) {
3635 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3636 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3637 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3639 static BOOL warned = FALSE;
3641 if(!warned) {
3642 ERR("No diffuse color in source, but destination has one\n");
3643 warned = TRUE;
3646 *( (DWORD *) dest_ptr) = 0xffffffff;
3647 dest_ptr += sizeof(DWORD);
3649 if(dest_conv) {
3650 *( (DWORD *) dest_conv) = 0xffffffff;
3651 dest_conv += sizeof(DWORD);
3654 else {
3655 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3656 if(dest_conv) {
3657 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3658 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3659 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3660 dest_conv += sizeof(DWORD);
3665 if (DestFVF & WINED3DFVF_SPECULAR)
3667 /* What's the color value in the feedback buffer? */
3668 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3669 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3670 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3672 static BOOL warned = FALSE;
3674 if(!warned) {
3675 ERR("No specular color in source, but destination has one\n");
3676 warned = TRUE;
3679 *( (DWORD *) dest_ptr) = 0xFF000000;
3680 dest_ptr += sizeof(DWORD);
3682 if(dest_conv) {
3683 *( (DWORD *) dest_conv) = 0xFF000000;
3684 dest_conv += sizeof(DWORD);
3687 else {
3688 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3689 if(dest_conv) {
3690 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3691 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3692 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3693 dest_conv += sizeof(DWORD);
3698 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3699 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3700 const float *tex_coord = (const float *)(element->data + i * element->stride);
3701 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3703 ERR("No source texture, but destination requests one\n");
3704 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3705 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3707 else {
3708 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3709 if(dest_conv) {
3710 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3716 if(dest_conv) {
3717 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3718 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3719 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3720 dwCount * get_flexible_vertex_size(DestFVF),
3721 dest_conv_addr));
3722 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3723 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3726 LEAVE_GL();
3728 return WINED3D_OK;
3730 #undef copy_and_next
3732 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3733 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3734 DWORD DestFVF)
3736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3737 struct wined3d_stream_info stream_info;
3738 struct wined3d_context *context;
3739 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3740 HRESULT hr;
3742 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3744 if(pVertexDecl) {
3745 ERR("Output vertex declaration not implemented yet\n");
3748 /* Need any context to write to the vbo. */
3749 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
3751 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3752 * control the streamIsUP flag, thus restore it afterwards.
3754 This->stateBlock->streamIsUP = FALSE;
3755 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3756 This->stateBlock->streamIsUP = streamWasUP;
3758 if(vbo || SrcStartIndex) {
3759 unsigned int i;
3760 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3761 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3763 * Also get the start index in, but only loop over all elements if there's something to add at all.
3765 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3767 struct wined3d_stream_info_element *e;
3769 if (!(stream_info.use_map & (1 << i))) continue;
3771 e = &stream_info.elements[i];
3772 if (e->buffer_object)
3774 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3775 e->buffer_object = 0;
3776 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3777 ENTER_GL();
3778 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3779 vb->buffer_object = 0;
3780 LEAVE_GL();
3782 if (e->data) e->data += e->stride * SrcStartIndex;
3786 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3787 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3789 context_release(context);
3791 return hr;
3794 /*****
3795 * Get / Set Texture Stage States
3796 * TODO: Verify against dx9 definitions
3797 *****/
3798 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3800 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3802 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3804 if (Stage >= MAX_TEXTURES) {
3805 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
3806 return WINED3D_OK;
3809 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3810 This->updateStateBlock->textureState[Stage][Type] = Value;
3812 if (This->isRecordingState) {
3813 TRACE("Recording... not performing anything\n");
3814 return WINED3D_OK;
3817 /* Checked after the assignments to allow proper stateblock recording */
3818 if(oldValue == Value) {
3819 TRACE("App is setting the old value over, nothing to do\n");
3820 return WINED3D_OK;
3823 if(Stage > This->stateBlock->lowest_disabled_stage &&
3824 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3825 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3826 * Changes in other states are important on disabled stages too
3828 return WINED3D_OK;
3831 if(Type == WINED3DTSS_COLOROP) {
3832 unsigned int i;
3834 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3835 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3836 * they have to be disabled
3838 * The current stage is dirtified below.
3840 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3841 TRACE("Additionally dirtifying stage %u\n", i);
3842 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3844 This->stateBlock->lowest_disabled_stage = Stage;
3845 TRACE("New lowest disabled: %u\n", Stage);
3846 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3847 /* Previously disabled stage enabled. Stages above it may need enabling
3848 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3849 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3851 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3854 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
3856 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3857 break;
3859 TRACE("Additionally dirtifying stage %u due to enable\n", i);
3860 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3862 This->stateBlock->lowest_disabled_stage = i;
3863 TRACE("New lowest disabled: %u\n", i);
3867 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3869 return WINED3D_OK;
3872 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3874 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3875 *pValue = This->updateStateBlock->textureState[Stage][Type];
3876 return WINED3D_OK;
3879 /*****
3880 * Get / Set Texture
3881 *****/
3882 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
3883 DWORD stage, IWineD3DBaseTexture *texture)
3885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3886 IWineD3DBaseTexture *prev;
3888 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
3890 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
3891 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3893 /* Windows accepts overflowing this array... we do not. */
3894 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
3896 WARN("Ignoring invalid stage %u.\n", stage);
3897 return WINED3D_OK;
3900 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
3901 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
3903 WARN("Rejecting attempt to set scratch texture.\n");
3904 return WINED3DERR_INVALIDCALL;
3907 This->updateStateBlock->changed.textures |= 1 << stage;
3909 prev = This->updateStateBlock->textures[stage];
3910 TRACE("Previous texture %p.\n", prev);
3912 if (texture == prev)
3914 TRACE("App is setting the same texture again, nothing to do.\n");
3915 return WINED3D_OK;
3918 TRACE("Setting new texture to %p.\n", texture);
3919 This->updateStateBlock->textures[stage] = texture;
3921 if (This->isRecordingState)
3923 TRACE("Recording... not performing anything\n");
3925 if (texture) IWineD3DBaseTexture_AddRef(texture);
3926 if (prev) IWineD3DBaseTexture_Release(prev);
3928 return WINED3D_OK;
3931 if (texture)
3933 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
3934 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
3935 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
3937 IWineD3DBaseTexture_AddRef(texture);
3939 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
3941 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3944 if (!prev && stage < MAX_TEXTURES)
3946 /* The source arguments for color and alpha ops have different
3947 * meanings when a NULL texture is bound, so the COLOROP and
3948 * ALPHAOP have to be dirtified. */
3949 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
3950 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
3953 if (bind_count == 1) t->baseTexture.sampler = stage;
3956 if (prev)
3958 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
3959 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
3961 IWineD3DBaseTexture_Release(prev);
3963 if (!texture && stage < MAX_TEXTURES)
3965 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
3966 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
3969 if (bind_count && t->baseTexture.sampler == stage)
3971 unsigned int i;
3973 /* Search for other stages the texture is bound to. Shouldn't
3974 * happen if applications bind textures to a single stage only. */
3975 TRACE("Searching for other stages the texture is bound to.\n");
3976 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
3978 if (This->updateStateBlock->textures[i] == prev)
3980 TRACE("Texture is also bound to stage %u.\n", i);
3981 t->baseTexture.sampler = i;
3982 break;
3988 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
3990 return WINED3D_OK;
3993 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
3994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3996 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
3998 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
3999 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4002 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4003 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4004 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4007 *ppTexture=This->stateBlock->textures[Stage];
4008 if (*ppTexture)
4009 IWineD3DBaseTexture_AddRef(*ppTexture);
4011 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4013 return WINED3D_OK;
4016 /*****
4017 * Get Back Buffer
4018 *****/
4019 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4020 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4022 IWineD3DSwapChain *swapchain;
4023 HRESULT hr;
4025 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4026 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4028 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4029 if (FAILED(hr))
4031 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4032 return hr;
4035 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4036 IWineD3DSwapChain_Release(swapchain);
4037 if (FAILED(hr))
4039 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4040 return hr;
4043 return WINED3D_OK;
4046 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4048 WARN("(%p) : stub, calling idirect3d for now\n", This);
4049 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4052 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4054 IWineD3DSwapChain *swapChain;
4055 HRESULT hr;
4057 if(iSwapChain > 0) {
4058 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4059 if (hr == WINED3D_OK) {
4060 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4061 IWineD3DSwapChain_Release(swapChain);
4062 } else {
4063 FIXME("(%p) Error getting display mode\n", This);
4065 } else {
4066 /* Don't read the real display mode,
4067 but return the stored mode instead. X11 can't change the color
4068 depth, and some apps are pretty angry if they SetDisplayMode from
4069 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4071 Also don't relay to the swapchain because with ddraw it's possible
4072 that there isn't a swapchain at all */
4073 pMode->Width = This->ddraw_width;
4074 pMode->Height = This->ddraw_height;
4075 pMode->Format = This->ddraw_format;
4076 pMode->RefreshRate = 0;
4077 hr = WINED3D_OK;
4080 return hr;
4083 /*****
4084 * Stateblock related functions
4085 *****/
4087 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4089 IWineD3DStateBlock *stateblock;
4090 HRESULT hr;
4092 TRACE("(%p)\n", This);
4094 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4096 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4097 if (FAILED(hr)) return hr;
4099 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4100 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4101 This->isRecordingState = TRUE;
4103 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4105 return WINED3D_OK;
4108 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4110 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4112 if (!This->isRecordingState) {
4113 WARN("(%p) not recording! returning error\n", This);
4114 *ppStateBlock = NULL;
4115 return WINED3DERR_INVALIDCALL;
4118 stateblock_init_contained_states(object);
4120 *ppStateBlock = (IWineD3DStateBlock*) object;
4121 This->isRecordingState = FALSE;
4122 This->updateStateBlock = This->stateBlock;
4123 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4124 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4125 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4126 return WINED3D_OK;
4129 /*****
4130 * Scene related functions
4131 *****/
4132 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4133 /* At the moment we have no need for any functionality at the beginning
4134 of a scene */
4135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4136 TRACE("(%p)\n", This);
4138 if(This->inScene) {
4139 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4140 return WINED3DERR_INVALIDCALL;
4142 This->inScene = TRUE;
4143 return WINED3D_OK;
4146 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4149 struct wined3d_context *context;
4151 TRACE("(%p)\n", This);
4153 if(!This->inScene) {
4154 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4155 return WINED3DERR_INVALIDCALL;
4158 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4159 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4160 wglFlush();
4161 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4162 * fails. */
4163 context_release(context);
4165 This->inScene = FALSE;
4166 return WINED3D_OK;
4169 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4170 const RECT *pSourceRect, const RECT *pDestRect,
4171 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4173 IWineD3DSwapChain *swapChain = NULL;
4174 int i;
4175 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4177 TRACE("iface %p.\n", iface);
4179 for(i = 0 ; i < swapchains ; i ++) {
4181 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4182 TRACE("presentinng chain %d, %p\n", i, swapChain);
4183 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4184 IWineD3DSwapChain_Release(swapChain);
4187 return WINED3D_OK;
4190 /* Not called from the VTable (internal subroutine) */
4191 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4192 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4193 float Z, DWORD Stencil) {
4194 GLbitfield glMask = 0;
4195 unsigned int i;
4196 WINED3DRECT curRect;
4197 RECT vp_rect;
4198 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4199 UINT drawable_width, drawable_height;
4200 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4201 IWineD3DSwapChainImpl *swapchain = NULL;
4202 struct wined3d_context *context;
4204 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4205 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4206 * for the cleared parts, and the untouched parts.
4208 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4209 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4210 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4211 * checking all this if the dest surface is in the drawable anyway.
4213 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4214 while(1) {
4215 if(vp->X != 0 || vp->Y != 0 ||
4216 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4217 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4218 break;
4220 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4221 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4222 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4223 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4224 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4225 break;
4227 if(Count > 0 && pRects && (
4228 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4229 pRects[0].x2 < target->currentDesc.Width ||
4230 pRects[0].y2 < target->currentDesc.Height)) {
4231 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4232 break;
4234 break;
4238 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4240 target->get_drawable_size(context, &drawable_width, &drawable_height);
4242 ENTER_GL();
4244 /* Only set the values up once, as they are not changing */
4245 if (Flags & WINED3DCLEAR_STENCIL) {
4246 glClearStencil(Stencil);
4247 checkGLcall("glClearStencil");
4248 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4249 glStencilMask(0xFFFFFFFF);
4252 if (Flags & WINED3DCLEAR_ZBUFFER) {
4253 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4254 glDepthMask(GL_TRUE);
4255 glClearDepth(Z);
4256 checkGLcall("glClearDepth");
4257 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4258 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4260 if (vp->X != 0 || vp->Y != 0 ||
4261 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4262 surface_load_ds_location(This->stencilBufferTarget, context, location);
4264 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4265 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4266 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4267 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4268 surface_load_ds_location(This->stencilBufferTarget, context, location);
4270 else if (Count > 0 && pRects && (
4271 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4272 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4273 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4274 surface_load_ds_location(This->stencilBufferTarget, context, location);
4278 if (Flags & WINED3DCLEAR_TARGET) {
4279 TRACE("Clearing screen with glClear to color %x\n", Color);
4280 glClearColor(D3DCOLOR_R(Color),
4281 D3DCOLOR_G(Color),
4282 D3DCOLOR_B(Color),
4283 D3DCOLOR_A(Color));
4284 checkGLcall("glClearColor");
4286 /* Clear ALL colors! */
4287 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4288 glMask = glMask | GL_COLOR_BUFFER_BIT;
4291 vp_rect.left = vp->X;
4292 vp_rect.top = vp->Y;
4293 vp_rect.right = vp->X + vp->Width;
4294 vp_rect.bottom = vp->Y + vp->Height;
4295 if (!(Count > 0 && pRects)) {
4296 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4297 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4299 if (context->render_offscreen)
4301 glScissor(vp_rect.left, vp_rect.top,
4302 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4303 } else {
4304 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4305 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4307 checkGLcall("glScissor");
4308 glClear(glMask);
4309 checkGLcall("glClear");
4310 } else {
4311 /* Now process each rect in turn */
4312 for (i = 0; i < Count; i++) {
4313 /* Note gl uses lower left, width/height */
4314 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4315 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4316 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4318 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4319 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4320 curRect.x1, (target->currentDesc.Height - curRect.y2),
4321 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4323 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4324 * The rectangle is not cleared, no error is returned, but further rectanlges are
4325 * still cleared if they are valid
4327 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4328 TRACE("Rectangle with negative dimensions, ignoring\n");
4329 continue;
4332 if (context->render_offscreen)
4334 glScissor(curRect.x1, curRect.y1,
4335 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4336 } else {
4337 glScissor(curRect.x1, drawable_height - curRect.y2,
4338 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4340 checkGLcall("glScissor");
4342 glClear(glMask);
4343 checkGLcall("glClear");
4347 /* Restore the old values (why..?) */
4348 if (Flags & WINED3DCLEAR_STENCIL) {
4349 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4351 if (Flags & WINED3DCLEAR_TARGET) {
4352 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4353 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4354 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4355 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4356 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4358 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4359 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4361 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4363 if (Flags & WINED3DCLEAR_ZBUFFER) {
4364 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4365 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4366 surface_modify_ds_location(This->stencilBufferTarget, location);
4369 LEAVE_GL();
4371 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
4372 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
4373 wglFlush();
4375 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
4378 context_release(context);
4380 return WINED3D_OK;
4383 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4384 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4386 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4388 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4389 Count, pRects, Flags, Color, Z, Stencil);
4391 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4392 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4393 /* TODO: What about depth stencil buffers without stencil bits? */
4394 return WINED3DERR_INVALIDCALL;
4397 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4400 /*****
4401 * Drawing functions
4402 *****/
4404 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4405 WINED3DPRIMITIVETYPE primitive_type)
4407 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4409 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4411 This->updateStateBlock->changed.primitive_type = TRUE;
4412 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4415 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4416 WINED3DPRIMITIVETYPE *primitive_type)
4418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4420 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4422 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4424 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4427 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4431 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4433 if(!This->stateBlock->vertexDecl) {
4434 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4435 return WINED3DERR_INVALIDCALL;
4438 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4439 if(This->stateBlock->streamIsUP) {
4440 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4441 This->stateBlock->streamIsUP = FALSE;
4444 if(This->stateBlock->loadBaseVertexIndex != 0) {
4445 This->stateBlock->loadBaseVertexIndex = 0;
4446 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4448 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4449 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4450 return WINED3D_OK;
4453 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4456 UINT idxStride = 2;
4457 IWineD3DBuffer *pIB;
4458 GLuint vbo;
4460 pIB = This->stateBlock->pIndexData;
4461 if (!pIB) {
4462 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4463 * without an index buffer set. (The first time at least...)
4464 * D3D8 simply dies, but I doubt it can do much harm to return
4465 * D3DERR_INVALIDCALL there as well. */
4466 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4467 return WINED3DERR_INVALIDCALL;
4470 if(!This->stateBlock->vertexDecl) {
4471 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4472 return WINED3DERR_INVALIDCALL;
4475 if(This->stateBlock->streamIsUP) {
4476 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4477 This->stateBlock->streamIsUP = FALSE;
4479 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4481 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4483 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4484 idxStride = 2;
4485 } else {
4486 idxStride = 4;
4489 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4490 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4491 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4494 drawPrimitive(iface, index_count, startIndex, idxStride,
4495 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4497 return WINED3D_OK;
4500 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4501 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4504 IWineD3DBuffer *vb;
4506 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4507 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4509 if(!This->stateBlock->vertexDecl) {
4510 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4511 return WINED3DERR_INVALIDCALL;
4514 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4515 vb = This->stateBlock->streamSource[0];
4516 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4517 if (vb) IWineD3DBuffer_Release(vb);
4518 This->stateBlock->streamOffset[0] = 0;
4519 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4520 This->stateBlock->streamIsUP = TRUE;
4521 This->stateBlock->loadBaseVertexIndex = 0;
4523 /* TODO: Only mark dirty if drawing from a different UP address */
4524 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4526 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4528 /* MSDN specifies stream zero settings must be set to NULL */
4529 This->stateBlock->streamStride[0] = 0;
4530 This->stateBlock->streamSource[0] = NULL;
4532 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4533 * the new stream sources or use UP drawing again
4535 return WINED3D_OK;
4538 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4539 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4540 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4542 int idxStride;
4543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4544 IWineD3DBuffer *vb;
4545 IWineD3DBuffer *ib;
4547 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4548 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4550 if(!This->stateBlock->vertexDecl) {
4551 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4552 return WINED3DERR_INVALIDCALL;
4555 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4556 idxStride = 2;
4557 } else {
4558 idxStride = 4;
4561 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4562 vb = This->stateBlock->streamSource[0];
4563 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4564 if (vb) IWineD3DBuffer_Release(vb);
4565 This->stateBlock->streamIsUP = TRUE;
4566 This->stateBlock->streamOffset[0] = 0;
4567 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4569 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4570 This->stateBlock->baseVertexIndex = 0;
4571 This->stateBlock->loadBaseVertexIndex = 0;
4572 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4573 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4574 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4576 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4578 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4579 This->stateBlock->streamSource[0] = NULL;
4580 This->stateBlock->streamStride[0] = 0;
4581 ib = This->stateBlock->pIndexData;
4582 if(ib) {
4583 IWineD3DBuffer_Release(ib);
4584 This->stateBlock->pIndexData = NULL;
4586 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4587 * SetStreamSource to specify a vertex buffer
4590 return WINED3D_OK;
4593 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4594 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4598 /* Mark the state dirty until we have nicer tracking
4599 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4600 * that value.
4602 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4603 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4604 This->stateBlock->baseVertexIndex = 0;
4605 This->up_strided = DrawPrimStrideData;
4606 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4607 This->up_strided = NULL;
4608 return WINED3D_OK;
4611 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4612 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4613 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4616 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4618 /* Mark the state dirty until we have nicer tracking
4619 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4620 * that value.
4622 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4623 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4624 This->stateBlock->streamIsUP = TRUE;
4625 This->stateBlock->baseVertexIndex = 0;
4626 This->up_strided = DrawPrimStrideData;
4627 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4628 This->up_strided = NULL;
4629 return WINED3D_OK;
4632 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4633 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4634 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4636 WINED3DLOCKED_BOX src;
4637 WINED3DLOCKED_BOX dst;
4638 HRESULT hr;
4640 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4641 iface, pSourceVolume, pDestinationVolume);
4643 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4644 * dirtification to improve loading performance.
4646 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4647 if(FAILED(hr)) return hr;
4648 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4649 if(FAILED(hr)) {
4650 IWineD3DVolume_UnlockBox(pSourceVolume);
4651 return hr;
4654 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4656 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4657 if(FAILED(hr)) {
4658 IWineD3DVolume_UnlockBox(pSourceVolume);
4659 } else {
4660 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4662 return hr;
4665 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4666 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4668 unsigned int level_count, i;
4669 WINED3DRESOURCETYPE type;
4670 HRESULT hr;
4672 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4674 /* Verify that the source and destination textures are non-NULL. */
4675 if (!src_texture || !dst_texture)
4677 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4678 return WINED3DERR_INVALIDCALL;
4681 if (src_texture == dst_texture)
4683 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4684 return WINED3DERR_INVALIDCALL;
4687 /* Verify that the source and destination textures are the same type. */
4688 type = IWineD3DBaseTexture_GetType(src_texture);
4689 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4691 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4692 return WINED3DERR_INVALIDCALL;
4695 /* Check that both textures have the identical numbers of levels. */
4696 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4697 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4699 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4700 return WINED3DERR_INVALIDCALL;
4703 /* Make sure that the destination texture is loaded. */
4704 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4706 /* Update every surface level of the texture. */
4707 switch (type)
4709 case WINED3DRTYPE_TEXTURE:
4711 IWineD3DSurface *src_surface;
4712 IWineD3DSurface *dst_surface;
4714 for (i = 0; i < level_count; ++i)
4716 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4717 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4718 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4719 IWineD3DSurface_Release(dst_surface);
4720 IWineD3DSurface_Release(src_surface);
4721 if (FAILED(hr))
4723 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4724 return hr;
4727 break;
4730 case WINED3DRTYPE_CUBETEXTURE:
4732 IWineD3DSurface *src_surface;
4733 IWineD3DSurface *dst_surface;
4734 WINED3DCUBEMAP_FACES face;
4736 for (i = 0; i < level_count; ++i)
4738 /* Update each cube face. */
4739 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4741 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4742 face, i, &src_surface);
4743 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4744 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4745 face, i, &dst_surface);
4746 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4747 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4748 IWineD3DSurface_Release(dst_surface);
4749 IWineD3DSurface_Release(src_surface);
4750 if (FAILED(hr))
4752 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4753 return hr;
4757 break;
4760 case WINED3DRTYPE_VOLUMETEXTURE:
4762 IWineD3DVolume *src_volume;
4763 IWineD3DVolume *dst_volume;
4765 for (i = 0; i < level_count; ++i)
4767 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4768 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4769 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4770 IWineD3DVolume_Release(dst_volume);
4771 IWineD3DVolume_Release(src_volume);
4772 if (FAILED(hr))
4774 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4775 return hr;
4778 break;
4781 default:
4782 FIXME("Unsupported texture type %#x.\n", type);
4783 return WINED3DERR_INVALIDCALL;
4786 return WINED3D_OK;
4789 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4790 IWineD3DSwapChain *swapChain;
4791 HRESULT hr;
4792 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4793 if(hr == WINED3D_OK) {
4794 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4795 IWineD3DSwapChain_Release(swapChain);
4797 return hr;
4800 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4802 IWineD3DBaseTextureImpl *texture;
4803 DWORD i;
4805 TRACE("(%p) : %p\n", This, pNumPasses);
4807 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4808 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
4809 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4810 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4812 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
4813 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4814 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4817 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
4818 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
4820 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
4821 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4822 return E_FAIL;
4824 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
4825 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4826 return E_FAIL;
4828 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
4829 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
4830 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4831 return E_FAIL;
4835 /* return a sensible default */
4836 *pNumPasses = 1;
4838 TRACE("returning D3D_OK\n");
4839 return WINED3D_OK;
4842 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
4844 int i;
4846 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4848 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
4849 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
4850 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
4852 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
4857 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4859 int j;
4860 UINT NewSize;
4861 PALETTEENTRY **palettes;
4863 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4865 if (PaletteNumber >= MAX_PALETTES) {
4866 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4867 return WINED3DERR_INVALIDCALL;
4870 if (PaletteNumber >= This->NumberOfPalettes) {
4871 NewSize = This->NumberOfPalettes;
4872 do {
4873 NewSize *= 2;
4874 } while(PaletteNumber >= NewSize);
4875 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
4876 if (!palettes) {
4877 ERR("Out of memory!\n");
4878 return E_OUTOFMEMORY;
4880 This->palettes = palettes;
4881 This->NumberOfPalettes = NewSize;
4884 if (!This->palettes[PaletteNumber]) {
4885 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
4886 if (!This->palettes[PaletteNumber]) {
4887 ERR("Out of memory!\n");
4888 return E_OUTOFMEMORY;
4892 for (j = 0; j < 256; ++j) {
4893 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4894 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4895 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4896 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4898 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
4899 TRACE("(%p) : returning\n", This);
4900 return WINED3D_OK;
4903 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4905 int j;
4906 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4907 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
4908 /* What happens in such situation isn't documented; Native seems to silently abort
4909 on such conditions. Return Invalid Call. */
4910 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
4911 return WINED3DERR_INVALIDCALL;
4913 for (j = 0; j < 256; ++j) {
4914 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4915 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4916 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4917 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4919 TRACE("(%p) : returning\n", This);
4920 return WINED3D_OK;
4923 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4925 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4926 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
4927 (tested with reference rasterizer). Return Invalid Call. */
4928 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
4929 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
4930 return WINED3DERR_INVALIDCALL;
4932 /*TODO: stateblocks */
4933 if (This->currentPalette != PaletteNumber) {
4934 This->currentPalette = PaletteNumber;
4935 dirtify_p8_texture_samplers(This);
4937 TRACE("(%p) : returning\n", This);
4938 return WINED3D_OK;
4941 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4943 if (PaletteNumber == NULL) {
4944 WARN("(%p) : returning Invalid Call\n", This);
4945 return WINED3DERR_INVALIDCALL;
4947 /*TODO: stateblocks */
4948 *PaletteNumber = This->currentPalette;
4949 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4950 return WINED3D_OK;
4953 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4954 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4955 static BOOL warned;
4956 if (!warned)
4958 FIXME("(%p) : stub\n", This);
4959 warned = TRUE;
4962 This->softwareVertexProcessing = bSoftware;
4963 return WINED3D_OK;
4967 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4969 static BOOL warned;
4970 if (!warned)
4972 FIXME("(%p) : stub\n", This);
4973 warned = TRUE;
4975 return This->softwareVertexProcessing;
4978 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
4979 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
4981 IWineD3DSwapChain *swapchain;
4982 HRESULT hr;
4984 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
4985 iface, swapchain_idx, raster_status);
4987 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4988 if (FAILED(hr))
4990 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4991 return hr;
4994 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
4995 IWineD3DSwapChain_Release(swapchain);
4996 if (FAILED(hr))
4998 WARN("Failed to get raster status, hr %#x.\n", hr);
4999 return hr;
5002 return WINED3D_OK;
5005 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5007 static BOOL warned;
5008 if(nSegments != 0.0f) {
5009 if (!warned)
5011 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5012 warned = TRUE;
5015 return WINED3D_OK;
5018 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5020 static BOOL warned;
5021 if (!warned)
5023 FIXME("iface %p stub!\n", iface);
5024 warned = TRUE;
5026 return 0.0f;
5029 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5031 /** TODO: remove casts to IWineD3DSurfaceImpl
5032 * NOTE: move code to surface to accomplish this
5033 ****************************************/
5034 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5035 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5036 int srcWidth, srcHeight;
5037 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5038 WINED3DFORMAT destFormat, srcFormat;
5039 UINT destSize;
5040 int srcLeft, destLeft, destTop;
5041 WINED3DPOOL srcPool, destPool;
5042 int offset = 0;
5043 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5044 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5045 GLenum dummy;
5046 DWORD sampler;
5047 int bpp;
5048 CONVERT_TYPES convert = NO_CONVERSION;
5049 struct wined3d_context *context;
5051 WINED3DSURFACE_DESC winedesc;
5053 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5055 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5056 srcSurfaceWidth = winedesc.width;
5057 srcSurfaceHeight = winedesc.height;
5058 srcPool = winedesc.pool;
5059 srcFormat = winedesc.format;
5061 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5062 destSurfaceWidth = winedesc.width;
5063 destSurfaceHeight = winedesc.height;
5064 destPool = winedesc.pool;
5065 destFormat = winedesc.format;
5066 destSize = winedesc.size;
5068 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5069 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5070 return WINED3DERR_INVALIDCALL;
5073 /* This call loads the opengl surface directly, instead of copying the surface to the
5074 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5075 * copy in sysmem and use regular surface loading.
5077 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5078 if(convert != NO_CONVERSION) {
5079 return IWineD3DSurface_BltFast(pDestinationSurface,
5080 pDestPoint ? pDestPoint->x : 0,
5081 pDestPoint ? pDestPoint->y : 0,
5082 pSourceSurface, pSourceRect, 0);
5085 if (destFormat == WINED3DFMT_UNKNOWN) {
5086 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5087 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5089 /* Get the update surface description */
5090 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5093 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5095 ENTER_GL();
5096 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5097 checkGLcall("glActiveTextureARB");
5098 LEAVE_GL();
5100 /* Make sure the surface is loaded and up to date */
5101 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5102 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5104 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5105 dst_format_desc = dst_impl->resource.format_desc;
5107 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5108 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5109 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5110 srcLeft = pSourceRect ? pSourceRect->left : 0;
5111 destLeft = pDestPoint ? pDestPoint->x : 0;
5112 destTop = pDestPoint ? pDestPoint->y : 0;
5115 /* This function doesn't support compressed textures
5116 the pitch is just bytesPerPixel * width */
5117 if(srcWidth != srcSurfaceWidth || srcLeft ){
5118 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5119 offset += srcLeft * src_format_desc->byte_count;
5120 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5122 /* TODO DXT formats */
5124 if(pSourceRect != NULL && pSourceRect->top != 0){
5125 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5127 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5128 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5129 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5131 /* Sanity check */
5132 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5134 /* need to lock the surface to get the data */
5135 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5138 ENTER_GL();
5140 /* TODO: Cube and volume support */
5141 if(rowoffset != 0){
5142 /* not a whole row so we have to do it a line at a time */
5143 int j;
5145 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5146 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5148 for (j = destTop; j < (srcHeight + destTop); ++j)
5150 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5151 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5152 data += rowoffset;
5155 } else { /* Full width, so just write out the whole texture */
5156 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5158 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5160 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5162 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5163 FIXME("Updating part of a compressed texture is not supported.\n");
5165 if (destFormat != srcFormat)
5167 FIXME("Updating mixed format compressed textures is not supported.\n");
5169 else
5171 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5172 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5175 else
5177 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5178 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5181 checkGLcall("glTexSubImage2D");
5183 LEAVE_GL();
5184 context_release(context);
5186 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5187 sampler = This->rev_tex_unit_map[0];
5188 if (sampler != WINED3D_UNMAPPED_STAGE)
5190 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5193 return WINED3D_OK;
5196 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5198 struct WineD3DRectPatch *patch;
5199 GLenum old_primitive_type;
5200 unsigned int i;
5201 struct list *e;
5202 BOOL found;
5203 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5205 if(!(Handle || pRectPatchInfo)) {
5206 /* TODO: Write a test for the return value, thus the FIXME */
5207 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5208 return WINED3DERR_INVALIDCALL;
5211 if(Handle) {
5212 i = PATCHMAP_HASHFUNC(Handle);
5213 found = FALSE;
5214 LIST_FOR_EACH(e, &This->patches[i]) {
5215 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5216 if(patch->Handle == Handle) {
5217 found = TRUE;
5218 break;
5222 if(!found) {
5223 TRACE("Patch does not exist. Creating a new one\n");
5224 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5225 patch->Handle = Handle;
5226 list_add_head(&This->patches[i], &patch->entry);
5227 } else {
5228 TRACE("Found existing patch %p\n", patch);
5230 } else {
5231 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5232 * attributes we have to tesselate, read back, and draw. This needs a patch
5233 * management structure instance. Create one.
5235 * A possible improvement is to check if a vertex shader is used, and if not directly
5236 * draw the patch.
5238 FIXME("Drawing an uncached patch. This is slow\n");
5239 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5242 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5243 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5244 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5245 HRESULT hr;
5246 TRACE("Tesselation density or patch info changed, retesselating\n");
5248 if(pRectPatchInfo) {
5249 patch->RectPatchInfo = *pRectPatchInfo;
5251 patch->numSegs[0] = pNumSegs[0];
5252 patch->numSegs[1] = pNumSegs[1];
5253 patch->numSegs[2] = pNumSegs[2];
5254 patch->numSegs[3] = pNumSegs[3];
5256 hr = tesselate_rectpatch(This, patch);
5257 if(FAILED(hr)) {
5258 WARN("Patch tesselation failed\n");
5260 /* Do not release the handle to store the params of the patch */
5261 if(!Handle) {
5262 HeapFree(GetProcessHeap(), 0, patch);
5264 return hr;
5268 This->currentPatch = patch;
5269 old_primitive_type = This->stateBlock->gl_primitive_type;
5270 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5271 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5272 This->stateBlock->gl_primitive_type = old_primitive_type;
5273 This->currentPatch = NULL;
5275 /* Destroy uncached patches */
5276 if(!Handle) {
5277 HeapFree(GetProcessHeap(), 0, patch->mem);
5278 HeapFree(GetProcessHeap(), 0, patch);
5280 return WINED3D_OK;
5283 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5284 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5286 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5287 iface, handle, segment_count, patch_info);
5289 return WINED3D_OK;
5292 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5294 int i;
5295 struct WineD3DRectPatch *patch;
5296 struct list *e;
5297 TRACE("(%p) Handle(%d)\n", This, Handle);
5299 i = PATCHMAP_HASHFUNC(Handle);
5300 LIST_FOR_EACH(e, &This->patches[i]) {
5301 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5302 if(patch->Handle == Handle) {
5303 TRACE("Deleting patch %p\n", patch);
5304 list_remove(&patch->entry);
5305 HeapFree(GetProcessHeap(), 0, patch->mem);
5306 HeapFree(GetProcessHeap(), 0, patch);
5307 return WINED3D_OK;
5311 /* TODO: Write a test for the return value */
5312 FIXME("Attempt to destroy nonexistent patch\n");
5313 return WINED3DERR_INVALIDCALL;
5316 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5317 HRESULT hr;
5318 IWineD3DSwapChain *swapchain;
5320 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5321 if (SUCCEEDED(hr)) {
5322 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5323 return swapchain;
5326 return NULL;
5329 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5330 const WINED3DRECT *rect, const float color[4])
5332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5333 struct wined3d_context *context;
5335 if (!surface_is_offscreen(surface))
5337 TRACE("Surface %p is onscreen\n", surface);
5339 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5340 ENTER_GL();
5341 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5342 context_set_draw_buffer(context, surface_get_gl_buffer(surface));
5344 else
5346 TRACE("Surface %p is offscreen\n", surface);
5348 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5349 ENTER_GL();
5350 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5351 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5352 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5355 if (rect) {
5356 glEnable(GL_SCISSOR_TEST);
5357 if(surface_is_offscreen(surface)) {
5358 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5359 } else {
5360 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5361 rect->x2 - rect->x1, rect->y2 - rect->y1);
5363 checkGLcall("glScissor");
5364 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5365 } else {
5366 glDisable(GL_SCISSOR_TEST);
5368 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5370 glDisable(GL_BLEND);
5371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5373 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5374 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5376 glClearColor(color[0], color[1], color[2], color[3]);
5377 glClear(GL_COLOR_BUFFER_BIT);
5378 checkGLcall("glClear");
5380 LEAVE_GL();
5381 context_release(context);
5384 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5385 unsigned int r, g, b, a;
5386 DWORD ret;
5388 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5389 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5390 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5391 return color;
5393 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5395 a = (color & 0xff000000) >> 24;
5396 r = (color & 0x00ff0000) >> 16;
5397 g = (color & 0x0000ff00) >> 8;
5398 b = (color & 0x000000ff) >> 0;
5400 switch(destfmt)
5402 case WINED3DFMT_B5G6R5_UNORM:
5403 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5404 r = (r * 32) / 256;
5405 g = (g * 64) / 256;
5406 b = (b * 32) / 256;
5407 ret = r << 11;
5408 ret |= g << 5;
5409 ret |= b;
5410 TRACE("Returning %08x\n", ret);
5411 return ret;
5413 case WINED3DFMT_B5G5R5X1_UNORM:
5414 case WINED3DFMT_B5G5R5A1_UNORM:
5415 a = (a * 2) / 256;
5416 r = (r * 32) / 256;
5417 g = (g * 32) / 256;
5418 b = (b * 32) / 256;
5419 ret = a << 15;
5420 ret |= r << 10;
5421 ret |= g << 5;
5422 ret |= b << 0;
5423 TRACE("Returning %08x\n", ret);
5424 return ret;
5426 case WINED3DFMT_A8_UNORM:
5427 TRACE("Returning %08x\n", a);
5428 return a;
5430 case WINED3DFMT_B4G4R4X4_UNORM:
5431 case WINED3DFMT_B4G4R4A4_UNORM:
5432 a = (a * 16) / 256;
5433 r = (r * 16) / 256;
5434 g = (g * 16) / 256;
5435 b = (b * 16) / 256;
5436 ret = a << 12;
5437 ret |= r << 8;
5438 ret |= g << 4;
5439 ret |= b << 0;
5440 TRACE("Returning %08x\n", ret);
5441 return ret;
5443 case WINED3DFMT_B2G3R3_UNORM:
5444 r = (r * 8) / 256;
5445 g = (g * 8) / 256;
5446 b = (b * 4) / 256;
5447 ret = r << 5;
5448 ret |= g << 2;
5449 ret |= b << 0;
5450 TRACE("Returning %08x\n", ret);
5451 return ret;
5453 case WINED3DFMT_R8G8B8X8_UNORM:
5454 case WINED3DFMT_R8G8B8A8_UNORM:
5455 ret = a << 24;
5456 ret |= b << 16;
5457 ret |= g << 8;
5458 ret |= r << 0;
5459 TRACE("Returning %08x\n", ret);
5460 return ret;
5462 case WINED3DFMT_B10G10R10A2_UNORM:
5463 a = (a * 4) / 256;
5464 r = (r * 1024) / 256;
5465 g = (g * 1024) / 256;
5466 b = (b * 1024) / 256;
5467 ret = a << 30;
5468 ret |= r << 20;
5469 ret |= g << 10;
5470 ret |= b << 0;
5471 TRACE("Returning %08x\n", ret);
5472 return ret;
5474 case WINED3DFMT_R10G10B10A2_UNORM:
5475 a = (a * 4) / 256;
5476 r = (r * 1024) / 256;
5477 g = (g * 1024) / 256;
5478 b = (b * 1024) / 256;
5479 ret = a << 30;
5480 ret |= b << 20;
5481 ret |= g << 10;
5482 ret |= r << 0;
5483 TRACE("Returning %08x\n", ret);
5484 return ret;
5486 default:
5487 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5488 return 0;
5492 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5493 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5495 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5496 WINEDDBLTFX BltFx;
5498 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5500 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5501 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5502 return WINED3DERR_INVALIDCALL;
5505 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5506 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5507 color_fill_fbo(iface, pSurface, pRect, c);
5508 return WINED3D_OK;
5509 } else {
5510 /* Just forward this to the DirectDraw blitting engine */
5511 memset(&BltFx, 0, sizeof(BltFx));
5512 BltFx.dwSize = sizeof(BltFx);
5513 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5514 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5515 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5519 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5520 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5522 IWineD3DResource *resource;
5523 IWineD3DSurface *surface;
5524 HRESULT hr;
5526 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5527 if (FAILED(hr))
5529 ERR("Failed to get resource, hr %#x\n", hr);
5530 return;
5533 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5535 FIXME("Only supported on surface resources\n");
5536 IWineD3DResource_Release(resource);
5537 return;
5540 surface = (IWineD3DSurface *)resource;
5542 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5544 color_fill_fbo(iface, surface, NULL, color);
5546 else
5548 WINEDDBLTFX BltFx;
5549 WINED3DCOLOR c;
5551 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5553 c = ((DWORD)(color[2] * 255.0f));
5554 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5555 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5556 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5558 /* Just forward this to the DirectDraw blitting engine */
5559 memset(&BltFx, 0, sizeof(BltFx));
5560 BltFx.dwSize = sizeof(BltFx);
5561 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5562 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5563 if (FAILED(hr))
5565 ERR("Blt failed, hr %#x\n", hr);
5569 IWineD3DResource_Release(resource);
5572 /* rendertarget and depth stencil functions */
5573 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5576 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5578 ERR("(%p) : Only %d render targets are supported.\n",
5579 This, This->adapter->gl_info.limits.buffers);
5580 return WINED3DERR_INVALIDCALL;
5583 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5584 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5585 /* Note inc ref on returned surface */
5586 if(*ppRenderTarget != NULL)
5587 IWineD3DSurface_AddRef(*ppRenderTarget);
5588 return WINED3D_OK;
5591 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5592 IWineD3DSurface *Front, IWineD3DSurface *Back)
5594 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5595 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5596 IWineD3DSwapChainImpl *Swapchain;
5597 HRESULT hr;
5599 TRACE("iface %p, front %p, back %p.\n", iface, Front, Back);
5601 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5602 if(hr != WINED3D_OK) {
5603 ERR("Can't get the swapchain\n");
5604 return hr;
5607 /* Make sure to release the swapchain */
5608 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5610 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5611 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5612 return WINED3DERR_INVALIDCALL;
5614 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5615 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5616 return WINED3DERR_INVALIDCALL;
5619 if(Swapchain->frontBuffer != Front) {
5620 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5622 if(Swapchain->frontBuffer)
5624 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5625 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5627 Swapchain->frontBuffer = Front;
5629 if(Swapchain->frontBuffer) {
5630 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5631 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5635 if(Back && !Swapchain->backBuffer) {
5636 /* We need memory for the back buffer array - only one back buffer this way */
5637 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5638 if(!Swapchain->backBuffer) {
5639 ERR("Out of memory\n");
5640 return E_OUTOFMEMORY;
5644 if(Swapchain->backBuffer[0] != Back) {
5645 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5647 /* What to do about the context here in the case of multithreading? Not sure.
5648 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5650 WARN("No active context?\n");
5652 ENTER_GL();
5653 if(!Swapchain->backBuffer[0]) {
5654 /* GL was told to draw to the front buffer at creation,
5655 * undo that
5657 glDrawBuffer(GL_BACK);
5658 checkGLcall("glDrawBuffer(GL_BACK)");
5659 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5660 Swapchain->presentParms.BackBufferCount = 1;
5661 } else if (!Back) {
5662 /* That makes problems - disable for now */
5663 /* glDrawBuffer(GL_FRONT); */
5664 checkGLcall("glDrawBuffer(GL_FRONT)");
5665 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5666 Swapchain->presentParms.BackBufferCount = 0;
5668 LEAVE_GL();
5670 if(Swapchain->backBuffer[0])
5672 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5673 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5675 Swapchain->backBuffer[0] = Back;
5677 if(Swapchain->backBuffer[0]) {
5678 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5679 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
5680 } else {
5681 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5682 Swapchain->backBuffer = NULL;
5687 return WINED3D_OK;
5690 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5692 *ppZStencilSurface = This->stencilBufferTarget;
5693 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5695 if(*ppZStencilSurface != NULL) {
5696 /* Note inc ref on returned surface */
5697 IWineD3DSurface_AddRef(*ppZStencilSurface);
5698 return WINED3D_OK;
5699 } else {
5700 return WINED3DERR_NOTFOUND;
5704 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5705 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
5707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5708 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5709 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5710 const struct wined3d_gl_info *gl_info;
5711 struct wined3d_context *context;
5712 GLenum gl_filter;
5713 POINT offset = {0, 0};
5715 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5716 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5717 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5718 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5720 switch (filter) {
5721 case WINED3DTEXF_LINEAR:
5722 gl_filter = GL_LINEAR;
5723 break;
5725 default:
5726 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5727 case WINED3DTEXF_NONE:
5728 case WINED3DTEXF_POINT:
5729 gl_filter = GL_NEAREST;
5730 break;
5733 /* Attach src surface to src fbo */
5734 src_swapchain = get_swapchain(src_surface);
5735 dst_swapchain = get_swapchain(dst_surface);
5737 if (src_swapchain) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
5738 else if (dst_swapchain) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5739 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5741 gl_info = context->gl_info;
5743 if (!surface_is_offscreen(src_surface))
5745 GLenum buffer = surface_get_gl_buffer(src_surface);
5747 TRACE("Source surface %p is onscreen\n", src_surface);
5748 /* Make sure the drawable is up to date. In the offscreen case
5749 * attach_surface_fbo() implicitly takes care of this. */
5750 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
5752 if(buffer == GL_FRONT) {
5753 RECT windowsize;
5754 UINT h;
5755 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
5756 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
5757 h = windowsize.bottom - windowsize.top;
5758 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
5759 src_rect->y1 = offset.y + h - src_rect->y1;
5760 src_rect->y2 = offset.y + h - src_rect->y2;
5761 } else {
5762 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5763 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5766 ENTER_GL();
5767 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5768 glReadBuffer(buffer);
5769 checkGLcall("glReadBuffer()");
5770 } else {
5771 TRACE("Source surface %p is offscreen\n", src_surface);
5772 ENTER_GL();
5773 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5774 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
5775 glReadBuffer(GL_COLOR_ATTACHMENT0);
5776 checkGLcall("glReadBuffer()");
5777 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5779 LEAVE_GL();
5781 /* Attach dst surface to dst fbo */
5782 if (!surface_is_offscreen(dst_surface))
5784 GLenum buffer = surface_get_gl_buffer(dst_surface);
5786 TRACE("Destination surface %p is onscreen\n", dst_surface);
5787 /* Make sure the drawable is up to date. In the offscreen case
5788 * attach_surface_fbo() implicitly takes care of this. */
5789 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
5791 if(buffer == GL_FRONT) {
5792 RECT windowsize;
5793 UINT h;
5794 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
5795 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
5796 h = windowsize.bottom - windowsize.top;
5797 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
5798 dst_rect->y1 = offset.y + h - dst_rect->y1;
5799 dst_rect->y2 = offset.y + h - dst_rect->y2;
5800 } else {
5801 /* Screen coords = window coords, surface height = window height */
5802 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5803 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5806 ENTER_GL();
5807 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5808 context_set_draw_buffer(context, buffer);
5810 else
5812 TRACE("Destination surface %p is offscreen\n", dst_surface);
5814 ENTER_GL();
5815 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5816 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
5817 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5818 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5820 glDisable(GL_SCISSOR_TEST);
5821 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5823 if (flip) {
5824 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5825 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
5826 checkGLcall("glBlitFramebuffer()");
5827 } else {
5828 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5829 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
5830 checkGLcall("glBlitFramebuffer()");
5833 LEAVE_GL();
5834 context_release(context);
5836 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
5839 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5840 BOOL set_viewport) {
5841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5843 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5845 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5847 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5848 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5849 return WINED3DERR_INVALIDCALL;
5852 /* MSDN says that null disables the render target
5853 but a device must always be associated with a render target
5854 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5856 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5857 FIXME("Trying to set render target 0 to NULL\n");
5858 return WINED3DERR_INVALIDCALL;
5860 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5861 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);
5862 return WINED3DERR_INVALIDCALL;
5865 /* If we are trying to set what we already have, don't bother */
5866 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5867 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5868 return WINED3D_OK;
5870 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5871 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5872 This->render_targets[RenderTargetIndex] = pRenderTarget;
5874 /* Render target 0 is special */
5875 if(RenderTargetIndex == 0 && set_viewport) {
5876 /* Finally, reset the viewport and scissor rect as the MSDN states.
5877 * Tests show that stateblock recording is ignored, the change goes
5878 * directly into the primary stateblock.
5880 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5881 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5882 This->stateBlock->viewport.X = 0;
5883 This->stateBlock->viewport.Y = 0;
5884 This->stateBlock->viewport.MaxZ = 1.0f;
5885 This->stateBlock->viewport.MinZ = 0.0f;
5886 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5888 This->stateBlock->scissorRect.top = 0;
5889 This->stateBlock->scissorRect.left = 0;
5890 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5891 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5892 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5894 return WINED3D_OK;
5897 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5899 HRESULT hr = WINED3D_OK;
5900 IWineD3DSurface *tmp;
5902 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
5904 if (pNewZStencil == This->stencilBufferTarget) {
5905 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5906 } else {
5907 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
5908 * depending on the renter target implementation being used.
5909 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5910 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5911 * stencil buffer and incur an extra memory overhead
5912 ******************************************************/
5914 if (This->stencilBufferTarget) {
5915 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5916 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
5917 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
5918 } else {
5919 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5920 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
5921 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
5922 context_release(context);
5926 tmp = This->stencilBufferTarget;
5927 This->stencilBufferTarget = pNewZStencil;
5928 /* should we be calling the parent or the wined3d surface? */
5929 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5930 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5931 hr = WINED3D_OK;
5933 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5934 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5935 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5936 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5937 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5941 return hr;
5944 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5945 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5947 /* TODO: the use of Impl is deprecated. */
5948 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5949 WINED3DLOCKED_RECT lockedRect;
5951 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5953 /* some basic validation checks */
5954 if(This->cursorTexture) {
5955 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5956 ENTER_GL();
5957 glDeleteTextures(1, &This->cursorTexture);
5958 LEAVE_GL();
5959 context_release(context);
5960 This->cursorTexture = 0;
5963 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5964 This->haveHardwareCursor = TRUE;
5965 else
5966 This->haveHardwareCursor = FALSE;
5968 if(pCursorBitmap) {
5969 WINED3DLOCKED_RECT rect;
5971 /* MSDN: Cursor must be A8R8G8B8 */
5972 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
5974 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5975 return WINED3DERR_INVALIDCALL;
5978 /* MSDN: Cursor must be smaller than the display mode */
5979 if(pSur->currentDesc.Width > This->ddraw_width ||
5980 pSur->currentDesc.Height > This->ddraw_height) {
5981 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);
5982 return WINED3DERR_INVALIDCALL;
5985 if (!This->haveHardwareCursor) {
5986 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5988 /* Do not store the surface's pointer because the application may
5989 * release it after setting the cursor image. Windows doesn't
5990 * addref the set surface, so we can't do this either without
5991 * creating circular refcount dependencies. Copy out the gl texture
5992 * instead.
5994 This->cursorWidth = pSur->currentDesc.Width;
5995 This->cursorHeight = pSur->currentDesc.Height;
5996 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5998 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5999 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6000 struct wined3d_context *context;
6001 char *mem, *bits = rect.pBits;
6002 GLint intfmt = glDesc->glInternal;
6003 GLint format = glDesc->glFormat;
6004 GLint type = glDesc->glType;
6005 INT height = This->cursorHeight;
6006 INT width = This->cursorWidth;
6007 INT bpp = glDesc->byte_count;
6008 DWORD sampler;
6009 INT i;
6011 /* Reformat the texture memory (pitch and width can be
6012 * different) */
6013 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6014 for(i = 0; i < height; i++)
6015 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6016 IWineD3DSurface_UnlockRect(pCursorBitmap);
6018 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6020 ENTER_GL();
6022 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6024 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6025 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6028 /* Make sure that a proper texture unit is selected */
6029 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6030 checkGLcall("glActiveTextureARB");
6031 sampler = This->rev_tex_unit_map[0];
6032 if (sampler != WINED3D_UNMAPPED_STAGE)
6034 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6036 /* Create a new cursor texture */
6037 glGenTextures(1, &This->cursorTexture);
6038 checkGLcall("glGenTextures");
6039 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6040 checkGLcall("glBindTexture");
6041 /* Copy the bitmap memory into the cursor texture */
6042 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6043 HeapFree(GetProcessHeap(), 0, mem);
6044 checkGLcall("glTexImage2D");
6046 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6048 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6049 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6052 LEAVE_GL();
6054 context_release(context);
6056 else
6058 FIXME("A cursor texture was not returned.\n");
6059 This->cursorTexture = 0;
6062 else
6064 /* Draw a hardware cursor */
6065 ICONINFO cursorInfo;
6066 HCURSOR cursor;
6067 /* Create and clear maskBits because it is not needed for
6068 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6069 * chunks. */
6070 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6071 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6072 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6073 WINED3DLOCK_NO_DIRTY_UPDATE |
6074 WINED3DLOCK_READONLY
6076 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6077 pSur->currentDesc.Height);
6079 cursorInfo.fIcon = FALSE;
6080 cursorInfo.xHotspot = XHotSpot;
6081 cursorInfo.yHotspot = YHotSpot;
6082 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6083 1, 1, maskBits);
6084 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6085 1, 32, lockedRect.pBits);
6086 IWineD3DSurface_UnlockRect(pCursorBitmap);
6087 /* Create our cursor and clean up. */
6088 cursor = CreateIconIndirect(&cursorInfo);
6089 SetCursor(cursor);
6090 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6091 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6092 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6093 This->hardwareCursor = cursor;
6094 HeapFree(GetProcessHeap(), 0, maskBits);
6098 This->xHotSpot = XHotSpot;
6099 This->yHotSpot = YHotSpot;
6100 return WINED3D_OK;
6103 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6105 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6107 This->xScreenSpace = XScreenSpace;
6108 This->yScreenSpace = YScreenSpace;
6110 return;
6114 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6116 BOOL oldVisible = This->bCursorVisible;
6117 POINT pt;
6119 TRACE("(%p) : visible(%d)\n", This, bShow);
6122 * When ShowCursor is first called it should make the cursor appear at the OS's last
6123 * known cursor position. Because of this, some applications just repetitively call
6124 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6126 GetCursorPos(&pt);
6127 This->xScreenSpace = pt.x;
6128 This->yScreenSpace = pt.y;
6130 if (This->haveHardwareCursor) {
6131 This->bCursorVisible = bShow;
6132 if (bShow)
6133 SetCursor(This->hardwareCursor);
6134 else
6135 SetCursor(NULL);
6137 else
6139 if (This->cursorTexture)
6140 This->bCursorVisible = bShow;
6143 return oldVisible;
6146 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6147 TRACE("checking resource %p for eviction\n", resource);
6148 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6149 TRACE("Evicting %p\n", resource);
6150 IWineD3DResource_UnLoad(resource);
6152 IWineD3DResource_Release(resource);
6153 return S_OK;
6156 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6158 TRACE("iface %p.\n", iface);
6160 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6161 return WINED3D_OK;
6164 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6166 IWineD3DDeviceImpl *device = surface->resource.device;
6167 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6169 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6170 if(surface->Flags & SFLAG_DIBSECTION) {
6171 /* Release the DC */
6172 SelectObject(surface->hDC, surface->dib.holdbitmap);
6173 DeleteDC(surface->hDC);
6174 /* Release the DIB section */
6175 DeleteObject(surface->dib.DIBsection);
6176 surface->dib.bitmap_data = NULL;
6177 surface->resource.allocatedMemory = NULL;
6178 surface->Flags &= ~SFLAG_DIBSECTION;
6180 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6181 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6182 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6183 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6185 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6186 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6187 } else {
6188 surface->pow2Width = surface->pow2Height = 1;
6189 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6190 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6192 surface->glRect.left = 0;
6193 surface->glRect.top = 0;
6194 surface->glRect.right = surface->pow2Width;
6195 surface->glRect.bottom = surface->pow2Height;
6197 if (surface->texture_name)
6199 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6200 ENTER_GL();
6201 glDeleteTextures(1, &surface->texture_name);
6202 LEAVE_GL();
6203 context_release(context);
6204 surface->texture_name = 0;
6205 surface->Flags &= ~SFLAG_CLIENT;
6207 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6208 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6209 surface->Flags |= SFLAG_NONPOW2;
6210 } else {
6211 surface->Flags &= ~SFLAG_NONPOW2;
6213 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6214 surface->resource.allocatedMemory = NULL;
6215 surface->resource.heapMemory = NULL;
6216 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6218 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6219 * to a FBO */
6220 if(!surface_init_sysmem((IWineD3DSurface *) surface))
6222 return E_OUTOFMEMORY;
6224 return WINED3D_OK;
6227 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6228 TRACE("Unloading resource %p\n", resource);
6229 IWineD3DResource_UnLoad(resource);
6230 IWineD3DResource_Release(resource);
6231 return S_OK;
6234 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6236 UINT i, count;
6237 WINED3DDISPLAYMODE m;
6238 HRESULT hr;
6240 /* All Windowed modes are supported, as is leaving the current mode */
6241 if(pp->Windowed) return TRUE;
6242 if(!pp->BackBufferWidth) return TRUE;
6243 if(!pp->BackBufferHeight) return TRUE;
6245 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6246 for(i = 0; i < count; i++) {
6247 memset(&m, 0, sizeof(m));
6248 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6249 if(FAILED(hr)) {
6250 ERR("EnumAdapterModes failed\n");
6252 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6253 /* Mode found, it is supported */
6254 return TRUE;
6257 /* Mode not found -> not supported */
6258 return FALSE;
6261 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6263 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6264 const struct wined3d_gl_info *gl_info;
6265 struct wined3d_context *context;
6266 IWineD3DBaseShaderImpl *shader;
6268 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6269 gl_info = context->gl_info;
6271 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6272 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6273 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6276 ENTER_GL();
6277 if(This->depth_blt_texture) {
6278 glDeleteTextures(1, &This->depth_blt_texture);
6279 This->depth_blt_texture = 0;
6281 if (This->depth_blt_rb) {
6282 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6283 This->depth_blt_rb = 0;
6284 This->depth_blt_rb_w = 0;
6285 This->depth_blt_rb_h = 0;
6287 LEAVE_GL();
6289 This->blitter->free_private(iface);
6290 This->frag_pipe->free_private(iface);
6291 This->shader_backend->shader_free_private(iface);
6292 destroy_dummy_textures(This, gl_info);
6294 context_release(context);
6296 while (This->numContexts)
6298 context_destroy(This, This->contexts[0]);
6300 HeapFree(GetProcessHeap(), 0, swapchain->context);
6301 swapchain->context = NULL;
6302 swapchain->num_contexts = 0;
6305 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6307 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6308 struct wined3d_context *context;
6309 HRESULT hr;
6310 IWineD3DSurfaceImpl *target;
6312 /* Recreate the primary swapchain's context */
6313 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6314 if (!swapchain->context)
6316 ERR("Failed to allocate memory for swapchain context array.\n");
6317 return E_OUTOFMEMORY;
6320 target = (IWineD3DSurfaceImpl *)(swapchain->backBuffer ? swapchain->backBuffer[0] : swapchain->frontBuffer);
6321 context = context_create(This, target, swapchain->win_handle, FALSE, &swapchain->presentParms);
6322 if (!context)
6324 WARN("Failed to create context.\n");
6325 HeapFree(GetProcessHeap(), 0, swapchain->context);
6326 return E_FAIL;
6329 swapchain->context[0] = context;
6330 swapchain->num_contexts = 1;
6331 create_dummy_textures(This);
6332 context_release(context);
6334 hr = This->shader_backend->shader_alloc_private(iface);
6335 if (FAILED(hr))
6337 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6338 goto err;
6341 hr = This->frag_pipe->alloc_private(iface);
6342 if (FAILED(hr))
6344 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6345 This->shader_backend->shader_free_private(iface);
6346 goto err;
6349 hr = This->blitter->alloc_private(iface);
6350 if (FAILED(hr))
6352 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6353 This->frag_pipe->free_private(iface);
6354 This->shader_backend->shader_free_private(iface);
6355 goto err;
6358 return WINED3D_OK;
6360 err:
6361 context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6362 destroy_dummy_textures(This, context->gl_info);
6363 context_release(context);
6364 context_destroy(This, context);
6365 HeapFree(GetProcessHeap(), 0, swapchain->context);
6366 swapchain->num_contexts = 0;
6367 return hr;
6370 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6371 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6372 IWineD3DSwapChainImpl *swapchain;
6373 HRESULT hr;
6374 BOOL DisplayModeChanged = FALSE;
6375 WINED3DDISPLAYMODE mode;
6376 TRACE("(%p)\n", This);
6378 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6379 if(FAILED(hr)) {
6380 ERR("Failed to get the first implicit swapchain\n");
6381 return hr;
6384 if(!is_display_mode_supported(This, pPresentationParameters)) {
6385 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6386 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6387 pPresentationParameters->BackBufferHeight);
6388 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6389 return WINED3DERR_INVALIDCALL;
6392 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6393 * on an existing gl context, so there's no real need for recreation.
6395 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6397 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6399 TRACE("New params:\n");
6400 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6401 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6402 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6403 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6404 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6405 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6406 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6407 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6408 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6409 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6410 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6411 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6412 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6414 /* No special treatment of these parameters. Just store them */
6415 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6416 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6417 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6418 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6420 /* What to do about these? */
6421 if(pPresentationParameters->BackBufferCount != 0 &&
6422 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6423 ERR("Cannot change the back buffer count yet\n");
6425 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6426 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6427 ERR("Cannot change the back buffer format yet\n");
6429 if(pPresentationParameters->hDeviceWindow != NULL &&
6430 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6431 ERR("Cannot change the device window yet\n");
6433 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6434 HRESULT hrc;
6436 TRACE("Creating the depth stencil buffer\n");
6438 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6439 This->parent,
6440 pPresentationParameters->BackBufferWidth,
6441 pPresentationParameters->BackBufferHeight,
6442 pPresentationParameters->AutoDepthStencilFormat,
6443 pPresentationParameters->MultiSampleType,
6444 pPresentationParameters->MultiSampleQuality,
6445 FALSE,
6446 &This->auto_depth_stencil_buffer);
6448 if (FAILED(hrc)) {
6449 ERR("Failed to create the depth stencil buffer\n");
6450 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6451 return WINED3DERR_INVALIDCALL;
6455 /* Reset the depth stencil */
6456 if (pPresentationParameters->EnableAutoDepthStencil)
6457 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6458 else
6459 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6461 TRACE("Resetting stateblock\n");
6462 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6463 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6465 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6467 if(pPresentationParameters->Windowed) {
6468 mode.Width = swapchain->orig_width;
6469 mode.Height = swapchain->orig_height;
6470 mode.RefreshRate = 0;
6471 mode.Format = swapchain->presentParms.BackBufferFormat;
6472 } else {
6473 mode.Width = pPresentationParameters->BackBufferWidth;
6474 mode.Height = pPresentationParameters->BackBufferHeight;
6475 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6476 mode.Format = swapchain->presentParms.BackBufferFormat;
6479 /* Should Width == 800 && Height == 0 set 800x600? */
6480 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6481 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6482 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6484 UINT i;
6486 if(!pPresentationParameters->Windowed) {
6487 DisplayModeChanged = TRUE;
6489 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6490 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6492 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6493 if(FAILED(hr))
6495 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6496 return hr;
6499 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6500 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6501 if(FAILED(hr))
6503 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6504 return hr;
6507 if(This->auto_depth_stencil_buffer) {
6508 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6509 if(FAILED(hr))
6511 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6512 return hr;
6517 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6518 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6519 DisplayModeChanged) {
6521 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6523 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
6524 if(swapchain->presentParms.Windowed) {
6525 /* switch from windowed to fs */
6526 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6527 pPresentationParameters->BackBufferHeight);
6528 } else {
6529 /* Fullscreen -> fullscreen mode change */
6530 MoveWindow(swapchain->win_handle, 0, 0,
6531 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6532 TRUE);
6534 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
6535 /* Fullscreen -> windowed switch */
6536 swapchain_restore_fullscreen_window(swapchain);
6538 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6539 } else if(!pPresentationParameters->Windowed) {
6540 DWORD style = This->style, exStyle = This->exStyle;
6541 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6542 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6543 * Reset to clear up their mess. Guild Wars also loses the device during that.
6545 This->style = 0;
6546 This->exStyle = 0;
6547 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6548 pPresentationParameters->BackBufferHeight);
6549 This->style = style;
6550 This->exStyle = exStyle;
6553 /* Note: No parent needed for initial internal stateblock */
6554 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6555 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6556 else TRACE("Created stateblock %p\n", This->stateBlock);
6557 This->updateStateBlock = This->stateBlock;
6558 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6560 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6561 if(FAILED(hr)) {
6562 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6565 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6567 RECT client_rect;
6568 GetClientRect(swapchain->win_handle, &client_rect);
6570 if(!swapchain->presentParms.BackBufferCount)
6572 TRACE("Single buffered rendering\n");
6573 swapchain->render_to_fbo = FALSE;
6575 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6576 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6578 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6579 swapchain->presentParms.BackBufferWidth,
6580 swapchain->presentParms.BackBufferHeight,
6581 client_rect.right, client_rect.bottom);
6582 swapchain->render_to_fbo = TRUE;
6584 else
6586 TRACE("Rendering directly to GL_BACK\n");
6587 swapchain->render_to_fbo = FALSE;
6591 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6592 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6594 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6595 * first use
6597 return hr;
6600 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6602 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6604 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6606 return WINED3D_OK;
6610 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6612 TRACE("(%p) : pParameters %p\n", This, pParameters);
6614 *pParameters = This->createParms;
6615 return WINED3D_OK;
6618 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6619 IWineD3DSwapChain *swapchain;
6621 TRACE("Relaying to swapchain\n");
6623 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6624 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6625 IWineD3DSwapChain_Release(swapchain);
6629 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6630 IWineD3DSwapChain *swapchain;
6632 TRACE("Relaying to swapchain\n");
6634 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6635 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6636 IWineD3DSwapChain_Release(swapchain);
6641 /** ********************************************************
6642 * Notification functions
6643 ** ********************************************************/
6644 /** This function must be called in the release of a resource when ref == 0,
6645 * the contents of resource must still be correct,
6646 * any handles to other resource held by the caller must be closed
6647 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6648 *****************************************************/
6649 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6651 TRACE("(%p) : Adding resource %p\n", This, resource);
6653 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6656 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6658 TRACE("(%p) : Removing resource %p\n", This, resource);
6660 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6663 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6665 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6666 int counter;
6668 TRACE("(%p) : resource %p\n", This, resource);
6670 context_resource_released((IWineD3DDevice *)This, resource, type);
6672 switch (type) {
6673 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6674 case WINED3DRTYPE_SURFACE: {
6675 unsigned int i;
6677 if (This->d3d_initialized)
6679 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6681 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6682 This->render_targets[i] = NULL;
6685 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6686 This->stencilBufferTarget = NULL;
6690 break;
6692 case WINED3DRTYPE_TEXTURE:
6693 case WINED3DRTYPE_CUBETEXTURE:
6694 case WINED3DRTYPE_VOLUMETEXTURE:
6695 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6696 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6697 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6698 This->stateBlock->textures[counter] = NULL;
6700 if (This->updateStateBlock != This->stateBlock ){
6701 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6702 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6703 This->updateStateBlock->textures[counter] = NULL;
6707 break;
6708 case WINED3DRTYPE_VOLUME:
6709 /* TODO: nothing really? */
6710 break;
6711 case WINED3DRTYPE_BUFFER:
6713 int streamNumber;
6714 TRACE("Cleaning up stream pointers\n");
6716 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6717 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6718 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6720 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6721 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6722 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6723 This->updateStateBlock->streamSource[streamNumber] = 0;
6724 /* Set changed flag? */
6727 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) */
6728 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6729 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6730 This->stateBlock->streamSource[streamNumber] = 0;
6735 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6736 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6737 This->updateStateBlock->pIndexData = NULL;
6740 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6741 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6742 This->stateBlock->pIndexData = NULL;
6746 break;
6748 default:
6749 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6750 break;
6754 /* Remove the resource from the resourceStore */
6755 device_resource_remove(This, resource);
6757 TRACE("Resource released\n");
6761 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6763 IWineD3DResourceImpl *resource, *cursor;
6764 HRESULT ret;
6765 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6767 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6768 TRACE("enumerating resource %p\n", resource);
6769 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6770 ret = pCallback((IWineD3DResource *) resource, pData);
6771 if(ret == S_FALSE) {
6772 TRACE("Canceling enumeration\n");
6773 break;
6776 return WINED3D_OK;
6779 /**********************************************************
6780 * IWineD3DDevice VTbl follows
6781 **********************************************************/
6783 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6785 /*** IUnknown methods ***/
6786 IWineD3DDeviceImpl_QueryInterface,
6787 IWineD3DDeviceImpl_AddRef,
6788 IWineD3DDeviceImpl_Release,
6789 /*** IWineD3DDevice methods ***/
6790 IWineD3DDeviceImpl_GetParent,
6791 /*** Creation methods**/
6792 IWineD3DDeviceImpl_CreateBuffer,
6793 IWineD3DDeviceImpl_CreateVertexBuffer,
6794 IWineD3DDeviceImpl_CreateIndexBuffer,
6795 IWineD3DDeviceImpl_CreateStateBlock,
6796 IWineD3DDeviceImpl_CreateSurface,
6797 IWineD3DDeviceImpl_CreateRendertargetView,
6798 IWineD3DDeviceImpl_CreateTexture,
6799 IWineD3DDeviceImpl_CreateVolumeTexture,
6800 IWineD3DDeviceImpl_CreateVolume,
6801 IWineD3DDeviceImpl_CreateCubeTexture,
6802 IWineD3DDeviceImpl_CreateQuery,
6803 IWineD3DDeviceImpl_CreateSwapChain,
6804 IWineD3DDeviceImpl_CreateVertexDeclaration,
6805 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6806 IWineD3DDeviceImpl_CreateVertexShader,
6807 IWineD3DDeviceImpl_CreatePixelShader,
6808 IWineD3DDeviceImpl_CreatePalette,
6809 /*** Odd functions **/
6810 IWineD3DDeviceImpl_Init3D,
6811 IWineD3DDeviceImpl_InitGDI,
6812 IWineD3DDeviceImpl_Uninit3D,
6813 IWineD3DDeviceImpl_UninitGDI,
6814 IWineD3DDeviceImpl_SetMultithreaded,
6815 IWineD3DDeviceImpl_EvictManagedResources,
6816 IWineD3DDeviceImpl_GetAvailableTextureMem,
6817 IWineD3DDeviceImpl_GetBackBuffer,
6818 IWineD3DDeviceImpl_GetCreationParameters,
6819 IWineD3DDeviceImpl_GetDeviceCaps,
6820 IWineD3DDeviceImpl_GetDirect3D,
6821 IWineD3DDeviceImpl_GetDisplayMode,
6822 IWineD3DDeviceImpl_SetDisplayMode,
6823 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6824 IWineD3DDeviceImpl_GetRasterStatus,
6825 IWineD3DDeviceImpl_GetSwapChain,
6826 IWineD3DDeviceImpl_Reset,
6827 IWineD3DDeviceImpl_SetDialogBoxMode,
6828 IWineD3DDeviceImpl_SetCursorProperties,
6829 IWineD3DDeviceImpl_SetCursorPosition,
6830 IWineD3DDeviceImpl_ShowCursor,
6831 /*** Getters and setters **/
6832 IWineD3DDeviceImpl_SetClipPlane,
6833 IWineD3DDeviceImpl_GetClipPlane,
6834 IWineD3DDeviceImpl_SetClipStatus,
6835 IWineD3DDeviceImpl_GetClipStatus,
6836 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6837 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6838 IWineD3DDeviceImpl_SetDepthStencilSurface,
6839 IWineD3DDeviceImpl_GetDepthStencilSurface,
6840 IWineD3DDeviceImpl_SetGammaRamp,
6841 IWineD3DDeviceImpl_GetGammaRamp,
6842 IWineD3DDeviceImpl_SetIndexBuffer,
6843 IWineD3DDeviceImpl_GetIndexBuffer,
6844 IWineD3DDeviceImpl_SetBaseVertexIndex,
6845 IWineD3DDeviceImpl_GetBaseVertexIndex,
6846 IWineD3DDeviceImpl_SetLight,
6847 IWineD3DDeviceImpl_GetLight,
6848 IWineD3DDeviceImpl_SetLightEnable,
6849 IWineD3DDeviceImpl_GetLightEnable,
6850 IWineD3DDeviceImpl_SetMaterial,
6851 IWineD3DDeviceImpl_GetMaterial,
6852 IWineD3DDeviceImpl_SetNPatchMode,
6853 IWineD3DDeviceImpl_GetNPatchMode,
6854 IWineD3DDeviceImpl_SetPaletteEntries,
6855 IWineD3DDeviceImpl_GetPaletteEntries,
6856 IWineD3DDeviceImpl_SetPixelShader,
6857 IWineD3DDeviceImpl_GetPixelShader,
6858 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6859 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6860 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6861 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6862 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6863 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6864 IWineD3DDeviceImpl_SetRenderState,
6865 IWineD3DDeviceImpl_GetRenderState,
6866 IWineD3DDeviceImpl_SetRenderTarget,
6867 IWineD3DDeviceImpl_GetRenderTarget,
6868 IWineD3DDeviceImpl_SetFrontBackBuffers,
6869 IWineD3DDeviceImpl_SetSamplerState,
6870 IWineD3DDeviceImpl_GetSamplerState,
6871 IWineD3DDeviceImpl_SetScissorRect,
6872 IWineD3DDeviceImpl_GetScissorRect,
6873 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6874 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6875 IWineD3DDeviceImpl_SetStreamSource,
6876 IWineD3DDeviceImpl_GetStreamSource,
6877 IWineD3DDeviceImpl_SetStreamSourceFreq,
6878 IWineD3DDeviceImpl_GetStreamSourceFreq,
6879 IWineD3DDeviceImpl_SetTexture,
6880 IWineD3DDeviceImpl_GetTexture,
6881 IWineD3DDeviceImpl_SetTextureStageState,
6882 IWineD3DDeviceImpl_GetTextureStageState,
6883 IWineD3DDeviceImpl_SetTransform,
6884 IWineD3DDeviceImpl_GetTransform,
6885 IWineD3DDeviceImpl_SetVertexDeclaration,
6886 IWineD3DDeviceImpl_GetVertexDeclaration,
6887 IWineD3DDeviceImpl_SetVertexShader,
6888 IWineD3DDeviceImpl_GetVertexShader,
6889 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6890 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6891 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6892 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6893 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6894 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6895 IWineD3DDeviceImpl_SetViewport,
6896 IWineD3DDeviceImpl_GetViewport,
6897 IWineD3DDeviceImpl_MultiplyTransform,
6898 IWineD3DDeviceImpl_ValidateDevice,
6899 IWineD3DDeviceImpl_ProcessVertices,
6900 /*** State block ***/
6901 IWineD3DDeviceImpl_BeginStateBlock,
6902 IWineD3DDeviceImpl_EndStateBlock,
6903 /*** Scene management ***/
6904 IWineD3DDeviceImpl_BeginScene,
6905 IWineD3DDeviceImpl_EndScene,
6906 IWineD3DDeviceImpl_Present,
6907 IWineD3DDeviceImpl_Clear,
6908 IWineD3DDeviceImpl_ClearRendertargetView,
6909 /*** Drawing ***/
6910 IWineD3DDeviceImpl_SetPrimitiveType,
6911 IWineD3DDeviceImpl_GetPrimitiveType,
6912 IWineD3DDeviceImpl_DrawPrimitive,
6913 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6914 IWineD3DDeviceImpl_DrawPrimitiveUP,
6915 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6916 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6917 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6918 IWineD3DDeviceImpl_DrawRectPatch,
6919 IWineD3DDeviceImpl_DrawTriPatch,
6920 IWineD3DDeviceImpl_DeletePatch,
6921 IWineD3DDeviceImpl_ColorFill,
6922 IWineD3DDeviceImpl_UpdateTexture,
6923 IWineD3DDeviceImpl_UpdateSurface,
6924 IWineD3DDeviceImpl_GetFrontBufferData,
6925 /*** object tracking ***/
6926 IWineD3DDeviceImpl_EnumResources
6929 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6930 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6931 IUnknown *parent, IWineD3DDeviceParent *device_parent)
6933 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6934 const struct fragment_pipeline *fragment_pipeline;
6935 struct shader_caps shader_caps;
6936 struct fragment_caps ffp_caps;
6937 WINED3DDISPLAYMODE mode;
6938 unsigned int i;
6939 HRESULT hr;
6941 device->lpVtbl = &IWineD3DDevice_Vtbl;
6942 device->ref = 1;
6943 device->wined3d = (IWineD3D *)wined3d;
6944 IWineD3D_AddRef(device->wined3d);
6945 device->adapter = wined3d->adapter_count ? adapter : NULL;
6946 device->parent = parent;
6947 device->device_parent = device_parent;
6948 list_init(&device->resources);
6949 list_init(&device->shaders);
6951 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6952 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6954 /* Get the initial screen setup for ddraw. */
6955 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6956 if (FAILED(hr))
6958 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6959 IWineD3D_Release(device->wined3d);
6960 return hr;
6962 device->ddraw_width = mode.Width;
6963 device->ddraw_height = mode.Height;
6964 device->ddraw_format = mode.Format;
6966 /* Save the creation parameters. */
6967 device->createParms.AdapterOrdinal = adapter_idx;
6968 device->createParms.DeviceType = device_type;
6969 device->createParms.hFocusWindow = focus_window;
6970 device->createParms.BehaviorFlags = flags;
6972 device->devType = device_type;
6973 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6975 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6976 device->shader_backend = select_shader_backend(adapter, device_type);
6978 memset(&shader_caps, 0, sizeof(shader_caps));
6979 device->shader_backend->shader_get_caps(device_type, &adapter->gl_info, &shader_caps);
6980 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6981 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6982 device->vs_clipping = shader_caps.VSClipping;
6984 memset(&ffp_caps, 0, sizeof(ffp_caps));
6985 fragment_pipeline = select_fragment_implementation(adapter, device_type);
6986 device->frag_pipe = fragment_pipeline;
6987 fragment_pipeline->get_caps(device_type, &adapter->gl_info, &ffp_caps);
6988 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6989 device->max_ffp_texture_stages = ffp_caps.MaxTextureBlendStages;
6991 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6992 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6993 if (FAILED(hr))
6995 ERR("Failed to compile state table, hr %#x.\n", hr);
6996 IWineD3D_Release(device->wined3d);
6997 return hr;
7000 device->blitter = select_blit_implementation(adapter, device_type);
7002 return WINED3D_OK;
7006 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7007 DWORD rep = This->StateTable[state].representative;
7008 struct wined3d_context *context;
7009 DWORD idx;
7010 BYTE shift;
7011 UINT i;
7013 for(i = 0; i < This->numContexts; i++) {
7014 context = This->contexts[i];
7015 if(isStateDirty(context, rep)) continue;
7017 context->dirtyArray[context->numDirtyEntries++] = rep;
7018 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7019 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7020 context->isStateDirty[idx] |= (1 << shift);
7024 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7026 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.device;
7027 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7028 *width = device->pbufferWidth;
7029 *height = device->pbufferHeight;
7032 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7034 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7035 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7036 *width = surface->pow2Width;
7037 *height = surface->pow2Height;
7040 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7042 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7043 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7044 * current context's drawable, which is the size of the back buffer of the swapchain
7045 * the active context belongs to. The back buffer of the swapchain is stored as the
7046 * surface the context belongs to. */
7047 *width = surface->currentDesc.Width;
7048 *height = surface->currentDesc.Height;
7051 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7052 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7054 if (device->filter_messages)
7056 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7057 window, message, wparam, lparam);
7058 return DefWindowProcW(window, message, wparam, lparam);
7061 if (message == WM_DESTROY)
7063 TRACE("unregister window %p.\n", window);
7064 wined3d_unregister_window(window);
7066 if (device->focus_window == window) device->focus_window = NULL;
7067 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7070 return CallWindowProcW(proc, window, message, wparam, lparam);