push 149f0a5527ac85057a8ef03858d34d91c36f97e8
[wine/hacks.git] / dlls / wined3d / device.c
blobcefabea2a55c0e96951b61e94b79bfe850c6a4ee
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "config.h"
30 #include <stdio.h>
31 #ifdef HAVE_FLOAT_H
32 # include <float.h>
33 #endif
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
37 #define GLINFO_LOCATION This->adapter->gl_info
39 /* Define the default light parameters as specified by MSDN */
40 const WINED3DLIGHT WINED3D_default_light = {
42 WINED3DLIGHT_DIRECTIONAL, /* Type */
43 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
45 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
46 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
47 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
48 0.0f, /* Range */
49 0.0f, /* Falloff */
50 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
51 0.0f, /* Theta */
52 0.0f /* Phi */
55 /**********************************************************
56 * Global variable / Constants follow
57 **********************************************************/
58 const float identity[] =
60 1.0f, 0.0f, 0.0f, 0.0f,
61 0.0f, 1.0f, 0.0f, 0.0f,
62 0.0f, 0.0f, 1.0f, 0.0f,
63 0.0f, 0.0f, 0.0f, 1.0f,
64 }; /* When needed for comparisons */
66 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
67 * actually have the same values in GL and D3D. */
68 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
70 switch(primitive_type)
72 case WINED3DPT_POINTLIST:
73 return GL_POINTS;
75 case WINED3DPT_LINELIST:
76 return GL_LINES;
78 case WINED3DPT_LINESTRIP:
79 return GL_LINE_STRIP;
81 case WINED3DPT_TRIANGLELIST:
82 return GL_TRIANGLES;
84 case WINED3DPT_TRIANGLESTRIP:
85 return GL_TRIANGLE_STRIP;
87 case WINED3DPT_TRIANGLEFAN:
88 return GL_TRIANGLE_FAN;
90 case WINED3DPT_LINELIST_ADJ:
91 return GL_LINES_ADJACENCY_ARB;
93 case WINED3DPT_LINESTRIP_ADJ:
94 return GL_LINE_STRIP_ADJACENCY_ARB;
96 case WINED3DPT_TRIANGLELIST_ADJ:
97 return GL_TRIANGLES_ADJACENCY_ARB;
99 case WINED3DPT_TRIANGLESTRIP_ADJ:
100 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
102 default:
103 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
104 return GL_NONE;
108 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
110 switch(primitive_type)
112 case GL_POINTS:
113 return WINED3DPT_POINTLIST;
115 case GL_LINES:
116 return WINED3DPT_LINELIST;
118 case GL_LINE_STRIP:
119 return WINED3DPT_LINESTRIP;
121 case GL_TRIANGLES:
122 return WINED3DPT_TRIANGLELIST;
124 case GL_TRIANGLE_STRIP:
125 return WINED3DPT_TRIANGLESTRIP;
127 case GL_TRIANGLE_FAN:
128 return WINED3DPT_TRIANGLEFAN;
130 case GL_LINES_ADJACENCY_ARB:
131 return WINED3DPT_LINELIST_ADJ;
133 case GL_LINE_STRIP_ADJACENCY_ARB:
134 return WINED3DPT_LINESTRIP_ADJ;
136 case GL_TRIANGLES_ADJACENCY_ARB:
137 return WINED3DPT_TRIANGLELIST_ADJ;
139 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
140 return WINED3DPT_TRIANGLESTRIP_ADJ;
142 default:
143 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
144 return WINED3DPT_UNDEFINED;
148 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
150 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
151 *regnum = WINED3D_FFP_POSITION;
152 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
153 *regnum = WINED3D_FFP_BLENDWEIGHT;
154 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
155 *regnum = WINED3D_FFP_BLENDINDICES;
156 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
157 *regnum = WINED3D_FFP_NORMAL;
158 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
159 *regnum = WINED3D_FFP_PSIZE;
160 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
161 *regnum = WINED3D_FFP_DIFFUSE;
162 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
163 *regnum = WINED3D_FFP_SPECULAR;
164 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
165 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
166 else
168 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
169 *regnum = ~0U;
170 return FALSE;
173 return TRUE;
176 /* Context activation is done by the caller. */
177 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
178 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
180 /* We need to deal with frequency data! */
181 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
182 UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
183 const DWORD *streams = declaration->streams;
184 unsigned int i;
186 stream_info->use_map = 0;
187 stream_info->swizzle_map = 0;
189 /* Check for transformed vertices, disable vertex shader if present. */
190 stream_info->position_transformed = declaration->position_transformed;
191 if (declaration->position_transformed) use_vshader = FALSE;
193 /* Translate the declaration into strided data. */
194 for (i = 0; i < declaration->element_count; ++i)
196 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
197 GLuint buffer_object = 0;
198 const BYTE *data = NULL;
199 BOOL stride_used;
200 unsigned int idx;
201 DWORD stride;
203 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
204 element, i + 1, declaration->element_count);
206 if (!This->stateBlock->streamSource[element->input_slot]) continue;
208 stride = This->stateBlock->streamStride[element->input_slot];
209 if (This->stateBlock->streamIsUP)
211 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
212 buffer_object = 0;
213 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
215 else
217 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
218 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
220 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
221 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
222 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
223 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
224 * not, drawStridedSlow is needed, including a vertex buffer path. */
225 if (This->stateBlock->loadBaseVertexIndex < 0)
227 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
228 buffer_object = 0;
229 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
230 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
232 FIXME("System memory vertex data load offset is negative!\n");
236 if (fixup)
238 if (buffer_object) *fixup = TRUE;
239 else if (*fixup && !use_vshader
240 && (element->usage == WINED3DDECLUSAGE_COLOR
241 || element->usage == WINED3DDECLUSAGE_POSITIONT))
243 static BOOL warned = FALSE;
244 if (!warned)
246 /* This may be bad with the fixed function pipeline. */
247 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
248 warned = TRUE;
253 data += element->offset;
255 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
257 if (use_vshader)
259 if (element->output_slot == ~0U)
261 /* TODO: Assuming vertexdeclarations are usually used with the
262 * same or a similar shader, it might be worth it to store the
263 * last used output slot and try that one first. */
264 stride_used = vshader_get_input(This->stateBlock->vertexShader,
265 element->usage, element->usage_idx, &idx);
267 else
269 idx = element->output_slot;
270 stride_used = TRUE;
273 else
275 if (!element->ffp_valid)
277 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
278 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
279 stride_used = FALSE;
281 else
283 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
287 if (stride_used)
289 TRACE("Load %s array %u [usage %s, usage_idx %u, "
290 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
291 use_vshader ? "shader": "fixed function", idx,
292 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
293 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
295 stream_info->elements[idx].format_desc = element->format_desc;
296 stream_info->elements[idx].stride = stride;
297 stream_info->elements[idx].data = data;
298 stream_info->elements[idx].stream_idx = element->input_slot;
299 stream_info->elements[idx].buffer_object = buffer_object;
301 if (!This->adapter->gl_info.supported[EXT_VERTEX_ARRAY_BGRA]
302 && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
304 stream_info->swizzle_map |= 1 << idx;
306 stream_info->use_map |= 1 << idx;
310 /* Now call PreLoad on all the vertex buffers. In the very rare case
311 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
312 * The vertex buffer can now use the strided structure in the device instead of finding its
313 * own again.
315 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
316 * once in there. */
317 for (i = 0; i < stream_count; ++i)
319 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
320 if (vb) IWineD3DBuffer_PreLoad(vb);
324 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
325 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
327 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, gl_info);
328 e->format_desc = format_desc;
329 e->stride = strided->dwStride;
330 e->data = strided->lpData;
331 e->stream_idx = 0;
332 e->buffer_object = 0;
335 void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
336 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
338 unsigned int i;
340 memset(stream_info, 0, sizeof(*stream_info));
342 if (strided->position.lpData)
343 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
344 if (strided->normal.lpData)
345 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
346 if (strided->diffuse.lpData)
347 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
348 if (strided->specular.lpData)
349 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
351 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
353 if (strided->texCoords[i].lpData)
354 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
355 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
358 stream_info->position_transformed = strided->position_transformed;
360 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
362 if (!stream_info->elements[i].format_desc) continue;
364 if (!gl_info->supported[EXT_VERTEX_ARRAY_BGRA]
365 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
367 stream_info->swizzle_map |= 1 << i;
369 stream_info->use_map |= 1 << i;
373 /**********************************************************
374 * IUnknown parts follows
375 **********************************************************/
377 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
381 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
382 if (IsEqualGUID(riid, &IID_IUnknown)
383 || IsEqualGUID(riid, &IID_IWineD3DBase)
384 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
385 IUnknown_AddRef(iface);
386 *ppobj = This;
387 return S_OK;
389 *ppobj = NULL;
390 return E_NOINTERFACE;
393 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
395 ULONG refCount = InterlockedIncrement(&This->ref);
397 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
398 return refCount;
401 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
403 ULONG refCount = InterlockedDecrement(&This->ref);
405 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
407 if (!refCount) {
408 UINT i;
410 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
411 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
412 This->multistate_funcs[i] = NULL;
415 /* TODO: Clean up all the surfaces and textures! */
416 /* NOTE: You must release the parent if the object was created via a callback
417 ** ***************************/
419 if (!list_empty(&This->resources)) {
420 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
421 dumpResources(&This->resources);
424 if(This->contexts) ERR("Context array not freed!\n");
425 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
426 This->haveHardwareCursor = FALSE;
428 IWineD3D_Release(This->wineD3D);
429 This->wineD3D = NULL;
430 HeapFree(GetProcessHeap(), 0, This);
431 TRACE("Freed device %p\n", This);
432 This = NULL;
434 return refCount;
437 /**********************************************************
438 * IWineD3DDevice implementation follows
439 **********************************************************/
440 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
442 *pParent = This->parent;
443 IUnknown_AddRef(This->parent);
444 return WINED3D_OK;
447 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
448 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
451 struct wined3d_buffer *object;
452 HRESULT hr;
454 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
456 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
457 if (!object)
459 ERR("Failed to allocate memory\n");
460 return E_OUTOFMEMORY;
463 FIXME("Ignoring access flags (pool)\n");
465 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
466 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
467 if (FAILED(hr))
469 WARN("Failed to initialize buffer, hr %#x.\n", hr);
470 HeapFree(GetProcessHeap(), 0, object);
471 return hr;
473 object->desc = *desc;
475 TRACE("Created buffer %p.\n", object);
477 *buffer = (IWineD3DBuffer *)object;
479 return WINED3D_OK;
482 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size,
483 DWORD Usage, DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
484 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
487 struct wined3d_buffer *object;
488 HRESULT hr;
489 BOOL conv;
491 if (Pool == WINED3DPOOL_SCRATCH)
493 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
494 * anyway, SCRATCH vertex buffers aren't usable anywhere
496 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
497 *ppVertexBuffer = NULL;
498 return WINED3DERR_INVALIDCALL;
501 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
502 if (!object)
504 ERR("Out of memory\n");
505 *ppVertexBuffer = NULL;
506 return WINED3DERR_OUTOFVIDEOMEMORY;
509 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
510 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
511 if (FAILED(hr))
513 WARN("Failed to initialize buffer, hr %#x.\n", hr);
514 HeapFree(GetProcessHeap(), 0, object);
515 return hr;
518 TRACE("Created buffer %p.\n", object);
519 TRACE("FVF %#x, Pool %#x.\n", FVF, Pool);
520 *ppVertexBuffer = (IWineD3DBuffer *)object;
522 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
523 * drawStridedFast (half-life 2).
525 * Basically converting the vertices in the buffer is quite expensive, and observations
526 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
527 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
529 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
530 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
531 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
532 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
533 * dx7 apps.
534 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
535 * more. In this call we can convert dx7 buffers too.
537 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
538 if (!This->adapter->gl_info.supported[ARB_VERTEX_BUFFER_OBJECT])
540 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
541 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
542 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
543 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
544 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
545 } else if(!(Usage & WINED3DUSAGE_OPTIMIZE) && conv) {
546 TRACE("Not creating a vbo because the fvf needs conversion, but VB optimization is disabled\n");
547 } else {
548 object->flags |= WINED3D_BUFFER_CREATEBO;
550 return WINED3D_OK;
553 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
554 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
555 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
558 struct wined3d_buffer *object;
559 HRESULT hr;
561 TRACE("(%p) Creating index buffer\n", This);
563 /* Allocate the storage for the device */
564 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
565 if (!object)
567 ERR("Out of memory\n");
568 *ppIndexBuffer = NULL;
569 return WINED3DERR_OUTOFVIDEOMEMORY;
572 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
573 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
574 if (FAILED(hr))
576 WARN("Failed to initialize buffer, hr %#x\n", hr);
577 HeapFree(GetProcessHeap(), 0, object);
578 return hr;
581 TRACE("Created buffer %p.\n", object);
583 if (Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC)
584 && This->adapter->gl_info.supported[ARB_VERTEX_BUFFER_OBJECT])
586 object->flags |= WINED3D_BUFFER_CREATEBO;
589 *ppIndexBuffer = (IWineD3DBuffer *) object;
591 return WINED3D_OK;
594 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
595 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
598 IWineD3DStateBlockImpl *object;
599 HRESULT hr;
601 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
602 if(!object)
604 ERR("Failed to allocate stateblock memory.\n");
605 return E_OUTOFMEMORY;
608 hr = stateblock_init(object, This, type);
609 if (FAILED(hr))
611 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
612 HeapFree(GetProcessHeap(), 0, object);
613 return hr;
616 TRACE("Created stateblock %p.\n", object);
617 *stateblock = (IWineD3DStateBlock *)object;
619 return WINED3D_OK;
622 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
623 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
624 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
625 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
628 IWineD3DSurfaceImpl *object;
629 HRESULT hr;
631 TRACE("(%p) Create surface\n",This);
633 if (Impl == SURFACE_OPENGL && !This->adapter)
635 ERR("OpenGL surfaces are not available without OpenGL.\n");
636 return WINED3DERR_NOTAVAILABLE;
639 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
640 if (!object)
642 ERR("Failed to allocate surface memory.\n");
643 *ppSurface = NULL;
644 return WINED3DERR_OUTOFVIDEOMEMORY;
647 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
648 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
649 if (FAILED(hr))
651 WARN("Failed to initialize surface, returning %#x.\n", hr);
652 HeapFree(GetProcessHeap(), 0, object);
653 *ppSurface = NULL;
654 return hr;
657 TRACE("(%p) : Created surface %p\n", This, object);
659 *ppSurface = (IWineD3DSurface *)object;
661 return hr;
664 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
665 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
667 struct wined3d_rendertarget_view *object;
669 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
670 if (!object)
672 ERR("Failed to allocate memory\n");
673 return E_OUTOFMEMORY;
676 object->vtbl = &wined3d_rendertarget_view_vtbl;
677 object->refcount = 1;
678 IWineD3DResource_AddRef(resource);
679 object->resource = resource;
680 object->parent = parent;
682 *rendertarget_view = (IWineD3DRendertargetView *)object;
684 return WINED3D_OK;
687 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
688 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
689 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
692 IWineD3DTextureImpl *object;
693 HRESULT hr;
695 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
696 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
697 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
699 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
700 if (!object)
702 ERR("Out of memory\n");
703 *ppTexture = NULL;
704 return WINED3DERR_OUTOFVIDEOMEMORY;
707 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
708 if (FAILED(hr))
710 WARN("Failed to initialize texture, returning %#x\n", hr);
711 HeapFree(GetProcessHeap(), 0, object);
712 *ppTexture = NULL;
713 return hr;
716 *ppTexture = (IWineD3DTexture *)object;
718 TRACE("(%p) : Created texture %p\n", This, object);
720 return WINED3D_OK;
723 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
724 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
725 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
728 IWineD3DVolumeTextureImpl *object;
729 HRESULT hr;
731 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
732 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
734 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
735 if (!object)
737 ERR("Out of memory\n");
738 *ppVolumeTexture = NULL;
739 return WINED3DERR_OUTOFVIDEOMEMORY;
742 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
743 if (FAILED(hr))
745 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
746 HeapFree(GetProcessHeap(), 0, object);
747 *ppVolumeTexture = NULL;
748 return hr;
751 TRACE("(%p) : Created volume texture %p.\n", This, object);
752 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
754 return WINED3D_OK;
757 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
758 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
759 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
762 IWineD3DVolumeImpl *object;
763 HRESULT hr;
765 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
766 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
768 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
769 if (!object)
771 ERR("Out of memory\n");
772 *ppVolume = NULL;
773 return WINED3DERR_OUTOFVIDEOMEMORY;
776 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
777 if (FAILED(hr))
779 WARN("Failed to initialize volume, returning %#x.\n", hr);
780 HeapFree(GetProcessHeap(), 0, object);
781 return hr;
784 TRACE("(%p) : Created volume %p.\n", This, object);
785 *ppVolume = (IWineD3DVolume *)object;
787 return WINED3D_OK;
790 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
791 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
792 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
795 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
796 HRESULT hr;
798 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
799 if (!object)
801 ERR("Out of memory\n");
802 *ppCubeTexture = NULL;
803 return WINED3DERR_OUTOFVIDEOMEMORY;
806 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
807 if (FAILED(hr))
809 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
810 HeapFree(GetProcessHeap(), 0, object);
811 *ppCubeTexture = NULL;
812 return hr;
815 TRACE("(%p) : Created Cube Texture %p\n", This, object);
816 *ppCubeTexture = (IWineD3DCubeTexture *)object;
818 return WINED3D_OK;
821 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
823 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
824 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
825 HRESULT hr = WINED3DERR_NOTAVAILABLE;
826 const IWineD3DQueryVtbl *vtable;
828 /* Just a check to see if we support this type of query */
829 switch(Type) {
830 case WINED3DQUERYTYPE_OCCLUSION:
831 TRACE("(%p) occlusion query\n", This);
832 if (gl_info->supported[ARB_OCCLUSION_QUERY])
833 hr = WINED3D_OK;
834 else
835 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
837 vtable = &IWineD3DOcclusionQuery_Vtbl;
838 break;
840 case WINED3DQUERYTYPE_EVENT:
841 if (!gl_info->supported[NV_FENCE] && !gl_info->supported[APPLE_FENCE])
843 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
844 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
846 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
848 vtable = &IWineD3DEventQuery_Vtbl;
849 hr = WINED3D_OK;
850 break;
852 case WINED3DQUERYTYPE_VCACHE:
853 case WINED3DQUERYTYPE_RESOURCEMANAGER:
854 case WINED3DQUERYTYPE_VERTEXSTATS:
855 case WINED3DQUERYTYPE_TIMESTAMP:
856 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
857 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
858 case WINED3DQUERYTYPE_PIPELINETIMINGS:
859 case WINED3DQUERYTYPE_INTERFACETIMINGS:
860 case WINED3DQUERYTYPE_VERTEXTIMINGS:
861 case WINED3DQUERYTYPE_PIXELTIMINGS:
862 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
863 case WINED3DQUERYTYPE_CACHEUTILIZATION:
864 default:
865 /* Use the base Query vtable until we have a special one for each query */
866 vtable = &IWineD3DQuery_Vtbl;
867 FIXME("(%p) Unhandled query type %d\n", This, Type);
869 if(NULL == ppQuery || hr != WINED3D_OK) {
870 return hr;
873 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
874 if(!object)
876 ERR("Out of memory\n");
877 *ppQuery = NULL;
878 return WINED3DERR_OUTOFVIDEOMEMORY;
881 object->lpVtbl = vtable;
882 object->type = Type;
883 object->state = QUERY_CREATED;
884 object->wineD3DDevice = This;
885 object->parent = parent;
886 object->ref = 1;
888 *ppQuery = (IWineD3DQuery *)object;
890 /* allocated the 'extended' data based on the type of query requested */
891 switch(Type){
892 case WINED3DQUERYTYPE_OCCLUSION:
893 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
894 ((struct wined3d_occlusion_query *)object->extendedData)->context = NULL;
895 break;
897 case WINED3DQUERYTYPE_EVENT:
898 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query));
899 ((struct wined3d_event_query *)object->extendedData)->context = NULL;
900 break;
902 case WINED3DQUERYTYPE_VCACHE:
903 case WINED3DQUERYTYPE_RESOURCEMANAGER:
904 case WINED3DQUERYTYPE_VERTEXSTATS:
905 case WINED3DQUERYTYPE_TIMESTAMP:
906 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
907 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
908 case WINED3DQUERYTYPE_PIPELINETIMINGS:
909 case WINED3DQUERYTYPE_INTERFACETIMINGS:
910 case WINED3DQUERYTYPE_VERTEXTIMINGS:
911 case WINED3DQUERYTYPE_PIXELTIMINGS:
912 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
913 case WINED3DQUERYTYPE_CACHEUTILIZATION:
914 default:
915 object->extendedData = 0;
916 FIXME("(%p) Unhandled query type %d\n",This , Type);
918 TRACE("(%p) : Created Query %p\n", This, object);
919 return WINED3D_OK;
922 /*****************************************************************************
923 * IWineD3DDeviceImpl_SetupFullscreenWindow
925 * Helper function that modifies a HWND's Style and ExStyle for proper
926 * fullscreen use.
928 * Params:
929 * iface: Pointer to the IWineD3DDevice interface
930 * window: Window to setup
932 *****************************************************************************/
933 static LONG fullscreen_style(LONG orig_style) {
934 LONG style = orig_style;
935 style &= ~WS_CAPTION;
936 style &= ~WS_THICKFRAME;
938 /* Make sure the window is managed, otherwise we won't get keyboard input */
939 style |= WS_POPUP | WS_SYSMENU;
941 return style;
944 static LONG fullscreen_exStyle(LONG orig_exStyle) {
945 LONG exStyle = orig_exStyle;
947 /* Filter out window decorations */
948 exStyle &= ~WS_EX_WINDOWEDGE;
949 exStyle &= ~WS_EX_CLIENTEDGE;
951 return exStyle;
954 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
957 LONG style, exStyle;
958 /* Don't do anything if an original style is stored.
959 * That shouldn't happen
961 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
962 if (This->style || This->exStyle) {
963 ERR("(%p): Want to change the window parameters of HWND %p, but "
964 "another style is stored for restoration afterwards\n", This, window);
967 /* Get the parameters and save them */
968 style = GetWindowLongW(window, GWL_STYLE);
969 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
970 This->style = style;
971 This->exStyle = exStyle;
973 style = fullscreen_style(style);
974 exStyle = fullscreen_exStyle(exStyle);
976 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
977 This->style, This->exStyle, style, exStyle);
979 SetWindowLongW(window, GWL_STYLE, style);
980 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
982 /* Inform the window about the update. */
983 SetWindowPos(window, HWND_TOP, 0, 0,
984 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
987 /*****************************************************************************
988 * IWineD3DDeviceImpl_RestoreWindow
990 * Helper function that restores a windows' properties when taking it out
991 * of fullscreen mode
993 * Params:
994 * iface: Pointer to the IWineD3DDevice interface
995 * window: Window to setup
997 *****************************************************************************/
998 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1000 LONG style, exStyle;
1002 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1003 * switch, do nothing
1005 if (!This->style && !This->exStyle) return;
1007 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1008 This, window, This->style, This->exStyle);
1010 style = GetWindowLongW(window, GWL_STYLE);
1011 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1013 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1014 * Some applications change it before calling Reset() when switching between windowed and
1015 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1017 if(style == fullscreen_style(This->style) &&
1018 exStyle == fullscreen_style(This->exStyle)) {
1019 SetWindowLongW(window, GWL_STYLE, This->style);
1020 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1023 /* Delete the old values */
1024 This->style = 0;
1025 This->exStyle = 0;
1027 /* Inform the window about the update */
1028 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1029 0, 0, 0, 0, /* Pos, Size, ignored */
1030 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1033 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1034 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1035 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1036 IUnknown *parent, WINED3DSURFTYPE surface_type)
1038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1040 HDC hDc;
1041 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1042 HRESULT hr;
1043 BOOL displaymode_set = FALSE;
1044 WINED3DDISPLAYMODE Mode;
1045 const struct GlPixelFormatDesc *format_desc;
1047 TRACE("(%p) : Created Additional Swap Chain\n", This);
1049 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1050 * does a device hold a reference to a swap chain giving them a lifetime of the device
1051 * or does the swap chain notify the device of its destruction.
1052 *******************************/
1054 /* Check the params */
1055 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1056 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1057 return WINED3DERR_INVALIDCALL;
1058 } else if (pPresentationParameters->BackBufferCount > 1) {
1059 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1062 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1063 if(!object)
1065 ERR("Out of memory\n");
1066 *ppSwapChain = NULL;
1067 return WINED3DERR_OUTOFVIDEOMEMORY;
1070 switch(surface_type) {
1071 case SURFACE_GDI:
1072 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1073 break;
1074 case SURFACE_OPENGL:
1075 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1076 break;
1077 case SURFACE_UNKNOWN:
1078 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1079 HeapFree(GetProcessHeap(), 0, object);
1080 return WINED3DERR_INVALIDCALL;
1082 object->wineD3DDevice = This;
1083 object->parent = parent;
1084 object->ref = 1;
1086 *ppSwapChain = (IWineD3DSwapChain *)object;
1088 /*********************
1089 * Lookup the window Handle and the relating X window handle
1090 ********************/
1092 /* Setup hwnd we are using, plus which display this equates to */
1093 object->win_handle = pPresentationParameters->hDeviceWindow;
1094 if (!object->win_handle) {
1095 object->win_handle = This->createParms.hFocusWindow;
1097 if(!pPresentationParameters->Windowed && object->win_handle) {
1098 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1099 pPresentationParameters->BackBufferWidth,
1100 pPresentationParameters->BackBufferHeight);
1103 hDc = GetDC(object->win_handle);
1104 TRACE("Using hDc %p\n", hDc);
1106 if (NULL == hDc) {
1107 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1108 return WINED3DERR_NOTAVAILABLE;
1111 /* Get info on the current display setup */
1112 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1113 object->orig_width = Mode.Width;
1114 object->orig_height = Mode.Height;
1115 object->orig_fmt = Mode.Format;
1116 format_desc = getFormatDescEntry(Mode.Format, &This->adapter->gl_info);
1118 if (pPresentationParameters->Windowed &&
1119 ((pPresentationParameters->BackBufferWidth == 0) ||
1120 (pPresentationParameters->BackBufferHeight == 0) ||
1121 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1123 RECT Rect;
1124 GetClientRect(object->win_handle, &Rect);
1126 if (pPresentationParameters->BackBufferWidth == 0) {
1127 pPresentationParameters->BackBufferWidth = Rect.right;
1128 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1130 if (pPresentationParameters->BackBufferHeight == 0) {
1131 pPresentationParameters->BackBufferHeight = Rect.bottom;
1132 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1134 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1135 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1136 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1140 /* Put the correct figures in the presentation parameters */
1141 TRACE("Copying across presentation parameters\n");
1142 object->presentParms = *pPresentationParameters;
1144 TRACE("calling rendertarget CB\n");
1145 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1146 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1147 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1148 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1149 if (SUCCEEDED(hr)) {
1150 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1151 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1152 if(surface_type == SURFACE_OPENGL) {
1153 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1155 } else {
1156 ERR("Failed to create the front buffer\n");
1157 goto error;
1160 /*********************
1161 * Windowed / Fullscreen
1162 *******************/
1165 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1166 * so we should really check to see if there is a fullscreen swapchain already
1167 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1168 **************************************/
1170 if (!pPresentationParameters->Windowed) {
1171 WINED3DDISPLAYMODE mode;
1174 /* Change the display settings */
1175 mode.Width = pPresentationParameters->BackBufferWidth;
1176 mode.Height = pPresentationParameters->BackBufferHeight;
1177 mode.Format = pPresentationParameters->BackBufferFormat;
1178 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1180 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1181 displaymode_set = TRUE;
1185 * Create an opengl context for the display visual
1186 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1187 * use different properties after that point in time. FIXME: How to handle when requested format
1188 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1189 * it chooses is identical to the one already being used!
1190 **********************************/
1191 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1193 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1194 if(!object->context) {
1195 ERR("Failed to create the context array\n");
1196 hr = E_OUTOFMEMORY;
1197 goto error;
1199 object->num_contexts = 1;
1201 if (surface_type == SURFACE_OPENGL)
1203 object->context[0] = context_create(This, (IWineD3DSurfaceImpl *)object->frontBuffer,
1204 object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1205 if (!object->context[0]) {
1206 ERR("Failed to create a new context\n");
1207 hr = WINED3DERR_NOTAVAILABLE;
1208 goto error;
1209 } else {
1210 TRACE("Context created (HWND=%p, glContext=%p)\n",
1211 object->win_handle, object->context[0]->glCtx);
1214 else
1216 object->context[0] = NULL;
1219 /*********************
1220 * Create the back, front and stencil buffers
1221 *******************/
1222 if(object->presentParms.BackBufferCount > 0) {
1223 UINT i;
1225 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1226 if(!object->backBuffer) {
1227 ERR("Out of memory\n");
1228 hr = E_OUTOFMEMORY;
1229 goto error;
1232 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1233 TRACE("calling rendertarget CB\n");
1234 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1235 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1236 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1237 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1238 if(SUCCEEDED(hr)) {
1239 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1240 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1241 } else {
1242 ERR("Cannot create new back buffer\n");
1243 goto error;
1245 if(surface_type == SURFACE_OPENGL) {
1246 ENTER_GL();
1247 glDrawBuffer(GL_BACK);
1248 checkGLcall("glDrawBuffer(GL_BACK)");
1249 LEAVE_GL();
1252 } else {
1253 object->backBuffer = NULL;
1255 /* Single buffering - draw to front buffer */
1256 if(surface_type == SURFACE_OPENGL) {
1257 ENTER_GL();
1258 glDrawBuffer(GL_FRONT);
1259 checkGLcall("glDrawBuffer(GL_FRONT)");
1260 LEAVE_GL();
1264 if (object->context[0]) context_release(object->context[0]);
1266 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1267 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1268 TRACE("Creating depth stencil buffer\n");
1269 if (This->auto_depth_stencil_buffer == NULL ) {
1270 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1271 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1272 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1273 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1274 &This->auto_depth_stencil_buffer);
1275 if (SUCCEEDED(hr)) {
1276 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1277 } else {
1278 ERR("Failed to create the auto depth stencil\n");
1279 goto error;
1284 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1286 TRACE("Created swapchain %p\n", object);
1287 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1288 return WINED3D_OK;
1290 error:
1291 if (displaymode_set) {
1292 DEVMODEW devmode;
1293 RECT clip_rc;
1295 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1296 ClipCursor(NULL);
1298 /* Change the display settings */
1299 memset(&devmode, 0, sizeof(devmode));
1300 devmode.dmSize = sizeof(devmode);
1301 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1302 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1303 devmode.dmPelsWidth = object->orig_width;
1304 devmode.dmPelsHeight = object->orig_height;
1305 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1308 if (object->backBuffer) {
1309 UINT i;
1310 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1311 if (object->backBuffer[i]) IWineD3DSurface_Release(object->backBuffer[i]);
1313 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1314 object->backBuffer = NULL;
1316 if(object->context && object->context[0])
1318 context_release(object->context[0]);
1319 context_destroy(This, object->context[0]);
1321 if (object->frontBuffer) IWineD3DSurface_Release(object->frontBuffer);
1322 HeapFree(GetProcessHeap(), 0, object);
1323 return hr;
1326 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1327 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1329 TRACE("(%p)\n", This);
1331 return This->NumberOfSwapChains;
1334 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1336 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1338 if(iSwapChain < This->NumberOfSwapChains) {
1339 *pSwapChain = This->swapchains[iSwapChain];
1340 IWineD3DSwapChain_AddRef(*pSwapChain);
1341 TRACE("(%p) returning %p\n", This, *pSwapChain);
1342 return WINED3D_OK;
1343 } else {
1344 TRACE("Swapchain out of range\n");
1345 *pSwapChain = NULL;
1346 return WINED3DERR_INVALIDCALL;
1350 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1351 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1352 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1355 IWineD3DVertexDeclarationImpl *object = NULL;
1356 HRESULT hr;
1358 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1359 iface, declaration, parent, elements, element_count);
1361 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1362 if(!object)
1364 ERR("Failed to allocate vertex declaration memory.\n");
1365 return E_OUTOFMEMORY;
1368 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1369 if (FAILED(hr))
1371 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1372 HeapFree(GetProcessHeap(), 0, object);
1373 return hr;
1376 TRACE("Created vertex declaration %p.\n", object);
1377 *declaration = (IWineD3DVertexDeclaration *)object;
1379 return WINED3D_OK;
1382 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1383 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1385 unsigned int idx, idx2;
1386 unsigned int offset;
1387 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1388 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1389 BOOL has_blend_idx = has_blend &&
1390 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1391 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1392 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1393 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1394 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1395 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1396 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1398 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1399 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1400 WINED3DVERTEXELEMENT *elements = NULL;
1402 unsigned int size;
1403 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1404 if (has_blend_idx) num_blends--;
1406 /* Compute declaration size */
1407 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1408 has_psize + has_diffuse + has_specular + num_textures;
1410 /* convert the declaration */
1411 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1412 if (!elements) return ~0U;
1414 idx = 0;
1415 if (has_pos) {
1416 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1417 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1418 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1420 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1421 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1422 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1424 else {
1425 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1426 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1428 elements[idx].usage_idx = 0;
1429 idx++;
1431 if (has_blend && (num_blends > 0)) {
1432 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1433 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1434 else {
1435 switch(num_blends) {
1436 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1437 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1438 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1439 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1440 default:
1441 ERR("Unexpected amount of blend values: %u\n", num_blends);
1444 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1445 elements[idx].usage_idx = 0;
1446 idx++;
1448 if (has_blend_idx) {
1449 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1450 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1451 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1452 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1453 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1454 else
1455 elements[idx].format = WINED3DFMT_R32_FLOAT;
1456 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1457 elements[idx].usage_idx = 0;
1458 idx++;
1460 if (has_normal) {
1461 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1462 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1463 elements[idx].usage_idx = 0;
1464 idx++;
1466 if (has_psize) {
1467 elements[idx].format = WINED3DFMT_R32_FLOAT;
1468 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1469 elements[idx].usage_idx = 0;
1470 idx++;
1472 if (has_diffuse) {
1473 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1474 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1475 elements[idx].usage_idx = 0;
1476 idx++;
1478 if (has_specular) {
1479 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1480 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1481 elements[idx].usage_idx = 1;
1482 idx++;
1484 for (idx2 = 0; idx2 < num_textures; idx2++) {
1485 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1486 switch (numcoords) {
1487 case WINED3DFVF_TEXTUREFORMAT1:
1488 elements[idx].format = WINED3DFMT_R32_FLOAT;
1489 break;
1490 case WINED3DFVF_TEXTUREFORMAT2:
1491 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1492 break;
1493 case WINED3DFVF_TEXTUREFORMAT3:
1494 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1495 break;
1496 case WINED3DFVF_TEXTUREFORMAT4:
1497 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1498 break;
1500 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1501 elements[idx].usage_idx = idx2;
1502 idx++;
1505 /* Now compute offsets, and initialize the rest of the fields */
1506 for (idx = 0, offset = 0; idx < size; ++idx)
1508 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1509 elements[idx].input_slot = 0;
1510 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1511 elements[idx].offset = offset;
1512 offset += format_desc->component_count * format_desc->component_size;
1515 *ppVertexElements = elements;
1516 return size;
1519 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1520 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1521 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1524 WINED3DVERTEXELEMENT *elements;
1525 unsigned int size;
1526 DWORD hr;
1528 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1530 size = ConvertFvfToDeclaration(This, fvf, &elements);
1531 if (size == ~0U) return E_OUTOFMEMORY;
1533 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1534 HeapFree(GetProcessHeap(), 0, elements);
1535 return hr;
1538 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1539 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1540 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1541 const struct wined3d_parent_ops *parent_ops)
1543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1544 IWineD3DVertexShaderImpl *object;
1545 HRESULT hr;
1547 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1548 if (!object)
1550 ERR("Failed to allocate shader memory.\n");
1551 return E_OUTOFMEMORY;
1554 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1555 if (FAILED(hr))
1557 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1558 HeapFree(GetProcessHeap(), 0, object);
1559 return hr;
1562 TRACE("Created vertex shader %p.\n", object);
1563 *ppVertexShader = (IWineD3DVertexShader *)object;
1565 return WINED3D_OK;
1568 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1569 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1570 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1571 const struct wined3d_parent_ops *parent_ops)
1573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1574 IWineD3DPixelShaderImpl *object;
1575 HRESULT hr;
1577 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1578 if (!object)
1580 ERR("Failed to allocate shader memory.\n");
1581 return E_OUTOFMEMORY;
1584 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1585 if (FAILED(hr))
1587 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1588 HeapFree(GetProcessHeap(), 0, object);
1589 return hr;
1592 TRACE("Created pixel shader %p.\n", object);
1593 *ppPixelShader = (IWineD3DPixelShader *)object;
1595 return WINED3D_OK;
1598 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1599 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1602 IWineD3DPaletteImpl *object;
1603 HRESULT hr;
1604 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1606 /* Create the new object */
1607 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1608 if(!object) {
1609 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1610 return E_OUTOFMEMORY;
1613 object->lpVtbl = &IWineD3DPalette_Vtbl;
1614 object->ref = 1;
1615 object->Flags = Flags;
1616 object->parent = Parent;
1617 object->wineD3DDevice = This;
1618 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1619 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1621 if(!object->hpal) {
1622 HeapFree( GetProcessHeap(), 0, object);
1623 return E_OUTOFMEMORY;
1626 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1627 if(FAILED(hr)) {
1628 IWineD3DPalette_Release((IWineD3DPalette *) object);
1629 return hr;
1632 *Palette = (IWineD3DPalette *) object;
1634 return WINED3D_OK;
1637 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1638 HBITMAP hbm;
1639 BITMAP bm;
1640 HRESULT hr;
1641 HDC dcb = NULL, dcs = NULL;
1642 WINEDDCOLORKEY colorkey;
1644 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1645 if(hbm)
1647 GetObjectA(hbm, sizeof(BITMAP), &bm);
1648 dcb = CreateCompatibleDC(NULL);
1649 if(!dcb) goto out;
1650 SelectObject(dcb, hbm);
1652 else
1654 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1655 * couldn't be loaded
1657 memset(&bm, 0, sizeof(bm));
1658 bm.bmWidth = 32;
1659 bm.bmHeight = 32;
1662 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1663 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1664 NULL, &wined3d_null_parent_ops);
1665 if(FAILED(hr)) {
1666 ERR("Wine logo requested, but failed to create surface\n");
1667 goto out;
1670 if(dcb) {
1671 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1672 if(FAILED(hr)) goto out;
1673 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1674 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1676 colorkey.dwColorSpaceLowValue = 0;
1677 colorkey.dwColorSpaceHighValue = 0;
1678 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1679 } else {
1680 /* Fill the surface with a white color to show that wined3d is there */
1681 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1684 out:
1685 if(dcb) {
1686 DeleteDC(dcb);
1688 if(hbm) {
1689 DeleteObject(hbm);
1691 return;
1694 /* Context activation is done by the caller. */
1695 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1697 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1698 unsigned int i;
1699 /* Under DirectX you can have texture stage operations even if no texture is
1700 bound, whereas opengl will only do texture operations when a valid texture is
1701 bound. We emulate this by creating dummy textures and binding them to each
1702 texture stage, but disable all stages by default. Hence if a stage is enabled
1703 then the default texture will kick in until replaced by a SetTexture call */
1704 ENTER_GL();
1706 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1708 /* The dummy texture does not have client storage backing */
1709 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1710 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1713 for (i = 0; i < gl_info->limits.textures; ++i)
1715 GLubyte white = 255;
1717 /* Make appropriate texture active */
1718 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1719 checkGLcall("glActiveTextureARB");
1721 /* Generate an opengl texture name */
1722 glGenTextures(1, &This->dummyTextureName[i]);
1723 checkGLcall("glGenTextures");
1724 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1726 /* Generate a dummy 2d texture (not using 1d because they cause many
1727 * DRI drivers fall back to sw) */
1728 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1729 checkGLcall("glBindTexture");
1731 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1732 checkGLcall("glTexImage2D");
1735 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1737 /* Reenable because if supported it is enabled by default */
1738 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1739 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1742 LEAVE_GL();
1745 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1746 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1748 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1749 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1750 IWineD3DSwapChainImpl *swapchain = NULL;
1751 struct wined3d_context *context;
1752 HRESULT hr;
1753 DWORD state;
1754 unsigned int i;
1756 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1758 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1759 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1761 /* TODO: Test if OpenGL is compiled in and loaded */
1763 TRACE("(%p) : Creating stateblock\n", This);
1764 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1765 hr = IWineD3DDevice_CreateStateBlock(iface,
1766 WINED3DSBT_INIT,
1767 (IWineD3DStateBlock **)&This->stateBlock,
1768 NULL);
1769 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1770 WARN("Failed to create stateblock\n");
1771 goto err_out;
1773 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1774 This->updateStateBlock = This->stateBlock;
1775 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1777 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1778 sizeof(IWineD3DSurface *) * gl_info->limits.buffers);
1779 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1780 sizeof(GLenum) * gl_info->limits.buffers);
1782 This->NumberOfPalettes = 1;
1783 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1784 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1785 ERR("Out of memory!\n");
1786 hr = E_OUTOFMEMORY;
1787 goto err_out;
1789 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1790 if(!This->palettes[0]) {
1791 ERR("Out of memory!\n");
1792 hr = E_OUTOFMEMORY;
1793 goto err_out;
1795 for (i = 0; i < 256; ++i) {
1796 This->palettes[0][i].peRed = 0xFF;
1797 This->palettes[0][i].peGreen = 0xFF;
1798 This->palettes[0][i].peBlue = 0xFF;
1799 This->palettes[0][i].peFlags = 0xFF;
1801 This->currentPalette = 0;
1803 /* Initialize the texture unit mapping to a 1:1 mapping */
1804 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1806 if (state < gl_info->limits.fragment_samplers)
1808 This->texUnitMap[state] = state;
1809 This->rev_tex_unit_map[state] = state;
1810 } else {
1811 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1812 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1816 /* Setup the implicit swapchain. This also initializes a context. */
1817 TRACE("Creating implicit swapchain\n");
1818 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1819 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1820 if (FAILED(hr))
1822 WARN("Failed to create implicit swapchain\n");
1823 goto err_out;
1826 This->NumberOfSwapChains = 1;
1827 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1828 if(!This->swapchains) {
1829 ERR("Out of memory!\n");
1830 goto err_out;
1832 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1834 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1835 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1836 This->render_targets[0] = swapchain->backBuffer[0];
1838 else {
1839 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1840 This->render_targets[0] = swapchain->frontBuffer;
1842 IWineD3DSurface_AddRef(This->render_targets[0]);
1844 /* Depth Stencil support */
1845 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1846 if (NULL != This->stencilBufferTarget) {
1847 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1850 hr = This->shader_backend->shader_alloc_private(iface);
1851 if(FAILED(hr)) {
1852 TRACE("Shader private data couldn't be allocated\n");
1853 goto err_out;
1855 hr = This->frag_pipe->alloc_private(iface);
1856 if(FAILED(hr)) {
1857 TRACE("Fragment pipeline private data couldn't be allocated\n");
1858 goto err_out;
1860 hr = This->blitter->alloc_private(iface);
1861 if(FAILED(hr)) {
1862 TRACE("Blitter private data couldn't be allocated\n");
1863 goto err_out;
1866 /* Set up some starting GL setup */
1868 /* Setup all the devices defaults */
1869 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1871 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1873 create_dummy_textures(This);
1875 ENTER_GL();
1877 /* Initialize the current view state */
1878 This->view_ident = 1;
1879 This->contexts[0]->last_was_rhw = 0;
1880 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1881 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1883 switch(wined3d_settings.offscreen_rendering_mode) {
1884 case ORM_FBO:
1885 case ORM_PBUFFER:
1886 This->offscreenBuffer = GL_BACK;
1887 break;
1889 case ORM_BACKBUFFER:
1891 if (context_get_current()->aux_buffers > 0)
1893 TRACE("Using auxilliary buffer for offscreen rendering\n");
1894 This->offscreenBuffer = GL_AUX0;
1895 } else {
1896 TRACE("Using back buffer for offscreen rendering\n");
1897 This->offscreenBuffer = GL_BACK;
1902 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1903 LEAVE_GL();
1905 context_release(context);
1907 /* Clear the screen */
1908 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1909 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1910 0x00, 1.0f, 0);
1912 This->d3d_initialized = TRUE;
1914 if(wined3d_settings.logo) {
1915 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1917 This->highest_dirty_ps_const = 0;
1918 This->highest_dirty_vs_const = 0;
1919 return WINED3D_OK;
1921 err_out:
1922 HeapFree(GetProcessHeap(), 0, This->render_targets);
1923 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1924 HeapFree(GetProcessHeap(), 0, This->swapchains);
1925 This->NumberOfSwapChains = 0;
1926 if(This->palettes) {
1927 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1928 HeapFree(GetProcessHeap(), 0, This->palettes);
1930 This->NumberOfPalettes = 0;
1931 if(swapchain) {
1932 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1934 if(This->stateBlock) {
1935 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1936 This->stateBlock = NULL;
1938 if (This->blit_priv) {
1939 This->blitter->free_private(iface);
1941 if (This->fragment_priv) {
1942 This->frag_pipe->free_private(iface);
1944 if (This->shader_priv) {
1945 This->shader_backend->shader_free_private(iface);
1947 return hr;
1950 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1951 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1954 IWineD3DSwapChainImpl *swapchain = NULL;
1955 HRESULT hr;
1957 /* Setup the implicit swapchain */
1958 TRACE("Creating implicit swapchain\n");
1959 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1960 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1961 if (FAILED(hr))
1963 WARN("Failed to create implicit swapchain\n");
1964 goto err_out;
1967 This->NumberOfSwapChains = 1;
1968 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1969 if(!This->swapchains) {
1970 ERR("Out of memory!\n");
1971 goto err_out;
1973 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1974 return WINED3D_OK;
1976 err_out:
1977 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1978 return hr;
1981 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1983 IWineD3DResource_UnLoad(resource);
1984 IWineD3DResource_Release(resource);
1985 return WINED3D_OK;
1988 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1989 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1992 const struct wined3d_gl_info *gl_info;
1993 struct wined3d_context *context;
1994 int sampler;
1995 UINT i;
1996 TRACE("(%p)\n", This);
1998 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2000 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2001 * it was created. Thus make sure a context is active for the glDelete* calls
2003 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
2004 gl_info = context->gl_info;
2006 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2008 /* Unload resources */
2009 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2011 TRACE("Deleting high order patches\n");
2012 for(i = 0; i < PATCHMAP_SIZE; i++) {
2013 struct list *e1, *e2;
2014 struct WineD3DRectPatch *patch;
2015 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2016 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2017 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2021 /* Delete the palette conversion shader if it is around */
2022 if(This->paletteConversionShader) {
2023 ENTER_GL();
2024 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2025 LEAVE_GL();
2026 This->paletteConversionShader = 0;
2029 /* Delete the pbuffer context if there is any */
2030 if(This->pbufferContext) context_destroy(This, This->pbufferContext);
2032 /* Delete the mouse cursor texture */
2033 if(This->cursorTexture) {
2034 ENTER_GL();
2035 glDeleteTextures(1, &This->cursorTexture);
2036 LEAVE_GL();
2037 This->cursorTexture = 0;
2040 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2041 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2043 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2044 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2047 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2048 * private data, it might contain opengl pointers
2050 if(This->depth_blt_texture) {
2051 ENTER_GL();
2052 glDeleteTextures(1, &This->depth_blt_texture);
2053 LEAVE_GL();
2054 This->depth_blt_texture = 0;
2056 if (This->depth_blt_rb) {
2057 ENTER_GL();
2058 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2059 LEAVE_GL();
2060 This->depth_blt_rb = 0;
2061 This->depth_blt_rb_w = 0;
2062 This->depth_blt_rb_h = 0;
2065 /* Release the update stateblock */
2066 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2067 if(This->updateStateBlock != This->stateBlock)
2068 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2070 This->updateStateBlock = NULL;
2072 { /* because were not doing proper internal refcounts releasing the primary state block
2073 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2074 to set this->stateBlock = NULL; first */
2075 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2076 This->stateBlock = NULL;
2078 /* Release the stateblock */
2079 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2080 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2084 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2085 This->blitter->free_private(iface);
2086 This->frag_pipe->free_private(iface);
2087 This->shader_backend->shader_free_private(iface);
2089 /* Release the buffers (with sanity checks)*/
2090 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2091 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2092 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2093 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2095 This->stencilBufferTarget = NULL;
2097 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2098 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2099 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2101 TRACE("Setting rendertarget to NULL\n");
2102 This->render_targets[0] = NULL;
2104 if (This->auto_depth_stencil_buffer) {
2105 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
2107 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2109 This->auto_depth_stencil_buffer = NULL;
2112 context_release(context);
2114 for(i=0; i < This->NumberOfSwapChains; i++) {
2115 TRACE("Releasing the implicit swapchain %d\n", i);
2116 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2117 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2121 HeapFree(GetProcessHeap(), 0, This->swapchains);
2122 This->swapchains = NULL;
2123 This->NumberOfSwapChains = 0;
2125 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2126 HeapFree(GetProcessHeap(), 0, This->palettes);
2127 This->palettes = NULL;
2128 This->NumberOfPalettes = 0;
2130 HeapFree(GetProcessHeap(), 0, This->render_targets);
2131 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2132 This->render_targets = NULL;
2133 This->draw_buffers = NULL;
2135 This->d3d_initialized = FALSE;
2136 return WINED3D_OK;
2139 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2141 unsigned int i;
2143 for(i=0; i < This->NumberOfSwapChains; i++) {
2144 TRACE("Releasing the implicit swapchain %d\n", i);
2145 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2146 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2150 HeapFree(GetProcessHeap(), 0, This->swapchains);
2151 This->swapchains = NULL;
2152 This->NumberOfSwapChains = 0;
2153 return WINED3D_OK;
2156 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2157 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2158 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2160 * There is no way to deactivate thread safety once it is enabled.
2162 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2165 /*For now just store the flag(needed in case of ddraw) */
2166 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2168 return;
2171 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2172 const WINED3DDISPLAYMODE* pMode) {
2173 DEVMODEW devmode;
2174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2175 LONG ret;
2176 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
2177 RECT clip_rc;
2179 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2181 /* Resize the screen even without a window:
2182 * The app could have unset it with SetCooperativeLevel, but not called
2183 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2184 * but we don't have any hwnd
2187 memset(&devmode, 0, sizeof(devmode));
2188 devmode.dmSize = sizeof(devmode);
2189 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2190 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2191 devmode.dmPelsWidth = pMode->Width;
2192 devmode.dmPelsHeight = pMode->Height;
2194 devmode.dmDisplayFrequency = pMode->RefreshRate;
2195 if (pMode->RefreshRate != 0) {
2196 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2199 /* Only change the mode if necessary */
2200 if( (This->ddraw_width == pMode->Width) &&
2201 (This->ddraw_height == pMode->Height) &&
2202 (This->ddraw_format == pMode->Format) &&
2203 (pMode->RefreshRate == 0) ) {
2204 return WINED3D_OK;
2207 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2208 if (ret != DISP_CHANGE_SUCCESSFUL) {
2209 if(devmode.dmDisplayFrequency != 0) {
2210 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2211 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2212 devmode.dmDisplayFrequency = 0;
2213 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2215 if(ret != DISP_CHANGE_SUCCESSFUL) {
2216 return WINED3DERR_NOTAVAILABLE;
2220 /* Store the new values */
2221 This->ddraw_width = pMode->Width;
2222 This->ddraw_height = pMode->Height;
2223 This->ddraw_format = pMode->Format;
2225 /* And finally clip mouse to our screen */
2226 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2227 ClipCursor(&clip_rc);
2229 return WINED3D_OK;
2232 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2234 *ppD3D= This->wineD3D;
2235 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2236 IWineD3D_AddRef(*ppD3D);
2237 return WINED3D_OK;
2240 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2243 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2244 (This->adapter->TextureRam/(1024*1024)),
2245 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2246 /* return simulated texture memory left */
2247 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2250 /*****
2251 * Get / Set Stream Source
2252 *****/
2253 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2254 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2257 IWineD3DBuffer *oldSrc;
2259 if (StreamNumber >= MAX_STREAMS) {
2260 WARN("Stream out of range %d\n", StreamNumber);
2261 return WINED3DERR_INVALIDCALL;
2262 } else if(OffsetInBytes & 0x3) {
2263 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2264 return WINED3DERR_INVALIDCALL;
2267 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2268 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2270 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2272 if(oldSrc == pStreamData &&
2273 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2274 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2275 TRACE("Application is setting the old values over, nothing to do\n");
2276 return WINED3D_OK;
2279 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2280 if (pStreamData) {
2281 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2282 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2285 /* Handle recording of state blocks */
2286 if (This->isRecordingState) {
2287 TRACE("Recording... not performing anything\n");
2288 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2289 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2290 return WINED3D_OK;
2293 if (pStreamData != NULL) {
2294 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2295 IWineD3DBuffer_AddRef(pStreamData);
2297 if (oldSrc != NULL) {
2298 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2299 IWineD3DBuffer_Release(oldSrc);
2302 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2304 return WINED3D_OK;
2307 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2308 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2310 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2312 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2313 This->stateBlock->streamSource[StreamNumber],
2314 This->stateBlock->streamOffset[StreamNumber],
2315 This->stateBlock->streamStride[StreamNumber]);
2317 if (StreamNumber >= MAX_STREAMS) {
2318 WARN("Stream out of range %d\n", StreamNumber);
2319 return WINED3DERR_INVALIDCALL;
2321 *pStream = This->stateBlock->streamSource[StreamNumber];
2322 *pStride = This->stateBlock->streamStride[StreamNumber];
2323 if (pOffset) {
2324 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2327 if (*pStream != NULL) {
2328 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2330 return WINED3D_OK;
2333 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2335 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2336 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2338 /* Verify input at least in d3d9 this is invalid*/
2339 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2340 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2341 return WINED3DERR_INVALIDCALL;
2343 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2344 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2345 return WINED3DERR_INVALIDCALL;
2347 if( Divider == 0 ){
2348 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2349 return WINED3DERR_INVALIDCALL;
2352 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2353 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2355 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2356 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2358 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2359 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2360 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2363 return WINED3D_OK;
2366 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2369 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2370 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2372 TRACE("(%p) : returning %d\n", This, *Divider);
2374 return WINED3D_OK;
2377 /*****
2378 * Get / Set & Multiply Transform
2379 *****/
2380 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2383 /* Most of this routine, comments included copied from ddraw tree initially: */
2384 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2386 /* Handle recording of state blocks */
2387 if (This->isRecordingState) {
2388 TRACE("Recording... not performing anything\n");
2389 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2390 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2391 return WINED3D_OK;
2395 * If the new matrix is the same as the current one,
2396 * we cut off any further processing. this seems to be a reasonable
2397 * optimization because as was noticed, some apps (warcraft3 for example)
2398 * tend towards setting the same matrix repeatedly for some reason.
2400 * From here on we assume that the new matrix is different, wherever it matters.
2402 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2403 TRACE("The app is setting the same matrix over again\n");
2404 return WINED3D_OK;
2405 } else {
2406 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2410 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2411 where ViewMat = Camera space, WorldMat = world space.
2413 In OpenGL, camera and world space is combined into GL_MODELVIEW
2414 matrix. The Projection matrix stay projection matrix.
2417 /* Capture the times we can just ignore the change for now */
2418 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2419 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2420 /* Handled by the state manager */
2423 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2424 return WINED3D_OK;
2427 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2429 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2430 *pMatrix = This->stateBlock->transforms[State];
2431 return WINED3D_OK;
2434 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2435 const WINED3DMATRIX *mat = NULL;
2436 WINED3DMATRIX temp;
2438 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2439 * below means it will be recorded in a state block change, but it
2440 * works regardless where it is recorded.
2441 * If this is found to be wrong, change to StateBlock.
2443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2444 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2446 if (State <= HIGHEST_TRANSFORMSTATE)
2448 mat = &This->updateStateBlock->transforms[State];
2449 } else {
2450 FIXME("Unhandled transform state!!\n");
2453 multiply_matrix(&temp, mat, pMatrix);
2455 /* Apply change via set transform - will reapply to eg. lights this way */
2456 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2459 /*****
2460 * Get / Set Light
2461 *****/
2462 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2463 you can reference any indexes you want as long as that number max are enabled at any
2464 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2465 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2466 but when recording, just build a chain pretty much of commands to be replayed. */
2468 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2469 float rho;
2470 struct wined3d_light_info *object = NULL;
2471 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2472 struct list *e;
2474 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2475 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2477 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2478 * the gl driver.
2480 if(!pLight) {
2481 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2482 return WINED3DERR_INVALIDCALL;
2485 switch(pLight->Type) {
2486 case WINED3DLIGHT_POINT:
2487 case WINED3DLIGHT_SPOT:
2488 case WINED3DLIGHT_PARALLELPOINT:
2489 case WINED3DLIGHT_GLSPOT:
2490 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2491 * most wanted
2493 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2495 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2496 return WINED3DERR_INVALIDCALL;
2498 break;
2500 case WINED3DLIGHT_DIRECTIONAL:
2501 /* Ignores attenuation */
2502 break;
2504 default:
2505 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2506 return WINED3DERR_INVALIDCALL;
2509 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2511 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2512 if(object->OriginalIndex == Index) break;
2513 object = NULL;
2516 if(!object) {
2517 TRACE("Adding new light\n");
2518 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2519 if(!object) {
2520 ERR("Out of memory error when allocating a light\n");
2521 return E_OUTOFMEMORY;
2523 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2524 object->glIndex = -1;
2525 object->OriginalIndex = Index;
2528 /* Initialize the object */
2529 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,
2530 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2531 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2532 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2533 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2534 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2535 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2537 /* Save away the information */
2538 object->OriginalParms = *pLight;
2540 switch (pLight->Type) {
2541 case WINED3DLIGHT_POINT:
2542 /* Position */
2543 object->lightPosn[0] = pLight->Position.x;
2544 object->lightPosn[1] = pLight->Position.y;
2545 object->lightPosn[2] = pLight->Position.z;
2546 object->lightPosn[3] = 1.0f;
2547 object->cutoff = 180.0f;
2548 /* FIXME: Range */
2549 break;
2551 case WINED3DLIGHT_DIRECTIONAL:
2552 /* Direction */
2553 object->lightPosn[0] = -pLight->Direction.x;
2554 object->lightPosn[1] = -pLight->Direction.y;
2555 object->lightPosn[2] = -pLight->Direction.z;
2556 object->lightPosn[3] = 0.0f;
2557 object->exponent = 0.0f;
2558 object->cutoff = 180.0f;
2559 break;
2561 case WINED3DLIGHT_SPOT:
2562 /* Position */
2563 object->lightPosn[0] = pLight->Position.x;
2564 object->lightPosn[1] = pLight->Position.y;
2565 object->lightPosn[2] = pLight->Position.z;
2566 object->lightPosn[3] = 1.0f;
2568 /* Direction */
2569 object->lightDirn[0] = pLight->Direction.x;
2570 object->lightDirn[1] = pLight->Direction.y;
2571 object->lightDirn[2] = pLight->Direction.z;
2572 object->lightDirn[3] = 1.0f;
2575 * opengl-ish and d3d-ish spot lights use too different models for the
2576 * light "intensity" as a function of the angle towards the main light direction,
2577 * so we only can approximate very roughly.
2578 * however spot lights are rather rarely used in games (if ever used at all).
2579 * furthermore if still used, probably nobody pays attention to such details.
2581 if (pLight->Falloff == 0) {
2582 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2583 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2584 * will always be 1.0 for both of them, and we don't have to care for the
2585 * rest of the rather complex calculation
2587 object->exponent = 0.0f;
2588 } else {
2589 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2590 if (rho < 0.0001f) rho = 0.0001f;
2591 object->exponent = -0.3f/logf(cosf(rho/2));
2593 if (object->exponent > 128.0f)
2595 object->exponent = 128.0f;
2597 object->cutoff = pLight->Phi*90/M_PI;
2599 /* FIXME: Range */
2600 break;
2602 default:
2603 FIXME("Unrecognized light type %d\n", pLight->Type);
2606 /* Update the live definitions if the light is currently assigned a glIndex */
2607 if (object->glIndex != -1 && !This->isRecordingState) {
2608 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2610 return WINED3D_OK;
2613 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2615 struct wined3d_light_info *lightInfo = NULL;
2616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2617 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2618 struct list *e;
2619 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2621 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2623 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2624 if(lightInfo->OriginalIndex == Index) break;
2625 lightInfo = NULL;
2628 if (lightInfo == NULL) {
2629 TRACE("Light information requested but light not defined\n");
2630 return WINED3DERR_INVALIDCALL;
2633 *pLight = lightInfo->OriginalParms;
2634 return WINED3D_OK;
2637 /*****
2638 * Get / Set Light Enable
2639 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2640 *****/
2641 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2643 struct wined3d_light_info *lightInfo = NULL;
2644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2645 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2646 struct list *e;
2647 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2649 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2651 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2652 if(lightInfo->OriginalIndex == Index) break;
2653 lightInfo = NULL;
2655 TRACE("Found light: %p\n", lightInfo);
2657 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2658 if (lightInfo == NULL) {
2660 TRACE("Light enabled requested but light not defined, so defining one!\n");
2661 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2663 /* Search for it again! Should be fairly quick as near head of list */
2664 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2666 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2667 if(lightInfo->OriginalIndex == Index) break;
2668 lightInfo = NULL;
2670 if (lightInfo == NULL) {
2671 FIXME("Adding default lights has failed dismally\n");
2672 return WINED3DERR_INVALIDCALL;
2676 if(!Enable) {
2677 if(lightInfo->glIndex != -1) {
2678 if(!This->isRecordingState) {
2679 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2682 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2683 lightInfo->glIndex = -1;
2684 } else {
2685 TRACE("Light already disabled, nothing to do\n");
2687 lightInfo->enabled = FALSE;
2688 } else {
2689 lightInfo->enabled = TRUE;
2690 if (lightInfo->glIndex != -1) {
2691 /* nop */
2692 TRACE("Nothing to do as light was enabled\n");
2693 } else {
2694 int i;
2695 /* Find a free gl light */
2696 for(i = 0; i < This->maxConcurrentLights; i++) {
2697 if(This->updateStateBlock->activeLights[i] == NULL) {
2698 This->updateStateBlock->activeLights[i] = lightInfo;
2699 lightInfo->glIndex = i;
2700 break;
2703 if(lightInfo->glIndex == -1) {
2704 /* Our tests show that Windows returns D3D_OK in this situation, even with
2705 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2706 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2707 * as well for those lights.
2709 * TODO: Test how this affects rendering
2711 WARN("Too many concurrently active lights\n");
2712 return WINED3D_OK;
2715 /* i == lightInfo->glIndex */
2716 if(!This->isRecordingState) {
2717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2722 return WINED3D_OK;
2725 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2727 struct wined3d_light_info *lightInfo = NULL;
2728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2729 struct list *e;
2730 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2731 TRACE("(%p) : for idx(%d)\n", This, Index);
2733 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2735 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2736 if(lightInfo->OriginalIndex == Index) break;
2737 lightInfo = NULL;
2740 if (lightInfo == NULL) {
2741 TRACE("Light enabled state requested but light not defined\n");
2742 return WINED3DERR_INVALIDCALL;
2744 /* true is 128 according to SetLightEnable */
2745 *pEnable = lightInfo->enabled ? 128 : 0;
2746 return WINED3D_OK;
2749 /*****
2750 * Get / Set Clip Planes
2751 *****/
2752 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2754 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2756 /* Validate Index */
2757 if (Index >= This->adapter->gl_info.limits.clipplanes)
2759 TRACE("Application has requested clipplane this device doesn't support\n");
2760 return WINED3DERR_INVALIDCALL;
2763 This->updateStateBlock->changed.clipplane |= 1 << Index;
2765 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2766 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2767 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2768 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2769 TRACE("Application is setting old values over, nothing to do\n");
2770 return WINED3D_OK;
2773 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2774 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2775 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2776 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2778 /* Handle recording of state blocks */
2779 if (This->isRecordingState) {
2780 TRACE("Recording... not performing anything\n");
2781 return WINED3D_OK;
2784 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2786 return WINED3D_OK;
2789 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2791 TRACE("(%p) : for idx %d\n", This, Index);
2793 /* Validate Index */
2794 if (Index >= This->adapter->gl_info.limits.clipplanes)
2796 TRACE("Application has requested clipplane this device doesn't support\n");
2797 return WINED3DERR_INVALIDCALL;
2800 pPlane[0] = This->stateBlock->clipplane[Index][0];
2801 pPlane[1] = This->stateBlock->clipplane[Index][1];
2802 pPlane[2] = This->stateBlock->clipplane[Index][2];
2803 pPlane[3] = This->stateBlock->clipplane[Index][3];
2804 return WINED3D_OK;
2807 /*****
2808 * Get / Set Clip Plane Status
2809 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2810 *****/
2811 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2813 FIXME("(%p) : stub\n", This);
2814 if (NULL == pClipStatus) {
2815 return WINED3DERR_INVALIDCALL;
2817 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2818 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2819 return WINED3D_OK;
2822 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2824 FIXME("(%p) : stub\n", This);
2825 if (NULL == pClipStatus) {
2826 return WINED3DERR_INVALIDCALL;
2828 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2829 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2830 return WINED3D_OK;
2833 /*****
2834 * Get / Set Material
2835 *****/
2836 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2839 This->updateStateBlock->changed.material = TRUE;
2840 This->updateStateBlock->material = *pMaterial;
2842 /* Handle recording of state blocks */
2843 if (This->isRecordingState) {
2844 TRACE("Recording... not performing anything\n");
2845 return WINED3D_OK;
2848 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2849 return WINED3D_OK;
2852 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2854 *pMaterial = This->updateStateBlock->material;
2855 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2856 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2857 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2858 pMaterial->Ambient.b, pMaterial->Ambient.a);
2859 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2860 pMaterial->Specular.b, pMaterial->Specular.a);
2861 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2862 pMaterial->Emissive.b, pMaterial->Emissive.a);
2863 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2865 return WINED3D_OK;
2868 /*****
2869 * Get / Set Indices
2870 *****/
2871 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2872 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2875 IWineD3DBuffer *oldIdxs;
2877 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2878 oldIdxs = This->updateStateBlock->pIndexData;
2880 This->updateStateBlock->changed.indices = TRUE;
2881 This->updateStateBlock->pIndexData = pIndexData;
2882 This->updateStateBlock->IndexFmt = fmt;
2884 /* Handle recording of state blocks */
2885 if (This->isRecordingState) {
2886 TRACE("Recording... not performing anything\n");
2887 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2888 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2889 return WINED3D_OK;
2892 if(oldIdxs != pIndexData) {
2893 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2894 if(pIndexData) {
2895 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2896 IWineD3DBuffer_AddRef(pIndexData);
2898 if(oldIdxs) {
2899 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2900 IWineD3DBuffer_Release(oldIdxs);
2904 return WINED3D_OK;
2907 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2911 *ppIndexData = This->stateBlock->pIndexData;
2913 /* up ref count on ppindexdata */
2914 if (*ppIndexData) {
2915 IWineD3DBuffer_AddRef(*ppIndexData);
2916 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2917 }else{
2918 TRACE("(%p) No index data set\n", This);
2920 TRACE("Returning %p\n", *ppIndexData);
2922 return WINED3D_OK;
2925 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2926 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2928 TRACE("(%p)->(%d)\n", This, BaseIndex);
2930 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2931 TRACE("Application is setting the old value over, nothing to do\n");
2932 return WINED3D_OK;
2935 This->updateStateBlock->baseVertexIndex = BaseIndex;
2937 if (This->isRecordingState) {
2938 TRACE("Recording... not performing anything\n");
2939 return WINED3D_OK;
2941 /* The base vertex index affects the stream sources */
2942 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2943 return WINED3D_OK;
2946 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2948 TRACE("(%p) : base_index %p\n", This, base_index);
2950 *base_index = This->stateBlock->baseVertexIndex;
2952 TRACE("Returning %u\n", *base_index);
2954 return WINED3D_OK;
2957 /*****
2958 * Get / Set Viewports
2959 *****/
2960 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2963 TRACE("(%p)\n", This);
2964 This->updateStateBlock->changed.viewport = TRUE;
2965 This->updateStateBlock->viewport = *pViewport;
2967 /* Handle recording of state blocks */
2968 if (This->isRecordingState) {
2969 TRACE("Recording... not performing anything\n");
2970 return WINED3D_OK;
2973 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2974 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2976 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2977 return WINED3D_OK;
2981 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2983 TRACE("(%p)\n", This);
2984 *pViewport = This->stateBlock->viewport;
2985 return WINED3D_OK;
2988 /*****
2989 * Get / Set Render States
2990 * TODO: Verify against dx9 definitions
2991 *****/
2992 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2995 DWORD oldValue = This->stateBlock->renderState[State];
2997 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2999 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3000 This->updateStateBlock->renderState[State] = Value;
3002 /* Handle recording of state blocks */
3003 if (This->isRecordingState) {
3004 TRACE("Recording... not performing anything\n");
3005 return WINED3D_OK;
3008 /* Compared here and not before the assignment to allow proper stateblock recording */
3009 if(Value == oldValue) {
3010 TRACE("Application is setting the old value over, nothing to do\n");
3011 } else {
3012 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3015 return WINED3D_OK;
3018 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3020 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3021 *pValue = This->stateBlock->renderState[State];
3022 return WINED3D_OK;
3025 /*****
3026 * Get / Set Sampler States
3027 * TODO: Verify against dx9 definitions
3028 *****/
3030 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3032 DWORD oldValue;
3034 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3035 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3037 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3038 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3041 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3042 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3043 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3046 * SetSampler is designed to allow for more than the standard up to 8 textures
3047 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3048 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3050 * http://developer.nvidia.com/object/General_FAQ.html#t6
3052 * There are two new settings for GForce
3053 * the sampler one:
3054 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3055 * and the texture one:
3056 * GL_MAX_TEXTURE_COORDS_ARB.
3057 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3058 ******************/
3060 oldValue = This->stateBlock->samplerState[Sampler][Type];
3061 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3062 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3064 /* Handle recording of state blocks */
3065 if (This->isRecordingState) {
3066 TRACE("Recording... not performing anything\n");
3067 return WINED3D_OK;
3070 if(oldValue == Value) {
3071 TRACE("Application is setting the old value over, nothing to do\n");
3072 return WINED3D_OK;
3075 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3077 return WINED3D_OK;
3080 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3083 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3084 This, Sampler, debug_d3dsamplerstate(Type), Type);
3086 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3087 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3090 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3091 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3092 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3094 *Value = This->stateBlock->samplerState[Sampler][Type];
3095 TRACE("(%p) : Returning %#x\n", This, *Value);
3097 return WINED3D_OK;
3100 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3103 This->updateStateBlock->changed.scissorRect = TRUE;
3104 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3105 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3106 return WINED3D_OK;
3108 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3110 if(This->isRecordingState) {
3111 TRACE("Recording... not performing anything\n");
3112 return WINED3D_OK;
3115 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3117 return WINED3D_OK;
3120 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3123 *pRect = This->updateStateBlock->scissorRect;
3124 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3125 return WINED3D_OK;
3128 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3130 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3132 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3134 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3135 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3137 This->updateStateBlock->vertexDecl = pDecl;
3138 This->updateStateBlock->changed.vertexDecl = TRUE;
3140 if (This->isRecordingState) {
3141 TRACE("Recording... not performing anything\n");
3142 return WINED3D_OK;
3143 } else if(pDecl == oldDecl) {
3144 /* Checked after the assignment to allow proper stateblock recording */
3145 TRACE("Application is setting the old declaration over, nothing to do\n");
3146 return WINED3D_OK;
3149 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3150 return WINED3D_OK;
3153 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3156 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3158 *ppDecl = This->stateBlock->vertexDecl;
3159 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3160 return WINED3D_OK;
3163 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3165 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3167 This->updateStateBlock->vertexShader = pShader;
3168 This->updateStateBlock->changed.vertexShader = TRUE;
3170 if (This->isRecordingState) {
3171 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3172 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3173 TRACE("Recording... not performing anything\n");
3174 return WINED3D_OK;
3175 } else if(oldShader == pShader) {
3176 /* Checked here to allow proper stateblock recording */
3177 TRACE("App is setting the old shader over, nothing to do\n");
3178 return WINED3D_OK;
3181 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3182 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3183 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3185 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3187 return WINED3D_OK;
3190 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3193 if (NULL == ppShader) {
3194 return WINED3DERR_INVALIDCALL;
3196 *ppShader = This->stateBlock->vertexShader;
3197 if( NULL != *ppShader)
3198 IWineD3DVertexShader_AddRef(*ppShader);
3200 TRACE("(%p) : returning %p\n", This, *ppShader);
3201 return WINED3D_OK;
3204 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3205 IWineD3DDevice *iface,
3206 UINT start,
3207 CONST BOOL *srcData,
3208 UINT count) {
3210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3211 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3213 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3214 iface, srcData, start, count);
3216 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3218 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3219 for (i = 0; i < cnt; i++)
3220 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3222 for (i = start; i < cnt + start; ++i) {
3223 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3226 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3228 return WINED3D_OK;
3231 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3232 IWineD3DDevice *iface,
3233 UINT start,
3234 BOOL *dstData,
3235 UINT count) {
3237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3238 int cnt = min(count, MAX_CONST_B - start);
3240 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3241 iface, dstData, start, count);
3243 if (dstData == NULL || cnt < 0)
3244 return WINED3DERR_INVALIDCALL;
3246 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3247 return WINED3D_OK;
3250 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3251 IWineD3DDevice *iface,
3252 UINT start,
3253 CONST int *srcData,
3254 UINT count) {
3256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3257 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3259 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3260 iface, srcData, start, count);
3262 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3264 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3265 for (i = 0; i < cnt; i++)
3266 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3267 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3269 for (i = start; i < cnt + start; ++i) {
3270 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3273 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3275 return WINED3D_OK;
3278 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3279 IWineD3DDevice *iface,
3280 UINT start,
3281 int *dstData,
3282 UINT count) {
3284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3285 int cnt = min(count, MAX_CONST_I - start);
3287 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3288 iface, dstData, start, count);
3290 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3291 return WINED3DERR_INVALIDCALL;
3293 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3294 return WINED3D_OK;
3297 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3298 IWineD3DDevice *iface,
3299 UINT start,
3300 CONST float *srcData,
3301 UINT count) {
3303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3304 UINT i;
3306 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3307 iface, srcData, start, count);
3309 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3310 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3311 return WINED3DERR_INVALIDCALL;
3313 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3314 if(TRACE_ON(d3d)) {
3315 for (i = 0; i < count; i++)
3316 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3317 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3320 if (!This->isRecordingState)
3322 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3323 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3326 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3327 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3329 return WINED3D_OK;
3332 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3333 IWineD3DDevice *iface,
3334 UINT start,
3335 float *dstData,
3336 UINT count) {
3338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3339 int cnt = min(count, This->d3d_vshader_constantF - start);
3341 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3342 iface, dstData, start, count);
3344 if (dstData == NULL || cnt < 0)
3345 return WINED3DERR_INVALIDCALL;
3347 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3348 return WINED3D_OK;
3351 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3352 DWORD i;
3353 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3355 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3359 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3361 DWORD i = This->rev_tex_unit_map[unit];
3362 DWORD j = This->texUnitMap[stage];
3364 This->texUnitMap[stage] = unit;
3365 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3367 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3370 This->rev_tex_unit_map[unit] = stage;
3371 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3373 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3377 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3378 int i;
3380 This->fixed_function_usage_map = 0;
3381 for (i = 0; i < MAX_TEXTURES; ++i) {
3382 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3383 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3384 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3385 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3386 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3387 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3388 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3389 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3391 if (color_op == WINED3DTOP_DISABLE) {
3392 /* Not used, and disable higher stages */
3393 break;
3396 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3397 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3398 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3399 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3400 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3401 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3402 This->fixed_function_usage_map |= (1 << i);
3405 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3406 This->fixed_function_usage_map |= (1 << (i + 1));
3411 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3412 unsigned int i, tex;
3413 WORD ffu_map;
3415 device_update_fixed_function_usage_map(This);
3416 ffu_map = This->fixed_function_usage_map;
3418 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3419 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3420 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3422 if (!(ffu_map & 1)) continue;
3424 if (This->texUnitMap[i] != i) {
3425 device_map_stage(This, i, i);
3426 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3427 markTextureStagesDirty(This, i);
3430 return;
3433 /* Now work out the mapping */
3434 tex = 0;
3435 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3437 if (!(ffu_map & 1)) continue;
3439 if (This->texUnitMap[i] != tex) {
3440 device_map_stage(This, i, tex);
3441 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3442 markTextureStagesDirty(This, i);
3445 ++tex;
3449 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3450 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3451 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3452 unsigned int i;
3454 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3455 if (sampler_type[i] && This->texUnitMap[i] != i)
3457 device_map_stage(This, i, i);
3458 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3459 if (i < MAX_TEXTURES) {
3460 markTextureStagesDirty(This, i);
3466 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3467 const DWORD *vshader_sampler_tokens, DWORD unit)
3469 DWORD current_mapping = This->rev_tex_unit_map[unit];
3471 /* Not currently used */
3472 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3474 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3475 /* Used by a fragment sampler */
3477 if (!pshader_sampler_tokens) {
3478 /* No pixel shader, check fixed function */
3479 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3482 /* Pixel shader, check the shader's sampler map */
3483 return !pshader_sampler_tokens[current_mapping];
3486 /* Used by a vertex sampler */
3487 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3490 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3491 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3492 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3493 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3494 int start = min(MAX_COMBINED_SAMPLERS, This->adapter->gl_info.limits.combined_samplers) - 1;
3495 int i;
3497 if (ps) {
3498 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3500 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3501 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3502 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3505 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3506 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3507 if (vshader_sampler_type[i])
3509 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3511 /* Already mapped somewhere */
3512 continue;
3515 while (start >= 0) {
3516 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3518 device_map_stage(This, vsampler_idx, start);
3519 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3521 --start;
3522 break;
3525 --start;
3531 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3532 BOOL vs = use_vs(This->stateBlock);
3533 BOOL ps = use_ps(This->stateBlock);
3535 * Rules are:
3536 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3537 * that would be really messy and require shader recompilation
3538 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3539 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3541 if (ps) {
3542 device_map_psamplers(This);
3543 } else {
3544 device_map_fixed_function_samplers(This);
3547 if (vs) {
3548 device_map_vsamplers(This, ps);
3552 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3554 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3555 This->updateStateBlock->pixelShader = pShader;
3556 This->updateStateBlock->changed.pixelShader = TRUE;
3558 /* Handle recording of state blocks */
3559 if (This->isRecordingState) {
3560 TRACE("Recording... not performing anything\n");
3563 if (This->isRecordingState) {
3564 TRACE("Recording... not performing anything\n");
3565 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3566 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3567 return WINED3D_OK;
3570 if(pShader == oldShader) {
3571 TRACE("App is setting the old pixel shader over, nothing to do\n");
3572 return WINED3D_OK;
3575 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3576 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3578 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3579 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3581 return WINED3D_OK;
3584 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3587 if (NULL == ppShader) {
3588 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3589 return WINED3DERR_INVALIDCALL;
3592 *ppShader = This->stateBlock->pixelShader;
3593 if (NULL != *ppShader) {
3594 IWineD3DPixelShader_AddRef(*ppShader);
3596 TRACE("(%p) : returning %p\n", This, *ppShader);
3597 return WINED3D_OK;
3600 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3601 IWineD3DDevice *iface,
3602 UINT start,
3603 CONST BOOL *srcData,
3604 UINT count) {
3606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3607 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3609 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3610 iface, srcData, start, count);
3612 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3614 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3615 for (i = 0; i < cnt; i++)
3616 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3618 for (i = start; i < cnt + start; ++i) {
3619 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3622 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3624 return WINED3D_OK;
3627 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3628 IWineD3DDevice *iface,
3629 UINT start,
3630 BOOL *dstData,
3631 UINT count) {
3633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3634 int cnt = min(count, MAX_CONST_B - start);
3636 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3637 iface, dstData, start, count);
3639 if (dstData == NULL || cnt < 0)
3640 return WINED3DERR_INVALIDCALL;
3642 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3643 return WINED3D_OK;
3646 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3647 IWineD3DDevice *iface,
3648 UINT start,
3649 CONST int *srcData,
3650 UINT count) {
3652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3653 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3655 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3656 iface, srcData, start, count);
3658 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3660 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3661 for (i = 0; i < cnt; i++)
3662 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3663 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3665 for (i = start; i < cnt + start; ++i) {
3666 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3669 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3671 return WINED3D_OK;
3674 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3675 IWineD3DDevice *iface,
3676 UINT start,
3677 int *dstData,
3678 UINT count) {
3680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3681 int cnt = min(count, MAX_CONST_I - start);
3683 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3684 iface, dstData, start, count);
3686 if (dstData == NULL || cnt < 0)
3687 return WINED3DERR_INVALIDCALL;
3689 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3690 return WINED3D_OK;
3693 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3694 IWineD3DDevice *iface,
3695 UINT start,
3696 CONST float *srcData,
3697 UINT count) {
3699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3700 UINT i;
3702 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3703 iface, srcData, start, count);
3705 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3706 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3707 return WINED3DERR_INVALIDCALL;
3709 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3710 if(TRACE_ON(d3d)) {
3711 for (i = 0; i < count; i++)
3712 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3713 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3716 if (!This->isRecordingState)
3718 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3719 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3722 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3723 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3725 return WINED3D_OK;
3728 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3729 IWineD3DDevice *iface,
3730 UINT start,
3731 float *dstData,
3732 UINT count) {
3734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3735 int cnt = min(count, This->d3d_pshader_constantF - start);
3737 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3738 iface, dstData, start, count);
3740 if (dstData == NULL || cnt < 0)
3741 return WINED3DERR_INVALIDCALL;
3743 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3744 return WINED3D_OK;
3747 /* Context activation is done by the caller. */
3748 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3749 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3750 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3751 DWORD DestFVF)
3753 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3754 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3755 unsigned int i;
3756 WINED3DVIEWPORT vp;
3757 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3758 BOOL doClip;
3759 DWORD numTextures;
3761 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3763 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3766 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3768 ERR("Source has no position mask\n");
3769 return WINED3DERR_INVALIDCALL;
3772 /* We might access VBOs from this code, so hold the lock */
3773 ENTER_GL();
3775 if (dest->resource.allocatedMemory == NULL) {
3776 buffer_get_sysmem(dest);
3779 /* Get a pointer into the destination vbo(create one if none exists) and
3780 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3782 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3784 dest->flags |= WINED3D_BUFFER_CREATEBO;
3785 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3788 if (dest->buffer_object)
3790 unsigned char extrabytes = 0;
3791 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3792 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3793 * this may write 4 extra bytes beyond the area that should be written
3795 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3796 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3797 if(!dest_conv_addr) {
3798 ERR("Out of memory\n");
3799 /* Continue without storing converted vertices */
3801 dest_conv = dest_conv_addr;
3804 /* Should I clip?
3805 * a) WINED3DRS_CLIPPING is enabled
3806 * b) WINED3DVOP_CLIP is passed
3808 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3809 static BOOL warned = FALSE;
3811 * The clipping code is not quite correct. Some things need
3812 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3813 * so disable clipping for now.
3814 * (The graphics in Half-Life are broken, and my processvertices
3815 * test crashes with IDirect3DDevice3)
3816 doClip = TRUE;
3818 doClip = FALSE;
3819 if(!warned) {
3820 warned = TRUE;
3821 FIXME("Clipping is broken and disabled for now\n");
3823 } else doClip = FALSE;
3824 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3826 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3827 WINED3DTS_VIEW,
3828 &view_mat);
3829 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3830 WINED3DTS_PROJECTION,
3831 &proj_mat);
3832 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3833 WINED3DTS_WORLDMATRIX(0),
3834 &world_mat);
3836 TRACE("View mat:\n");
3837 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);
3838 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);
3839 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);
3840 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);
3842 TRACE("Proj mat:\n");
3843 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);
3844 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);
3845 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);
3846 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);
3848 TRACE("World mat:\n");
3849 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);
3850 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);
3851 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);
3852 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);
3854 /* Get the viewport */
3855 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3856 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3857 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3859 multiply_matrix(&mat,&view_mat,&world_mat);
3860 multiply_matrix(&mat,&proj_mat,&mat);
3862 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3864 for (i = 0; i < dwCount; i+= 1) {
3865 unsigned int tex_index;
3867 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3868 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3869 /* The position first */
3870 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3871 const float *p = (const float *)(element->data + i * element->stride);
3872 float x, y, z, rhw;
3873 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3875 /* Multiplication with world, view and projection matrix */
3876 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);
3877 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);
3878 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);
3879 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);
3881 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3883 /* WARNING: The following things are taken from d3d7 and were not yet checked
3884 * against d3d8 or d3d9!
3887 /* Clipping conditions: From msdn
3889 * A vertex is clipped if it does not match the following requirements
3890 * -rhw < x <= rhw
3891 * -rhw < y <= rhw
3892 * 0 < z <= rhw
3893 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3895 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3896 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3900 if( !doClip ||
3901 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3902 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3903 ( rhw > eps ) ) ) {
3905 /* "Normal" viewport transformation (not clipped)
3906 * 1) The values are divided by rhw
3907 * 2) The y axis is negative, so multiply it with -1
3908 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3909 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3910 * 4) Multiply x with Width/2 and add Width/2
3911 * 5) The same for the height
3912 * 6) Add the viewpoint X and Y to the 2D coordinates and
3913 * The minimum Z value to z
3914 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3916 * Well, basically it's simply a linear transformation into viewport
3917 * coordinates
3920 x /= rhw;
3921 y /= rhw;
3922 z /= rhw;
3924 y *= -1;
3926 x *= vp.Width / 2;
3927 y *= vp.Height / 2;
3928 z *= vp.MaxZ - vp.MinZ;
3930 x += vp.Width / 2 + vp.X;
3931 y += vp.Height / 2 + vp.Y;
3932 z += vp.MinZ;
3934 rhw = 1 / rhw;
3935 } else {
3936 /* That vertex got clipped
3937 * Contrary to OpenGL it is not dropped completely, it just
3938 * undergoes a different calculation.
3940 TRACE("Vertex got clipped\n");
3941 x += rhw;
3942 y += rhw;
3944 x /= 2;
3945 y /= 2;
3947 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3948 * outside of the main vertex buffer memory. That needs some more
3949 * investigation...
3953 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3956 ( (float *) dest_ptr)[0] = x;
3957 ( (float *) dest_ptr)[1] = y;
3958 ( (float *) dest_ptr)[2] = z;
3959 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3961 dest_ptr += 3 * sizeof(float);
3963 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3964 dest_ptr += sizeof(float);
3967 if(dest_conv) {
3968 float w = 1 / rhw;
3969 ( (float *) dest_conv)[0] = x * w;
3970 ( (float *) dest_conv)[1] = y * w;
3971 ( (float *) dest_conv)[2] = z * w;
3972 ( (float *) dest_conv)[3] = w;
3974 dest_conv += 3 * sizeof(float);
3976 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3977 dest_conv += sizeof(float);
3981 if (DestFVF & WINED3DFVF_PSIZE) {
3982 dest_ptr += sizeof(DWORD);
3983 if(dest_conv) dest_conv += sizeof(DWORD);
3985 if (DestFVF & WINED3DFVF_NORMAL) {
3986 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3987 const float *normal = (const float *)(element->data + i * element->stride);
3988 /* AFAIK this should go into the lighting information */
3989 FIXME("Didn't expect the destination to have a normal\n");
3990 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3991 if(dest_conv) {
3992 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3996 if (DestFVF & WINED3DFVF_DIFFUSE) {
3997 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3998 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3999 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4001 static BOOL warned = FALSE;
4003 if(!warned) {
4004 ERR("No diffuse color in source, but destination has one\n");
4005 warned = TRUE;
4008 *( (DWORD *) dest_ptr) = 0xffffffff;
4009 dest_ptr += sizeof(DWORD);
4011 if(dest_conv) {
4012 *( (DWORD *) dest_conv) = 0xffffffff;
4013 dest_conv += sizeof(DWORD);
4016 else {
4017 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4018 if(dest_conv) {
4019 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4020 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4021 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4022 dest_conv += sizeof(DWORD);
4027 if (DestFVF & WINED3DFVF_SPECULAR)
4029 /* What's the color value in the feedback buffer? */
4030 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4031 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4032 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4034 static BOOL warned = FALSE;
4036 if(!warned) {
4037 ERR("No specular color in source, but destination has one\n");
4038 warned = TRUE;
4041 *( (DWORD *) dest_ptr) = 0xFF000000;
4042 dest_ptr += sizeof(DWORD);
4044 if(dest_conv) {
4045 *( (DWORD *) dest_conv) = 0xFF000000;
4046 dest_conv += sizeof(DWORD);
4049 else {
4050 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4051 if(dest_conv) {
4052 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4053 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4054 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4055 dest_conv += sizeof(DWORD);
4060 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4061 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4062 const float *tex_coord = (const float *)(element->data + i * element->stride);
4063 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4065 ERR("No source texture, but destination requests one\n");
4066 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4067 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4069 else {
4070 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4071 if(dest_conv) {
4072 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4078 if(dest_conv) {
4079 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4080 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4081 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4082 dwCount * get_flexible_vertex_size(DestFVF),
4083 dest_conv_addr));
4084 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4085 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4088 LEAVE_GL();
4090 return WINED3D_OK;
4092 #undef copy_and_next
4094 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4095 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4096 DWORD DestFVF)
4098 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4099 struct wined3d_stream_info stream_info;
4100 struct wined3d_context *context;
4101 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4102 HRESULT hr;
4104 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4106 if(pVertexDecl) {
4107 ERR("Output vertex declaration not implemented yet\n");
4110 /* Need any context to write to the vbo. */
4111 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4113 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4114 * control the streamIsUP flag, thus restore it afterwards.
4116 This->stateBlock->streamIsUP = FALSE;
4117 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4118 This->stateBlock->streamIsUP = streamWasUP;
4120 if(vbo || SrcStartIndex) {
4121 unsigned int i;
4122 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4123 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4125 * Also get the start index in, but only loop over all elements if there's something to add at all.
4127 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4129 struct wined3d_stream_info_element *e;
4131 if (!(stream_info.use_map & (1 << i))) continue;
4133 e = &stream_info.elements[i];
4134 if (e->buffer_object)
4136 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4137 e->buffer_object = 0;
4138 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4139 ENTER_GL();
4140 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4141 vb->buffer_object = 0;
4142 LEAVE_GL();
4144 if (e->data) e->data += e->stride * SrcStartIndex;
4148 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4149 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4151 context_release(context);
4153 return hr;
4156 /*****
4157 * Get / Set Texture Stage States
4158 * TODO: Verify against dx9 definitions
4159 *****/
4160 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4162 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4164 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4166 if (Stage >= MAX_TEXTURES) {
4167 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4168 return WINED3D_OK;
4171 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4172 This->updateStateBlock->textureState[Stage][Type] = Value;
4174 if (This->isRecordingState) {
4175 TRACE("Recording... not performing anything\n");
4176 return WINED3D_OK;
4179 /* Checked after the assignments to allow proper stateblock recording */
4180 if(oldValue == Value) {
4181 TRACE("App is setting the old value over, nothing to do\n");
4182 return WINED3D_OK;
4185 if(Stage > This->stateBlock->lowest_disabled_stage &&
4186 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4187 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4188 * Changes in other states are important on disabled stages too
4190 return WINED3D_OK;
4193 if(Type == WINED3DTSS_COLOROP) {
4194 unsigned int i;
4196 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4197 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4198 * they have to be disabled
4200 * The current stage is dirtified below.
4202 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4203 TRACE("Additionally dirtifying stage %u\n", i);
4204 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4206 This->stateBlock->lowest_disabled_stage = Stage;
4207 TRACE("New lowest disabled: %u\n", Stage);
4208 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4209 /* Previously disabled stage enabled. Stages above it may need enabling
4210 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4211 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4213 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4216 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4218 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4219 break;
4221 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4222 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4224 This->stateBlock->lowest_disabled_stage = i;
4225 TRACE("New lowest disabled: %u\n", i);
4229 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4231 return WINED3D_OK;
4234 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4236 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4237 *pValue = This->updateStateBlock->textureState[Stage][Type];
4238 return WINED3D_OK;
4241 /*****
4242 * Get / Set Texture
4243 *****/
4244 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4245 DWORD stage, IWineD3DBaseTexture *texture)
4247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4248 IWineD3DBaseTexture *prev;
4250 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4252 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4253 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4255 /* Windows accepts overflowing this array... we do not. */
4256 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4258 WARN("Ignoring invalid stage %u.\n", stage);
4259 return WINED3D_OK;
4262 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4263 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4265 WARN("Rejecting attempt to set scratch texture.\n");
4266 return WINED3DERR_INVALIDCALL;
4269 This->updateStateBlock->changed.textures |= 1 << stage;
4271 prev = This->updateStateBlock->textures[stage];
4272 TRACE("Previous texture %p.\n", prev);
4274 if (texture == prev)
4276 TRACE("App is setting the same texture again, nothing to do.\n");
4277 return WINED3D_OK;
4280 TRACE("Setting new texture to %p.\n", texture);
4281 This->updateStateBlock->textures[stage] = texture;
4283 if (This->isRecordingState)
4285 TRACE("Recording... not performing anything\n");
4287 if (texture) IWineD3DBaseTexture_AddRef(texture);
4288 if (prev) IWineD3DBaseTexture_Release(prev);
4290 return WINED3D_OK;
4293 if (texture)
4295 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4296 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4297 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4299 IWineD3DBaseTexture_AddRef(texture);
4301 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4303 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4306 if (!prev && stage < MAX_TEXTURES)
4308 /* The source arguments for color and alpha ops have different
4309 * meanings when a NULL texture is bound, so the COLOROP and
4310 * ALPHAOP have to be dirtified. */
4311 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4312 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4315 if (bind_count == 1) t->baseTexture.sampler = stage;
4318 if (prev)
4320 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4321 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4323 IWineD3DBaseTexture_Release(prev);
4325 if (!texture && stage < MAX_TEXTURES)
4327 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4328 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4331 if (bind_count && t->baseTexture.sampler == stage)
4333 unsigned int i;
4335 /* Search for other stages the texture is bound to. Shouldn't
4336 * happen if applications bind textures to a single stage only. */
4337 TRACE("Searching for other stages the texture is bound to.\n");
4338 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4340 if (This->updateStateBlock->textures[i] == prev)
4342 TRACE("Texture is also bound to stage %u.\n", i);
4343 t->baseTexture.sampler = i;
4344 break;
4350 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4352 return WINED3D_OK;
4355 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4358 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4360 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4361 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4364 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4365 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4366 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4369 *ppTexture=This->stateBlock->textures[Stage];
4370 if (*ppTexture)
4371 IWineD3DBaseTexture_AddRef(*ppTexture);
4373 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4375 return WINED3D_OK;
4378 /*****
4379 * Get Back Buffer
4380 *****/
4381 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4382 IWineD3DSurface **ppBackBuffer) {
4383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4384 IWineD3DSwapChain *swapChain;
4385 HRESULT hr;
4387 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4389 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4390 if (hr == WINED3D_OK) {
4391 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4392 IWineD3DSwapChain_Release(swapChain);
4393 } else {
4394 *ppBackBuffer = NULL;
4396 return hr;
4399 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4401 WARN("(%p) : stub, calling idirect3d for now\n", This);
4402 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4405 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4407 IWineD3DSwapChain *swapChain;
4408 HRESULT hr;
4410 if(iSwapChain > 0) {
4411 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4412 if (hr == WINED3D_OK) {
4413 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4414 IWineD3DSwapChain_Release(swapChain);
4415 } else {
4416 FIXME("(%p) Error getting display mode\n", This);
4418 } else {
4419 /* Don't read the real display mode,
4420 but return the stored mode instead. X11 can't change the color
4421 depth, and some apps are pretty angry if they SetDisplayMode from
4422 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4424 Also don't relay to the swapchain because with ddraw it's possible
4425 that there isn't a swapchain at all */
4426 pMode->Width = This->ddraw_width;
4427 pMode->Height = This->ddraw_height;
4428 pMode->Format = This->ddraw_format;
4429 pMode->RefreshRate = 0;
4430 hr = WINED3D_OK;
4433 return hr;
4436 /*****
4437 * Stateblock related functions
4438 *****/
4440 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4442 IWineD3DStateBlock *stateblock;
4443 HRESULT hr;
4445 TRACE("(%p)\n", This);
4447 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4449 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4450 if (FAILED(hr)) return hr;
4452 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4453 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4454 This->isRecordingState = TRUE;
4456 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4458 return WINED3D_OK;
4461 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4463 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4465 if (!This->isRecordingState) {
4466 WARN("(%p) not recording! returning error\n", This);
4467 *ppStateBlock = NULL;
4468 return WINED3DERR_INVALIDCALL;
4471 stateblock_init_contained_states(object);
4473 *ppStateBlock = (IWineD3DStateBlock*) object;
4474 This->isRecordingState = FALSE;
4475 This->updateStateBlock = This->stateBlock;
4476 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4477 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4478 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4479 return WINED3D_OK;
4482 /*****
4483 * Scene related functions
4484 *****/
4485 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4486 /* At the moment we have no need for any functionality at the beginning
4487 of a scene */
4488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4489 TRACE("(%p)\n", This);
4491 if(This->inScene) {
4492 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4493 return WINED3DERR_INVALIDCALL;
4495 This->inScene = TRUE;
4496 return WINED3D_OK;
4499 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4502 struct wined3d_context *context;
4504 TRACE("(%p)\n", This);
4506 if(!This->inScene) {
4507 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4508 return WINED3DERR_INVALIDCALL;
4511 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4512 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4513 wglFlush();
4514 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4515 * fails. */
4516 context_release(context);
4518 This->inScene = FALSE;
4519 return WINED3D_OK;
4522 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4523 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4524 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4525 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4526 IWineD3DSwapChain *swapChain = NULL;
4527 int i;
4528 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4530 TRACE("(%p) Presenting the frame\n", This);
4532 for(i = 0 ; i < swapchains ; i ++) {
4534 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4535 TRACE("presentinng chain %d, %p\n", i, swapChain);
4536 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4537 IWineD3DSwapChain_Release(swapChain);
4540 return WINED3D_OK;
4543 /* Not called from the VTable (internal subroutine) */
4544 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4545 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4546 float Z, DWORD Stencil) {
4547 GLbitfield glMask = 0;
4548 unsigned int i;
4549 WINED3DRECT curRect;
4550 RECT vp_rect;
4551 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4552 UINT drawable_width, drawable_height;
4553 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4554 IWineD3DSwapChainImpl *swapchain = NULL;
4555 struct wined3d_context *context;
4557 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4558 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4559 * for the cleared parts, and the untouched parts.
4561 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4562 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4563 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4564 * checking all this if the dest surface is in the drawable anyway.
4566 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4567 while(1) {
4568 if(vp->X != 0 || vp->Y != 0 ||
4569 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4570 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4571 break;
4573 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4574 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4575 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4576 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4577 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4578 break;
4580 if(Count > 0 && pRects && (
4581 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4582 pRects[0].x2 < target->currentDesc.Width ||
4583 pRects[0].y2 < target->currentDesc.Height)) {
4584 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4585 break;
4587 break;
4591 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4593 target->get_drawable_size(context, &drawable_width, &drawable_height);
4595 ENTER_GL();
4597 /* Only set the values up once, as they are not changing */
4598 if (Flags & WINED3DCLEAR_STENCIL) {
4599 glClearStencil(Stencil);
4600 checkGLcall("glClearStencil");
4601 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4602 glStencilMask(0xFFFFFFFF);
4605 if (Flags & WINED3DCLEAR_ZBUFFER) {
4606 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4607 glDepthMask(GL_TRUE);
4608 glClearDepth(Z);
4609 checkGLcall("glClearDepth");
4610 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4611 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4613 if (vp->X != 0 || vp->Y != 0 ||
4614 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4615 surface_load_ds_location(This->stencilBufferTarget, context, location);
4617 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4618 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4619 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4620 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4621 surface_load_ds_location(This->stencilBufferTarget, context, location);
4623 else if (Count > 0 && pRects && (
4624 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4625 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4626 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4627 surface_load_ds_location(This->stencilBufferTarget, context, location);
4631 if (Flags & WINED3DCLEAR_TARGET) {
4632 TRACE("Clearing screen with glClear to color %x\n", Color);
4633 glClearColor(D3DCOLOR_R(Color),
4634 D3DCOLOR_G(Color),
4635 D3DCOLOR_B(Color),
4636 D3DCOLOR_A(Color));
4637 checkGLcall("glClearColor");
4639 /* Clear ALL colors! */
4640 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4641 glMask = glMask | GL_COLOR_BUFFER_BIT;
4644 vp_rect.left = vp->X;
4645 vp_rect.top = vp->Y;
4646 vp_rect.right = vp->X + vp->Width;
4647 vp_rect.bottom = vp->Y + vp->Height;
4648 if (!(Count > 0 && pRects)) {
4649 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4650 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4652 if (context->render_offscreen)
4654 glScissor(vp_rect.left, vp_rect.top,
4655 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4656 } else {
4657 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4658 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4660 checkGLcall("glScissor");
4661 glClear(glMask);
4662 checkGLcall("glClear");
4663 } else {
4664 /* Now process each rect in turn */
4665 for (i = 0; i < Count; i++) {
4666 /* Note gl uses lower left, width/height */
4667 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4668 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4669 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4671 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4672 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4673 curRect.x1, (target->currentDesc.Height - curRect.y2),
4674 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4676 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4677 * The rectangle is not cleared, no error is returned, but further rectanlges are
4678 * still cleared if they are valid
4680 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4681 TRACE("Rectangle with negative dimensions, ignoring\n");
4682 continue;
4685 if (context->render_offscreen)
4687 glScissor(curRect.x1, curRect.y1,
4688 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4689 } else {
4690 glScissor(curRect.x1, drawable_height - curRect.y2,
4691 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4693 checkGLcall("glScissor");
4695 glClear(glMask);
4696 checkGLcall("glClear");
4700 /* Restore the old values (why..?) */
4701 if (Flags & WINED3DCLEAR_STENCIL) {
4702 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4704 if (Flags & WINED3DCLEAR_TARGET) {
4705 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4706 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4707 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4708 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4709 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4711 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4712 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4714 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4716 if (Flags & WINED3DCLEAR_ZBUFFER) {
4717 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4718 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4719 surface_modify_ds_location(This->stencilBufferTarget, location);
4722 LEAVE_GL();
4724 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
4725 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
4726 wglFlush();
4728 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
4731 context_release(context);
4733 return WINED3D_OK;
4736 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4737 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4739 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4741 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4742 Count, pRects, Flags, Color, Z, Stencil);
4744 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4745 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4746 /* TODO: What about depth stencil buffers without stencil bits? */
4747 return WINED3DERR_INVALIDCALL;
4750 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4753 /*****
4754 * Drawing functions
4755 *****/
4757 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4758 WINED3DPRIMITIVETYPE primitive_type)
4760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4762 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4764 This->updateStateBlock->changed.primitive_type = TRUE;
4765 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4768 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4769 WINED3DPRIMITIVETYPE *primitive_type)
4771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4773 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4775 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4777 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4780 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4784 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4786 if(!This->stateBlock->vertexDecl) {
4787 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4788 return WINED3DERR_INVALIDCALL;
4791 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4792 if(This->stateBlock->streamIsUP) {
4793 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4794 This->stateBlock->streamIsUP = FALSE;
4797 if(This->stateBlock->loadBaseVertexIndex != 0) {
4798 This->stateBlock->loadBaseVertexIndex = 0;
4799 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4801 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4802 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4803 return WINED3D_OK;
4806 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4809 UINT idxStride = 2;
4810 IWineD3DBuffer *pIB;
4811 GLuint vbo;
4813 pIB = This->stateBlock->pIndexData;
4814 if (!pIB) {
4815 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4816 * without an index buffer set. (The first time at least...)
4817 * D3D8 simply dies, but I doubt it can do much harm to return
4818 * D3DERR_INVALIDCALL there as well. */
4819 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4820 return WINED3DERR_INVALIDCALL;
4823 if(!This->stateBlock->vertexDecl) {
4824 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4825 return WINED3DERR_INVALIDCALL;
4828 if(This->stateBlock->streamIsUP) {
4829 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4830 This->stateBlock->streamIsUP = FALSE;
4832 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4834 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4836 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4837 idxStride = 2;
4838 } else {
4839 idxStride = 4;
4842 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4843 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4844 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4847 drawPrimitive(iface, index_count, startIndex, idxStride,
4848 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4850 return WINED3D_OK;
4853 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4854 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4857 IWineD3DBuffer *vb;
4859 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4860 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4862 if(!This->stateBlock->vertexDecl) {
4863 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4864 return WINED3DERR_INVALIDCALL;
4867 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4868 vb = This->stateBlock->streamSource[0];
4869 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4870 if (vb) IWineD3DBuffer_Release(vb);
4871 This->stateBlock->streamOffset[0] = 0;
4872 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4873 This->stateBlock->streamIsUP = TRUE;
4874 This->stateBlock->loadBaseVertexIndex = 0;
4876 /* TODO: Only mark dirty if drawing from a different UP address */
4877 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4879 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4881 /* MSDN specifies stream zero settings must be set to NULL */
4882 This->stateBlock->streamStride[0] = 0;
4883 This->stateBlock->streamSource[0] = NULL;
4885 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4886 * the new stream sources or use UP drawing again
4888 return WINED3D_OK;
4891 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4892 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4893 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4895 int idxStride;
4896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4897 IWineD3DBuffer *vb;
4898 IWineD3DBuffer *ib;
4900 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4901 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4903 if(!This->stateBlock->vertexDecl) {
4904 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4905 return WINED3DERR_INVALIDCALL;
4908 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4909 idxStride = 2;
4910 } else {
4911 idxStride = 4;
4914 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4915 vb = This->stateBlock->streamSource[0];
4916 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4917 if (vb) IWineD3DBuffer_Release(vb);
4918 This->stateBlock->streamIsUP = TRUE;
4919 This->stateBlock->streamOffset[0] = 0;
4920 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4922 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4923 This->stateBlock->baseVertexIndex = 0;
4924 This->stateBlock->loadBaseVertexIndex = 0;
4925 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4926 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4927 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4929 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4931 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4932 This->stateBlock->streamSource[0] = NULL;
4933 This->stateBlock->streamStride[0] = 0;
4934 ib = This->stateBlock->pIndexData;
4935 if(ib) {
4936 IWineD3DBuffer_Release(ib);
4937 This->stateBlock->pIndexData = NULL;
4939 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4940 * SetStreamSource to specify a vertex buffer
4943 return WINED3D_OK;
4946 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4947 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4951 /* Mark the state dirty until we have nicer tracking
4952 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4953 * that value.
4955 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4956 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4957 This->stateBlock->baseVertexIndex = 0;
4958 This->up_strided = DrawPrimStrideData;
4959 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4960 This->up_strided = NULL;
4961 return WINED3D_OK;
4964 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4965 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4966 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4969 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4971 /* Mark the state dirty until we have nicer tracking
4972 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4973 * that value.
4975 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4976 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4977 This->stateBlock->streamIsUP = TRUE;
4978 This->stateBlock->baseVertexIndex = 0;
4979 This->up_strided = DrawPrimStrideData;
4980 drawPrimitive(iface, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData);
4981 This->up_strided = NULL;
4982 return WINED3D_OK;
4985 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
4986 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
4987 * not callable by the app directly no parameter validation checks are needed here.
4989 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4990 WINED3DLOCKED_BOX src;
4991 WINED3DLOCKED_BOX dst;
4992 HRESULT hr;
4993 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
4995 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4996 * dirtification to improve loading performance.
4998 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4999 if(FAILED(hr)) return hr;
5000 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5001 if(FAILED(hr)) {
5002 IWineD3DVolume_UnlockBox(pSourceVolume);
5003 return hr;
5006 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5008 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5009 if(FAILED(hr)) {
5010 IWineD3DVolume_UnlockBox(pSourceVolume);
5011 } else {
5012 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5014 return hr;
5017 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
5018 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
5020 unsigned int level_count, i;
5021 WINED3DRESOURCETYPE type;
5022 HRESULT hr;
5024 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
5026 /* Verify that the source and destination textures are non-NULL. */
5027 if (!src_texture || !dst_texture)
5029 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5030 return WINED3DERR_INVALIDCALL;
5033 if (src_texture == dst_texture)
5035 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5036 return WINED3DERR_INVALIDCALL;
5039 /* Verify that the source and destination textures are the same type. */
5040 type = IWineD3DBaseTexture_GetType(src_texture);
5041 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
5043 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5044 return WINED3DERR_INVALIDCALL;
5047 /* Check that both textures have the identical numbers of levels. */
5048 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
5049 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
5051 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5052 return WINED3DERR_INVALIDCALL;
5055 /* Make sure that the destination texture is loaded. */
5056 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
5058 /* Update every surface level of the texture. */
5059 switch (type)
5061 case WINED3DRTYPE_TEXTURE:
5063 IWineD3DSurface *src_surface;
5064 IWineD3DSurface *dst_surface;
5066 for (i = 0; i < level_count; ++i)
5068 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
5069 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
5070 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5071 IWineD3DSurface_Release(dst_surface);
5072 IWineD3DSurface_Release(src_surface);
5073 if (FAILED(hr))
5075 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5076 return hr;
5079 break;
5082 case WINED3DRTYPE_CUBETEXTURE:
5084 IWineD3DSurface *src_surface;
5085 IWineD3DSurface *dst_surface;
5086 WINED3DCUBEMAP_FACES face;
5088 for (i = 0; i < level_count; ++i)
5090 /* Update each cube face. */
5091 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
5093 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
5094 face, i, &src_surface);
5095 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5096 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
5097 face, i, &dst_surface);
5098 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5099 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5100 IWineD3DSurface_Release(dst_surface);
5101 IWineD3DSurface_Release(src_surface);
5102 if (FAILED(hr))
5104 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5105 return hr;
5109 break;
5112 case WINED3DRTYPE_VOLUMETEXTURE:
5114 IWineD3DVolume *src_volume;
5115 IWineD3DVolume *dst_volume;
5117 for (i = 0; i < level_count; ++i)
5119 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5120 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5121 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5122 IWineD3DVolume_Release(dst_volume);
5123 IWineD3DVolume_Release(src_volume);
5124 if (FAILED(hr))
5126 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5127 return hr;
5130 break;
5133 default:
5134 FIXME("Unsupported texture type %#x.\n", type);
5135 return WINED3DERR_INVALIDCALL;
5138 return WINED3D_OK;
5141 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5142 IWineD3DSwapChain *swapChain;
5143 HRESULT hr;
5144 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5145 if(hr == WINED3D_OK) {
5146 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5147 IWineD3DSwapChain_Release(swapChain);
5149 return hr;
5152 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5154 IWineD3DBaseTextureImpl *texture;
5155 DWORD i;
5157 TRACE("(%p) : %p\n", This, pNumPasses);
5159 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5160 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5161 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5162 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5164 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5165 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5166 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5169 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5170 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5172 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5173 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5174 return E_FAIL;
5176 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5177 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5178 return E_FAIL;
5180 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5181 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5182 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5183 return E_FAIL;
5187 /* return a sensible default */
5188 *pNumPasses = 1;
5190 TRACE("returning D3D_OK\n");
5191 return WINED3D_OK;
5194 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5196 int i;
5198 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5200 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5201 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
5202 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
5204 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5209 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5211 int j;
5212 UINT NewSize;
5213 PALETTEENTRY **palettes;
5215 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5217 if (PaletteNumber >= MAX_PALETTES) {
5218 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5219 return WINED3DERR_INVALIDCALL;
5222 if (PaletteNumber >= This->NumberOfPalettes) {
5223 NewSize = This->NumberOfPalettes;
5224 do {
5225 NewSize *= 2;
5226 } while(PaletteNumber >= NewSize);
5227 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5228 if (!palettes) {
5229 ERR("Out of memory!\n");
5230 return E_OUTOFMEMORY;
5232 This->palettes = palettes;
5233 This->NumberOfPalettes = NewSize;
5236 if (!This->palettes[PaletteNumber]) {
5237 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5238 if (!This->palettes[PaletteNumber]) {
5239 ERR("Out of memory!\n");
5240 return E_OUTOFMEMORY;
5244 for (j = 0; j < 256; ++j) {
5245 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5246 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5247 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5248 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5250 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5251 TRACE("(%p) : returning\n", This);
5252 return WINED3D_OK;
5255 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5257 int j;
5258 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5259 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5260 /* What happens in such situation isn't documented; Native seems to silently abort
5261 on such conditions. Return Invalid Call. */
5262 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5263 return WINED3DERR_INVALIDCALL;
5265 for (j = 0; j < 256; ++j) {
5266 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5267 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5268 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5269 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5271 TRACE("(%p) : returning\n", This);
5272 return WINED3D_OK;
5275 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5277 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5278 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5279 (tested with reference rasterizer). Return Invalid Call. */
5280 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5281 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5282 return WINED3DERR_INVALIDCALL;
5284 /*TODO: stateblocks */
5285 if (This->currentPalette != PaletteNumber) {
5286 This->currentPalette = PaletteNumber;
5287 dirtify_p8_texture_samplers(This);
5289 TRACE("(%p) : returning\n", This);
5290 return WINED3D_OK;
5293 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5295 if (PaletteNumber == NULL) {
5296 WARN("(%p) : returning Invalid Call\n", This);
5297 return WINED3DERR_INVALIDCALL;
5299 /*TODO: stateblocks */
5300 *PaletteNumber = This->currentPalette;
5301 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5302 return WINED3D_OK;
5305 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5307 static BOOL warned;
5308 if (!warned)
5310 FIXME("(%p) : stub\n", This);
5311 warned = TRUE;
5314 This->softwareVertexProcessing = bSoftware;
5315 return WINED3D_OK;
5319 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5321 static BOOL warned;
5322 if (!warned)
5324 FIXME("(%p) : stub\n", This);
5325 warned = TRUE;
5327 return This->softwareVertexProcessing;
5331 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5333 IWineD3DSwapChain *swapChain;
5334 HRESULT hr;
5336 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5338 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5339 if(hr == WINED3D_OK){
5340 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5341 IWineD3DSwapChain_Release(swapChain);
5342 }else{
5343 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5345 return hr;
5349 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5351 static BOOL warned;
5352 if(nSegments != 0.0f) {
5353 if (!warned)
5355 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5356 warned = TRUE;
5359 return WINED3D_OK;
5362 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5364 static BOOL warned;
5365 if (!warned)
5367 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5368 warned = TRUE;
5370 return 0.0f;
5373 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5375 /** TODO: remove casts to IWineD3DSurfaceImpl
5376 * NOTE: move code to surface to accomplish this
5377 ****************************************/
5378 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5379 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5380 int srcWidth, srcHeight;
5381 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5382 WINED3DFORMAT destFormat, srcFormat;
5383 UINT destSize;
5384 int srcLeft, destLeft, destTop;
5385 WINED3DPOOL srcPool, destPool;
5386 int offset = 0;
5387 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5388 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5389 GLenum dummy;
5390 DWORD sampler;
5391 int bpp;
5392 CONVERT_TYPES convert = NO_CONVERSION;
5393 struct wined3d_context *context;
5395 WINED3DSURFACE_DESC winedesc;
5397 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5399 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5400 srcSurfaceWidth = winedesc.width;
5401 srcSurfaceHeight = winedesc.height;
5402 srcPool = winedesc.pool;
5403 srcFormat = winedesc.format;
5405 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5406 destSurfaceWidth = winedesc.width;
5407 destSurfaceHeight = winedesc.height;
5408 destPool = winedesc.pool;
5409 destFormat = winedesc.format;
5410 destSize = winedesc.size;
5412 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5413 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5414 return WINED3DERR_INVALIDCALL;
5417 /* This call loads the opengl surface directly, instead of copying the surface to the
5418 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5419 * copy in sysmem and use regular surface loading.
5421 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5422 if(convert != NO_CONVERSION) {
5423 return IWineD3DSurface_BltFast(pDestinationSurface,
5424 pDestPoint ? pDestPoint->x : 0,
5425 pDestPoint ? pDestPoint->y : 0,
5426 pSourceSurface, pSourceRect, 0);
5429 if (destFormat == WINED3DFMT_UNKNOWN) {
5430 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5431 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5433 /* Get the update surface description */
5434 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5437 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5439 ENTER_GL();
5440 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5441 checkGLcall("glActiveTextureARB");
5442 LEAVE_GL();
5444 /* Make sure the surface is loaded and up to date */
5445 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5446 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5448 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5449 dst_format_desc = dst_impl->resource.format_desc;
5451 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5452 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5453 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5454 srcLeft = pSourceRect ? pSourceRect->left : 0;
5455 destLeft = pDestPoint ? pDestPoint->x : 0;
5456 destTop = pDestPoint ? pDestPoint->y : 0;
5459 /* This function doesn't support compressed textures
5460 the pitch is just bytesPerPixel * width */
5461 if(srcWidth != srcSurfaceWidth || srcLeft ){
5462 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5463 offset += srcLeft * src_format_desc->byte_count;
5464 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5466 /* TODO DXT formats */
5468 if(pSourceRect != NULL && pSourceRect->top != 0){
5469 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5471 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5472 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5473 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5475 /* Sanity check */
5476 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5478 /* need to lock the surface to get the data */
5479 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5482 ENTER_GL();
5484 /* TODO: Cube and volume support */
5485 if(rowoffset != 0){
5486 /* not a whole row so we have to do it a line at a time */
5487 int j;
5489 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5490 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5492 for (j = destTop; j < (srcHeight + destTop); ++j)
5494 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5495 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5496 data += rowoffset;
5499 } else { /* Full width, so just write out the whole texture */
5500 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5502 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5504 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5506 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5507 FIXME("Updating part of a compressed texture is not supported.\n");
5509 if (destFormat != srcFormat)
5511 FIXME("Updating mixed format compressed textures is not supported.\n");
5513 else
5515 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5516 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5519 else
5521 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5522 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5525 checkGLcall("glTexSubImage2D");
5527 LEAVE_GL();
5528 context_release(context);
5530 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5531 sampler = This->rev_tex_unit_map[0];
5532 if (sampler != WINED3D_UNMAPPED_STAGE)
5534 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5537 return WINED3D_OK;
5540 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5542 struct WineD3DRectPatch *patch;
5543 GLenum old_primitive_type;
5544 unsigned int i;
5545 struct list *e;
5546 BOOL found;
5547 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5549 if(!(Handle || pRectPatchInfo)) {
5550 /* TODO: Write a test for the return value, thus the FIXME */
5551 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5552 return WINED3DERR_INVALIDCALL;
5555 if(Handle) {
5556 i = PATCHMAP_HASHFUNC(Handle);
5557 found = FALSE;
5558 LIST_FOR_EACH(e, &This->patches[i]) {
5559 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5560 if(patch->Handle == Handle) {
5561 found = TRUE;
5562 break;
5566 if(!found) {
5567 TRACE("Patch does not exist. Creating a new one\n");
5568 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5569 patch->Handle = Handle;
5570 list_add_head(&This->patches[i], &patch->entry);
5571 } else {
5572 TRACE("Found existing patch %p\n", patch);
5574 } else {
5575 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5576 * attributes we have to tesselate, read back, and draw. This needs a patch
5577 * management structure instance. Create one.
5579 * A possible improvement is to check if a vertex shader is used, and if not directly
5580 * draw the patch.
5582 FIXME("Drawing an uncached patch. This is slow\n");
5583 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5586 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5587 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5588 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5589 HRESULT hr;
5590 TRACE("Tesselation density or patch info changed, retesselating\n");
5592 if(pRectPatchInfo) {
5593 patch->RectPatchInfo = *pRectPatchInfo;
5595 patch->numSegs[0] = pNumSegs[0];
5596 patch->numSegs[1] = pNumSegs[1];
5597 patch->numSegs[2] = pNumSegs[2];
5598 patch->numSegs[3] = pNumSegs[3];
5600 hr = tesselate_rectpatch(This, patch);
5601 if(FAILED(hr)) {
5602 WARN("Patch tesselation failed\n");
5604 /* Do not release the handle to store the params of the patch */
5605 if(!Handle) {
5606 HeapFree(GetProcessHeap(), 0, patch);
5608 return hr;
5612 This->currentPatch = patch;
5613 old_primitive_type = This->stateBlock->gl_primitive_type;
5614 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5615 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5616 This->stateBlock->gl_primitive_type = old_primitive_type;
5617 This->currentPatch = NULL;
5619 /* Destroy uncached patches */
5620 if(!Handle) {
5621 HeapFree(GetProcessHeap(), 0, patch->mem);
5622 HeapFree(GetProcessHeap(), 0, patch);
5624 return WINED3D_OK;
5627 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5629 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5630 FIXME("(%p) : Stub\n", This);
5631 return WINED3D_OK;
5634 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5636 int i;
5637 struct WineD3DRectPatch *patch;
5638 struct list *e;
5639 TRACE("(%p) Handle(%d)\n", This, Handle);
5641 i = PATCHMAP_HASHFUNC(Handle);
5642 LIST_FOR_EACH(e, &This->patches[i]) {
5643 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5644 if(patch->Handle == Handle) {
5645 TRACE("Deleting patch %p\n", patch);
5646 list_remove(&patch->entry);
5647 HeapFree(GetProcessHeap(), 0, patch->mem);
5648 HeapFree(GetProcessHeap(), 0, patch);
5649 return WINED3D_OK;
5653 /* TODO: Write a test for the return value */
5654 FIXME("Attempt to destroy nonexistent patch\n");
5655 return WINED3DERR_INVALIDCALL;
5658 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5659 HRESULT hr;
5660 IWineD3DSwapChain *swapchain;
5662 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5663 if (SUCCEEDED(hr)) {
5664 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5665 return swapchain;
5668 return NULL;
5671 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5672 const WINED3DRECT *rect, const float color[4])
5674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5675 struct wined3d_context *context;
5676 IWineD3DSwapChain *swapchain;
5678 swapchain = get_swapchain(surface);
5679 if (swapchain) {
5680 GLenum buffer;
5682 TRACE("Surface %p is onscreen\n", surface);
5684 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5685 ENTER_GL();
5686 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5687 buffer = surface_get_gl_buffer(surface, swapchain);
5688 glDrawBuffer(buffer);
5689 checkGLcall("glDrawBuffer()");
5690 } else {
5691 TRACE("Surface %p is offscreen\n", surface);
5693 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5694 ENTER_GL();
5695 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5696 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5697 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5700 if (rect) {
5701 glEnable(GL_SCISSOR_TEST);
5702 if(!swapchain) {
5703 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5704 } else {
5705 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5706 rect->x2 - rect->x1, rect->y2 - rect->y1);
5708 checkGLcall("glScissor");
5709 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5710 } else {
5711 glDisable(GL_SCISSOR_TEST);
5713 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5715 glDisable(GL_BLEND);
5716 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5718 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5719 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5721 glClearColor(color[0], color[1], color[2], color[3]);
5722 glClear(GL_COLOR_BUFFER_BIT);
5723 checkGLcall("glClear");
5725 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5726 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5727 glDrawBuffer(GL_BACK);
5728 checkGLcall("glDrawBuffer()");
5731 LEAVE_GL();
5732 context_release(context);
5735 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5736 unsigned int r, g, b, a;
5737 DWORD ret;
5739 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5740 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5741 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5742 return color;
5744 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5746 a = (color & 0xff000000) >> 24;
5747 r = (color & 0x00ff0000) >> 16;
5748 g = (color & 0x0000ff00) >> 8;
5749 b = (color & 0x000000ff) >> 0;
5751 switch(destfmt)
5753 case WINED3DFMT_B5G6R5_UNORM:
5754 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5755 r = (r * 32) / 256;
5756 g = (g * 64) / 256;
5757 b = (b * 32) / 256;
5758 ret = r << 11;
5759 ret |= g << 5;
5760 ret |= b;
5761 TRACE("Returning %08x\n", ret);
5762 return ret;
5764 case WINED3DFMT_B5G5R5X1_UNORM:
5765 case WINED3DFMT_B5G5R5A1_UNORM:
5766 a = (a * 2) / 256;
5767 r = (r * 32) / 256;
5768 g = (g * 32) / 256;
5769 b = (b * 32) / 256;
5770 ret = a << 15;
5771 ret |= r << 10;
5772 ret |= g << 5;
5773 ret |= b << 0;
5774 TRACE("Returning %08x\n", ret);
5775 return ret;
5777 case WINED3DFMT_A8_UNORM:
5778 TRACE("Returning %08x\n", a);
5779 return a;
5781 case WINED3DFMT_B4G4R4X4_UNORM:
5782 case WINED3DFMT_B4G4R4A4_UNORM:
5783 a = (a * 16) / 256;
5784 r = (r * 16) / 256;
5785 g = (g * 16) / 256;
5786 b = (b * 16) / 256;
5787 ret = a << 12;
5788 ret |= r << 8;
5789 ret |= g << 4;
5790 ret |= b << 0;
5791 TRACE("Returning %08x\n", ret);
5792 return ret;
5794 case WINED3DFMT_B2G3R3_UNORM:
5795 r = (r * 8) / 256;
5796 g = (g * 8) / 256;
5797 b = (b * 4) / 256;
5798 ret = r << 5;
5799 ret |= g << 2;
5800 ret |= b << 0;
5801 TRACE("Returning %08x\n", ret);
5802 return ret;
5804 case WINED3DFMT_R8G8B8X8_UNORM:
5805 case WINED3DFMT_R8G8B8A8_UNORM:
5806 ret = a << 24;
5807 ret |= b << 16;
5808 ret |= g << 8;
5809 ret |= r << 0;
5810 TRACE("Returning %08x\n", ret);
5811 return ret;
5813 case WINED3DFMT_B10G10R10A2_UNORM:
5814 a = (a * 4) / 256;
5815 r = (r * 1024) / 256;
5816 g = (g * 1024) / 256;
5817 b = (b * 1024) / 256;
5818 ret = a << 30;
5819 ret |= r << 20;
5820 ret |= g << 10;
5821 ret |= b << 0;
5822 TRACE("Returning %08x\n", ret);
5823 return ret;
5825 case WINED3DFMT_R10G10B10A2_UNORM:
5826 a = (a * 4) / 256;
5827 r = (r * 1024) / 256;
5828 g = (g * 1024) / 256;
5829 b = (b * 1024) / 256;
5830 ret = a << 30;
5831 ret |= b << 20;
5832 ret |= g << 10;
5833 ret |= r << 0;
5834 TRACE("Returning %08x\n", ret);
5835 return ret;
5837 default:
5838 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5839 return 0;
5843 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5845 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5846 WINEDDBLTFX BltFx;
5847 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5849 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5850 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5851 return WINED3DERR_INVALIDCALL;
5854 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5855 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5856 color_fill_fbo(iface, pSurface, pRect, c);
5857 return WINED3D_OK;
5858 } else {
5859 /* Just forward this to the DirectDraw blitting engine */
5860 memset(&BltFx, 0, sizeof(BltFx));
5861 BltFx.dwSize = sizeof(BltFx);
5862 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5863 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5864 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5868 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5869 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5871 IWineD3DResource *resource;
5872 IWineD3DSurface *surface;
5873 HRESULT hr;
5875 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5876 if (FAILED(hr))
5878 ERR("Failed to get resource, hr %#x\n", hr);
5879 return;
5882 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5884 FIXME("Only supported on surface resources\n");
5885 IWineD3DResource_Release(resource);
5886 return;
5889 surface = (IWineD3DSurface *)resource;
5891 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5893 color_fill_fbo(iface, surface, NULL, color);
5895 else
5897 WINEDDBLTFX BltFx;
5898 WINED3DCOLOR c;
5900 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5902 c = ((DWORD)(color[2] * 255.0f));
5903 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5904 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5905 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5907 /* Just forward this to the DirectDraw blitting engine */
5908 memset(&BltFx, 0, sizeof(BltFx));
5909 BltFx.dwSize = sizeof(BltFx);
5910 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5911 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5912 if (FAILED(hr))
5914 ERR("Blt failed, hr %#x\n", hr);
5918 IWineD3DResource_Release(resource);
5921 /* rendertarget and depth stencil functions */
5922 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5925 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5927 ERR("(%p) : Only %d render targets are supported.\n",
5928 This, This->adapter->gl_info.limits.buffers);
5929 return WINED3DERR_INVALIDCALL;
5932 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5933 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5934 /* Note inc ref on returned surface */
5935 if(*ppRenderTarget != NULL)
5936 IWineD3DSurface_AddRef(*ppRenderTarget);
5937 return WINED3D_OK;
5940 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5942 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5943 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5944 IWineD3DSwapChainImpl *Swapchain;
5945 HRESULT hr;
5947 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5949 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5950 if(hr != WINED3D_OK) {
5951 ERR("Can't get the swapchain\n");
5952 return hr;
5955 /* Make sure to release the swapchain */
5956 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5958 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5959 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5960 return WINED3DERR_INVALIDCALL;
5962 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5963 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5964 return WINED3DERR_INVALIDCALL;
5967 if(Swapchain->frontBuffer != Front) {
5968 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5970 if(Swapchain->frontBuffer)
5972 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5973 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5975 Swapchain->frontBuffer = Front;
5977 if(Swapchain->frontBuffer) {
5978 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5979 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5983 if(Back && !Swapchain->backBuffer) {
5984 /* We need memory for the back buffer array - only one back buffer this way */
5985 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5986 if(!Swapchain->backBuffer) {
5987 ERR("Out of memory\n");
5988 return E_OUTOFMEMORY;
5992 if(Swapchain->backBuffer[0] != Back) {
5993 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5995 /* What to do about the context here in the case of multithreading? Not sure.
5996 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5998 WARN("No active context?\n");
6000 ENTER_GL();
6001 if(!Swapchain->backBuffer[0]) {
6002 /* GL was told to draw to the front buffer at creation,
6003 * undo that
6005 glDrawBuffer(GL_BACK);
6006 checkGLcall("glDrawBuffer(GL_BACK)");
6007 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6008 Swapchain->presentParms.BackBufferCount = 1;
6009 } else if (!Back) {
6010 /* That makes problems - disable for now */
6011 /* glDrawBuffer(GL_FRONT); */
6012 checkGLcall("glDrawBuffer(GL_FRONT)");
6013 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6014 Swapchain->presentParms.BackBufferCount = 0;
6016 LEAVE_GL();
6018 if(Swapchain->backBuffer[0])
6020 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6021 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6023 Swapchain->backBuffer[0] = Back;
6025 if(Swapchain->backBuffer[0]) {
6026 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6027 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6028 } else {
6029 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6030 Swapchain->backBuffer = NULL;
6035 return WINED3D_OK;
6038 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6040 *ppZStencilSurface = This->stencilBufferTarget;
6041 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6043 if(*ppZStencilSurface != NULL) {
6044 /* Note inc ref on returned surface */
6045 IWineD3DSurface_AddRef(*ppZStencilSurface);
6046 return WINED3D_OK;
6047 } else {
6048 return WINED3DERR_NOTFOUND;
6052 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6053 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6056 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6057 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6058 const struct wined3d_gl_info *gl_info;
6059 struct wined3d_context *context;
6060 GLenum gl_filter;
6061 POINT offset = {0, 0};
6063 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6064 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6065 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6066 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6068 switch (filter) {
6069 case WINED3DTEXF_LINEAR:
6070 gl_filter = GL_LINEAR;
6071 break;
6073 default:
6074 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6075 case WINED3DTEXF_NONE:
6076 case WINED3DTEXF_POINT:
6077 gl_filter = GL_NEAREST;
6078 break;
6081 /* Attach src surface to src fbo */
6082 src_swapchain = get_swapchain(src_surface);
6083 dst_swapchain = get_swapchain(dst_surface);
6085 if (src_swapchain) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
6086 else if (dst_swapchain) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6087 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6089 gl_info = context->gl_info;
6091 if (src_swapchain) {
6092 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6094 TRACE("Source surface %p is onscreen\n", src_surface);
6095 /* Make sure the drawable is up to date. In the offscreen case
6096 * attach_surface_fbo() implicitly takes care of this. */
6097 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6099 if(buffer == GL_FRONT) {
6100 RECT windowsize;
6101 UINT h;
6102 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6103 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6104 h = windowsize.bottom - windowsize.top;
6105 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6106 src_rect->y1 = offset.y + h - src_rect->y1;
6107 src_rect->y2 = offset.y + h - src_rect->y2;
6108 } else {
6109 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6110 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6113 ENTER_GL();
6114 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
6115 glReadBuffer(buffer);
6116 checkGLcall("glReadBuffer()");
6117 } else {
6118 TRACE("Source surface %p is offscreen\n", src_surface);
6119 ENTER_GL();
6120 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
6121 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
6122 glReadBuffer(GL_COLOR_ATTACHMENT0);
6123 checkGLcall("glReadBuffer()");
6124 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
6126 LEAVE_GL();
6128 /* Attach dst surface to dst fbo */
6129 if (dst_swapchain) {
6130 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6132 TRACE("Destination surface %p is onscreen\n", dst_surface);
6133 /* Make sure the drawable is up to date. In the offscreen case
6134 * attach_surface_fbo() implicitly takes care of this. */
6135 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6137 if(buffer == GL_FRONT) {
6138 RECT windowsize;
6139 UINT h;
6140 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6141 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6142 h = windowsize.bottom - windowsize.top;
6143 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6144 dst_rect->y1 = offset.y + h - dst_rect->y1;
6145 dst_rect->y2 = offset.y + h - dst_rect->y2;
6146 } else {
6147 /* Screen coords = window coords, surface height = window height */
6148 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6149 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6152 ENTER_GL();
6153 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
6154 glDrawBuffer(buffer);
6155 checkGLcall("glDrawBuffer()");
6156 } else {
6157 TRACE("Destination surface %p is offscreen\n", dst_surface);
6159 ENTER_GL();
6160 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
6161 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
6162 glDrawBuffer(GL_COLOR_ATTACHMENT0);
6163 checkGLcall("glDrawBuffer()");
6164 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
6166 glDisable(GL_SCISSOR_TEST);
6167 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6169 if (flip) {
6170 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6171 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
6172 checkGLcall("glBlitFramebuffer()");
6173 } else {
6174 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6175 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
6176 checkGLcall("glBlitFramebuffer()");
6179 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6181 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6182 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6183 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6184 glDrawBuffer(GL_BACK);
6185 checkGLcall("glDrawBuffer()");
6187 LEAVE_GL();
6189 context_release(context);
6192 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
6193 BOOL set_viewport) {
6194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6196 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6198 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
6200 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6201 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
6202 return WINED3DERR_INVALIDCALL;
6205 /* MSDN says that null disables the render target
6206 but a device must always be associated with a render target
6207 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6209 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6210 FIXME("Trying to set render target 0 to NULL\n");
6211 return WINED3DERR_INVALIDCALL;
6213 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6214 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);
6215 return WINED3DERR_INVALIDCALL;
6218 /* If we are trying to set what we already have, don't bother */
6219 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6220 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6221 return WINED3D_OK;
6223 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6224 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6225 This->render_targets[RenderTargetIndex] = pRenderTarget;
6227 /* Render target 0 is special */
6228 if(RenderTargetIndex == 0 && set_viewport) {
6229 /* Finally, reset the viewport and scissor rect as the MSDN states.
6230 * Tests show that stateblock recording is ignored, the change goes
6231 * directly into the primary stateblock.
6233 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6234 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6235 This->stateBlock->viewport.X = 0;
6236 This->stateBlock->viewport.Y = 0;
6237 This->stateBlock->viewport.MaxZ = 1.0f;
6238 This->stateBlock->viewport.MinZ = 0.0f;
6239 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6241 This->stateBlock->scissorRect.top = 0;
6242 This->stateBlock->scissorRect.left = 0;
6243 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
6244 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
6245 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6247 return WINED3D_OK;
6250 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6252 HRESULT hr = WINED3D_OK;
6253 IWineD3DSurface *tmp;
6255 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6257 if (pNewZStencil == This->stencilBufferTarget) {
6258 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6259 } else {
6260 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6261 * depending on the renter target implementation being used.
6262 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6263 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6264 * stencil buffer and incur an extra memory overhead
6265 ******************************************************/
6267 if (This->stencilBufferTarget) {
6268 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6269 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6270 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6271 } else {
6272 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6273 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
6274 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6275 context_release(context);
6279 tmp = This->stencilBufferTarget;
6280 This->stencilBufferTarget = pNewZStencil;
6281 /* should we be calling the parent or the wined3d surface? */
6282 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6283 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6284 hr = WINED3D_OK;
6286 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6287 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6288 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6289 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6290 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6294 return hr;
6297 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6298 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6300 /* TODO: the use of Impl is deprecated. */
6301 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6302 WINED3DLOCKED_RECT lockedRect;
6304 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6306 /* some basic validation checks */
6307 if(This->cursorTexture) {
6308 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6309 ENTER_GL();
6310 glDeleteTextures(1, &This->cursorTexture);
6311 LEAVE_GL();
6312 context_release(context);
6313 This->cursorTexture = 0;
6316 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6317 This->haveHardwareCursor = TRUE;
6318 else
6319 This->haveHardwareCursor = FALSE;
6321 if(pCursorBitmap) {
6322 WINED3DLOCKED_RECT rect;
6324 /* MSDN: Cursor must be A8R8G8B8 */
6325 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6327 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6328 return WINED3DERR_INVALIDCALL;
6331 /* MSDN: Cursor must be smaller than the display mode */
6332 if(pSur->currentDesc.Width > This->ddraw_width ||
6333 pSur->currentDesc.Height > This->ddraw_height) {
6334 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);
6335 return WINED3DERR_INVALIDCALL;
6338 if (!This->haveHardwareCursor) {
6339 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6341 /* Do not store the surface's pointer because the application may
6342 * release it after setting the cursor image. Windows doesn't
6343 * addref the set surface, so we can't do this either without
6344 * creating circular refcount dependencies. Copy out the gl texture
6345 * instead.
6347 This->cursorWidth = pSur->currentDesc.Width;
6348 This->cursorHeight = pSur->currentDesc.Height;
6349 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6351 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6352 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6353 struct wined3d_context *context;
6354 char *mem, *bits = rect.pBits;
6355 GLint intfmt = glDesc->glInternal;
6356 GLint format = glDesc->glFormat;
6357 GLint type = glDesc->glType;
6358 INT height = This->cursorHeight;
6359 INT width = This->cursorWidth;
6360 INT bpp = glDesc->byte_count;
6361 DWORD sampler;
6362 INT i;
6364 /* Reformat the texture memory (pitch and width can be
6365 * different) */
6366 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6367 for(i = 0; i < height; i++)
6368 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6369 IWineD3DSurface_UnlockRect(pCursorBitmap);
6371 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6373 ENTER_GL();
6375 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6377 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6378 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6381 /* Make sure that a proper texture unit is selected */
6382 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6383 checkGLcall("glActiveTextureARB");
6384 sampler = This->rev_tex_unit_map[0];
6385 if (sampler != WINED3D_UNMAPPED_STAGE)
6387 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6389 /* Create a new cursor texture */
6390 glGenTextures(1, &This->cursorTexture);
6391 checkGLcall("glGenTextures");
6392 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6393 checkGLcall("glBindTexture");
6394 /* Copy the bitmap memory into the cursor texture */
6395 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6396 HeapFree(GetProcessHeap(), 0, mem);
6397 checkGLcall("glTexImage2D");
6399 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6401 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6402 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6405 LEAVE_GL();
6407 context_release(context);
6409 else
6411 FIXME("A cursor texture was not returned.\n");
6412 This->cursorTexture = 0;
6415 else
6417 /* Draw a hardware cursor */
6418 ICONINFO cursorInfo;
6419 HCURSOR cursor;
6420 /* Create and clear maskBits because it is not needed for
6421 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6422 * chunks. */
6423 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6424 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6425 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6426 WINED3DLOCK_NO_DIRTY_UPDATE |
6427 WINED3DLOCK_READONLY
6429 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6430 pSur->currentDesc.Height);
6432 cursorInfo.fIcon = FALSE;
6433 cursorInfo.xHotspot = XHotSpot;
6434 cursorInfo.yHotspot = YHotSpot;
6435 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6436 1, 1, maskBits);
6437 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6438 1, 32, lockedRect.pBits);
6439 IWineD3DSurface_UnlockRect(pCursorBitmap);
6440 /* Create our cursor and clean up. */
6441 cursor = CreateIconIndirect(&cursorInfo);
6442 SetCursor(cursor);
6443 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6444 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6445 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6446 This->hardwareCursor = cursor;
6447 HeapFree(GetProcessHeap(), 0, maskBits);
6451 This->xHotSpot = XHotSpot;
6452 This->yHotSpot = YHotSpot;
6453 return WINED3D_OK;
6456 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6458 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6460 This->xScreenSpace = XScreenSpace;
6461 This->yScreenSpace = YScreenSpace;
6463 return;
6467 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6469 BOOL oldVisible = This->bCursorVisible;
6470 POINT pt;
6472 TRACE("(%p) : visible(%d)\n", This, bShow);
6475 * When ShowCursor is first called it should make the cursor appear at the OS's last
6476 * known cursor position. Because of this, some applications just repetitively call
6477 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6479 GetCursorPos(&pt);
6480 This->xScreenSpace = pt.x;
6481 This->yScreenSpace = pt.y;
6483 if (This->haveHardwareCursor) {
6484 This->bCursorVisible = bShow;
6485 if (bShow)
6486 SetCursor(This->hardwareCursor);
6487 else
6488 SetCursor(NULL);
6490 else
6492 if (This->cursorTexture)
6493 This->bCursorVisible = bShow;
6496 return oldVisible;
6499 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6500 TRACE("checking resource %p for eviction\n", resource);
6501 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6502 TRACE("Evicting %p\n", resource);
6503 IWineD3DResource_UnLoad(resource);
6505 IWineD3DResource_Release(resource);
6506 return S_OK;
6509 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6511 TRACE("(%p)\n", This);
6513 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6514 return WINED3D_OK;
6517 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6519 IWineD3DDeviceImpl *device = surface->resource.wineD3DDevice;
6520 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6522 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6523 if(surface->Flags & SFLAG_DIBSECTION) {
6524 /* Release the DC */
6525 SelectObject(surface->hDC, surface->dib.holdbitmap);
6526 DeleteDC(surface->hDC);
6527 /* Release the DIB section */
6528 DeleteObject(surface->dib.DIBsection);
6529 surface->dib.bitmap_data = NULL;
6530 surface->resource.allocatedMemory = NULL;
6531 surface->Flags &= ~SFLAG_DIBSECTION;
6533 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6534 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6535 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6536 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6538 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6539 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6540 } else {
6541 surface->pow2Width = surface->pow2Height = 1;
6542 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6543 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6545 surface->glRect.left = 0;
6546 surface->glRect.top = 0;
6547 surface->glRect.right = surface->pow2Width;
6548 surface->glRect.bottom = surface->pow2Height;
6550 if (surface->texture_name)
6552 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6553 ENTER_GL();
6554 glDeleteTextures(1, &surface->texture_name);
6555 LEAVE_GL();
6556 context_release(context);
6557 surface->texture_name = 0;
6558 surface->Flags &= ~SFLAG_CLIENT;
6560 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6561 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6562 surface->Flags |= SFLAG_NONPOW2;
6563 } else {
6564 surface->Flags &= ~SFLAG_NONPOW2;
6566 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6567 surface->resource.allocatedMemory = NULL;
6568 surface->resource.heapMemory = NULL;
6569 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6570 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6571 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6572 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6573 } else {
6574 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6578 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6579 TRACE("Unloading resource %p\n", resource);
6580 IWineD3DResource_UnLoad(resource);
6581 IWineD3DResource_Release(resource);
6582 return S_OK;
6585 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6587 UINT i, count;
6588 WINED3DDISPLAYMODE m;
6589 HRESULT hr;
6591 /* All Windowed modes are supported, as is leaving the current mode */
6592 if(pp->Windowed) return TRUE;
6593 if(!pp->BackBufferWidth) return TRUE;
6594 if(!pp->BackBufferHeight) return TRUE;
6596 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6597 for(i = 0; i < count; i++) {
6598 memset(&m, 0, sizeof(m));
6599 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6600 if(FAILED(hr)) {
6601 ERR("EnumAdapterModes failed\n");
6603 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6604 /* Mode found, it is supported */
6605 return TRUE;
6608 /* Mode not found -> not supported */
6609 return FALSE;
6612 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6614 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6615 const struct wined3d_gl_info *gl_info;
6616 struct wined3d_context *context;
6617 UINT i;
6618 IWineD3DBaseShaderImpl *shader;
6620 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6621 gl_info = context->gl_info;
6623 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6624 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6625 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6628 ENTER_GL();
6629 if(This->depth_blt_texture) {
6630 glDeleteTextures(1, &This->depth_blt_texture);
6631 This->depth_blt_texture = 0;
6633 if (This->depth_blt_rb) {
6634 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6635 This->depth_blt_rb = 0;
6636 This->depth_blt_rb_w = 0;
6637 This->depth_blt_rb_h = 0;
6639 LEAVE_GL();
6641 This->blitter->free_private(iface);
6642 This->frag_pipe->free_private(iface);
6643 This->shader_backend->shader_free_private(iface);
6645 ENTER_GL();
6646 for (i = 0; i < This->adapter->gl_info.limits.textures; ++i)
6648 /* Textures are recreated below */
6649 glDeleteTextures(1, &This->dummyTextureName[i]);
6650 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6651 This->dummyTextureName[i] = 0;
6653 LEAVE_GL();
6655 context_release(context);
6657 while (This->numContexts)
6659 context_destroy(This, This->contexts[0]);
6661 HeapFree(GetProcessHeap(), 0, swapchain->context);
6662 swapchain->context = NULL;
6663 swapchain->num_contexts = 0;
6666 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6668 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6669 HRESULT hr;
6670 IWineD3DSurfaceImpl *target;
6672 /* Recreate the primary swapchain's context */
6673 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6674 if(swapchain->backBuffer) {
6675 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6676 } else {
6677 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6679 swapchain->context[0] = context_create(This, target, swapchain->win_handle, FALSE, &swapchain->presentParms);
6680 swapchain->num_contexts = 1;
6682 create_dummy_textures(This);
6684 context_release(swapchain->context[0]);
6686 hr = This->shader_backend->shader_alloc_private(iface);
6687 if(FAILED(hr)) {
6688 ERR("Failed to recreate shader private data\n");
6689 goto err_out;
6691 hr = This->frag_pipe->alloc_private(iface);
6692 if(FAILED(hr)) {
6693 TRACE("Fragment pipeline private data couldn't be allocated\n");
6694 goto err_out;
6696 hr = This->blitter->alloc_private(iface);
6697 if(FAILED(hr)) {
6698 TRACE("Blitter private data couldn't be allocated\n");
6699 goto err_out;
6702 return WINED3D_OK;
6704 err_out:
6705 This->blitter->free_private(iface);
6706 This->frag_pipe->free_private(iface);
6707 This->shader_backend->shader_free_private(iface);
6708 return hr;
6711 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6713 IWineD3DSwapChainImpl *swapchain;
6714 HRESULT hr;
6715 BOOL DisplayModeChanged = FALSE;
6716 WINED3DDISPLAYMODE mode;
6717 TRACE("(%p)\n", This);
6719 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6720 if(FAILED(hr)) {
6721 ERR("Failed to get the first implicit swapchain\n");
6722 return hr;
6725 if(!is_display_mode_supported(This, pPresentationParameters)) {
6726 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6727 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6728 pPresentationParameters->BackBufferHeight);
6729 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6730 return WINED3DERR_INVALIDCALL;
6733 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6734 * on an existing gl context, so there's no real need for recreation.
6736 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6738 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6740 TRACE("New params:\n");
6741 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6742 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6743 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6744 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6745 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6746 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6747 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6748 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6749 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6750 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6751 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6752 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6753 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6755 /* No special treatment of these parameters. Just store them */
6756 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6757 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6758 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6759 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6761 /* What to do about these? */
6762 if(pPresentationParameters->BackBufferCount != 0 &&
6763 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6764 ERR("Cannot change the back buffer count yet\n");
6766 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6767 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6768 ERR("Cannot change the back buffer format yet\n");
6770 if(pPresentationParameters->hDeviceWindow != NULL &&
6771 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6772 ERR("Cannot change the device window yet\n");
6774 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6775 HRESULT hrc;
6777 TRACE("Creating the depth stencil buffer\n");
6779 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6780 This->parent,
6781 pPresentationParameters->BackBufferWidth,
6782 pPresentationParameters->BackBufferHeight,
6783 pPresentationParameters->AutoDepthStencilFormat,
6784 pPresentationParameters->MultiSampleType,
6785 pPresentationParameters->MultiSampleQuality,
6786 FALSE,
6787 &This->auto_depth_stencil_buffer);
6789 if (FAILED(hrc)) {
6790 ERR("Failed to create the depth stencil buffer\n");
6791 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6792 return WINED3DERR_INVALIDCALL;
6796 /* Reset the depth stencil */
6797 if (pPresentationParameters->EnableAutoDepthStencil)
6798 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6799 else
6800 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6802 TRACE("Resetting stateblock\n");
6803 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6804 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6806 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6808 if(pPresentationParameters->Windowed) {
6809 mode.Width = swapchain->orig_width;
6810 mode.Height = swapchain->orig_height;
6811 mode.RefreshRate = 0;
6812 mode.Format = swapchain->presentParms.BackBufferFormat;
6813 } else {
6814 mode.Width = pPresentationParameters->BackBufferWidth;
6815 mode.Height = pPresentationParameters->BackBufferHeight;
6816 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6817 mode.Format = swapchain->presentParms.BackBufferFormat;
6820 /* Should Width == 800 && Height == 0 set 800x600? */
6821 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6822 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6823 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6825 UINT i;
6827 if(!pPresentationParameters->Windowed) {
6828 DisplayModeChanged = TRUE;
6830 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6831 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6833 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6834 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6835 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6837 if(This->auto_depth_stencil_buffer) {
6838 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6842 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6843 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6844 DisplayModeChanged) {
6846 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6848 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
6849 if(swapchain->presentParms.Windowed) {
6850 /* switch from windowed to fs */
6851 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
6852 pPresentationParameters->BackBufferWidth,
6853 pPresentationParameters->BackBufferHeight);
6854 } else {
6855 /* Fullscreen -> fullscreen mode change */
6856 MoveWindow(swapchain->win_handle, 0, 0,
6857 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6858 TRUE);
6860 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
6861 /* Fullscreen -> windowed switch */
6862 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
6864 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6865 } else if(!pPresentationParameters->Windowed) {
6866 DWORD style = This->style, exStyle = This->exStyle;
6867 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6868 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6869 * Reset to clear up their mess. Guild Wars also loses the device during that.
6871 This->style = 0;
6872 This->exStyle = 0;
6873 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
6874 pPresentationParameters->BackBufferWidth,
6875 pPresentationParameters->BackBufferHeight);
6876 This->style = style;
6877 This->exStyle = exStyle;
6880 /* Note: No parent needed for initial internal stateblock */
6881 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6882 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6883 else TRACE("Created stateblock %p\n", This->stateBlock);
6884 This->updateStateBlock = This->stateBlock;
6885 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6887 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6888 if(FAILED(hr)) {
6889 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6892 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6893 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6895 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6896 * first use
6898 return hr;
6901 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6903 /** FIXME: always true at the moment **/
6904 if(!bEnableDialogs) {
6905 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6907 return WINED3D_OK;
6911 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6913 TRACE("(%p) : pParameters %p\n", This, pParameters);
6915 *pParameters = This->createParms;
6916 return WINED3D_OK;
6919 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6920 IWineD3DSwapChain *swapchain;
6922 TRACE("Relaying to swapchain\n");
6924 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6925 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6926 IWineD3DSwapChain_Release(swapchain);
6928 return;
6931 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6932 IWineD3DSwapChain *swapchain;
6934 TRACE("Relaying to swapchain\n");
6936 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6937 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6938 IWineD3DSwapChain_Release(swapchain);
6940 return;
6944 /** ********************************************************
6945 * Notification functions
6946 ** ********************************************************/
6947 /** This function must be called in the release of a resource when ref == 0,
6948 * the contents of resource must still be correct,
6949 * any handles to other resource held by the caller must be closed
6950 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6951 *****************************************************/
6952 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6954 TRACE("(%p) : Adding resource %p\n", This, resource);
6956 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6959 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6961 TRACE("(%p) : Removing resource %p\n", This, resource);
6963 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6966 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6968 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6969 int counter;
6971 TRACE("(%p) : resource %p\n", This, resource);
6973 context_resource_released((IWineD3DDevice *)This, resource, type);
6975 switch (type) {
6976 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6977 case WINED3DRTYPE_SURFACE: {
6978 unsigned int i;
6980 if (This->d3d_initialized)
6982 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6984 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6985 This->render_targets[i] = NULL;
6988 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6989 This->stencilBufferTarget = NULL;
6993 break;
6995 case WINED3DRTYPE_TEXTURE:
6996 case WINED3DRTYPE_CUBETEXTURE:
6997 case WINED3DRTYPE_VOLUMETEXTURE:
6998 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6999 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7000 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7001 This->stateBlock->textures[counter] = NULL;
7003 if (This->updateStateBlock != This->stateBlock ){
7004 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7005 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7006 This->updateStateBlock->textures[counter] = NULL;
7010 break;
7011 case WINED3DRTYPE_VOLUME:
7012 /* TODO: nothing really? */
7013 break;
7014 case WINED3DRTYPE_BUFFER:
7016 int streamNumber;
7017 TRACE("Cleaning up stream pointers\n");
7019 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7020 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7021 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7023 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7024 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7025 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7026 This->updateStateBlock->streamSource[streamNumber] = 0;
7027 /* Set changed flag? */
7030 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) */
7031 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7032 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7033 This->stateBlock->streamSource[streamNumber] = 0;
7038 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7039 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7040 This->updateStateBlock->pIndexData = NULL;
7043 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7044 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7045 This->stateBlock->pIndexData = NULL;
7049 break;
7051 default:
7052 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7053 break;
7057 /* Remove the resource from the resourceStore */
7058 device_resource_remove(This, resource);
7060 TRACE("Resource released\n");
7064 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7066 IWineD3DResourceImpl *resource, *cursor;
7067 HRESULT ret;
7068 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7070 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7071 TRACE("enumerating resource %p\n", resource);
7072 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7073 ret = pCallback((IWineD3DResource *) resource, pData);
7074 if(ret == S_FALSE) {
7075 TRACE("Canceling enumeration\n");
7076 break;
7079 return WINED3D_OK;
7082 /**********************************************************
7083 * IWineD3DDevice VTbl follows
7084 **********************************************************/
7086 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7088 /*** IUnknown methods ***/
7089 IWineD3DDeviceImpl_QueryInterface,
7090 IWineD3DDeviceImpl_AddRef,
7091 IWineD3DDeviceImpl_Release,
7092 /*** IWineD3DDevice methods ***/
7093 IWineD3DDeviceImpl_GetParent,
7094 /*** Creation methods**/
7095 IWineD3DDeviceImpl_CreateBuffer,
7096 IWineD3DDeviceImpl_CreateVertexBuffer,
7097 IWineD3DDeviceImpl_CreateIndexBuffer,
7098 IWineD3DDeviceImpl_CreateStateBlock,
7099 IWineD3DDeviceImpl_CreateSurface,
7100 IWineD3DDeviceImpl_CreateRendertargetView,
7101 IWineD3DDeviceImpl_CreateTexture,
7102 IWineD3DDeviceImpl_CreateVolumeTexture,
7103 IWineD3DDeviceImpl_CreateVolume,
7104 IWineD3DDeviceImpl_CreateCubeTexture,
7105 IWineD3DDeviceImpl_CreateQuery,
7106 IWineD3DDeviceImpl_CreateSwapChain,
7107 IWineD3DDeviceImpl_CreateVertexDeclaration,
7108 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7109 IWineD3DDeviceImpl_CreateVertexShader,
7110 IWineD3DDeviceImpl_CreatePixelShader,
7111 IWineD3DDeviceImpl_CreatePalette,
7112 /*** Odd functions **/
7113 IWineD3DDeviceImpl_Init3D,
7114 IWineD3DDeviceImpl_InitGDI,
7115 IWineD3DDeviceImpl_Uninit3D,
7116 IWineD3DDeviceImpl_UninitGDI,
7117 IWineD3DDeviceImpl_SetMultithreaded,
7118 IWineD3DDeviceImpl_EvictManagedResources,
7119 IWineD3DDeviceImpl_GetAvailableTextureMem,
7120 IWineD3DDeviceImpl_GetBackBuffer,
7121 IWineD3DDeviceImpl_GetCreationParameters,
7122 IWineD3DDeviceImpl_GetDeviceCaps,
7123 IWineD3DDeviceImpl_GetDirect3D,
7124 IWineD3DDeviceImpl_GetDisplayMode,
7125 IWineD3DDeviceImpl_SetDisplayMode,
7126 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7127 IWineD3DDeviceImpl_GetRasterStatus,
7128 IWineD3DDeviceImpl_GetSwapChain,
7129 IWineD3DDeviceImpl_Reset,
7130 IWineD3DDeviceImpl_SetDialogBoxMode,
7131 IWineD3DDeviceImpl_SetCursorProperties,
7132 IWineD3DDeviceImpl_SetCursorPosition,
7133 IWineD3DDeviceImpl_ShowCursor,
7134 /*** Getters and setters **/
7135 IWineD3DDeviceImpl_SetClipPlane,
7136 IWineD3DDeviceImpl_GetClipPlane,
7137 IWineD3DDeviceImpl_SetClipStatus,
7138 IWineD3DDeviceImpl_GetClipStatus,
7139 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7140 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7141 IWineD3DDeviceImpl_SetDepthStencilSurface,
7142 IWineD3DDeviceImpl_GetDepthStencilSurface,
7143 IWineD3DDeviceImpl_SetGammaRamp,
7144 IWineD3DDeviceImpl_GetGammaRamp,
7145 IWineD3DDeviceImpl_SetIndexBuffer,
7146 IWineD3DDeviceImpl_GetIndexBuffer,
7147 IWineD3DDeviceImpl_SetBaseVertexIndex,
7148 IWineD3DDeviceImpl_GetBaseVertexIndex,
7149 IWineD3DDeviceImpl_SetLight,
7150 IWineD3DDeviceImpl_GetLight,
7151 IWineD3DDeviceImpl_SetLightEnable,
7152 IWineD3DDeviceImpl_GetLightEnable,
7153 IWineD3DDeviceImpl_SetMaterial,
7154 IWineD3DDeviceImpl_GetMaterial,
7155 IWineD3DDeviceImpl_SetNPatchMode,
7156 IWineD3DDeviceImpl_GetNPatchMode,
7157 IWineD3DDeviceImpl_SetPaletteEntries,
7158 IWineD3DDeviceImpl_GetPaletteEntries,
7159 IWineD3DDeviceImpl_SetPixelShader,
7160 IWineD3DDeviceImpl_GetPixelShader,
7161 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7162 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7163 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7164 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7165 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7166 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7167 IWineD3DDeviceImpl_SetRenderState,
7168 IWineD3DDeviceImpl_GetRenderState,
7169 IWineD3DDeviceImpl_SetRenderTarget,
7170 IWineD3DDeviceImpl_GetRenderTarget,
7171 IWineD3DDeviceImpl_SetFrontBackBuffers,
7172 IWineD3DDeviceImpl_SetSamplerState,
7173 IWineD3DDeviceImpl_GetSamplerState,
7174 IWineD3DDeviceImpl_SetScissorRect,
7175 IWineD3DDeviceImpl_GetScissorRect,
7176 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7177 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7178 IWineD3DDeviceImpl_SetStreamSource,
7179 IWineD3DDeviceImpl_GetStreamSource,
7180 IWineD3DDeviceImpl_SetStreamSourceFreq,
7181 IWineD3DDeviceImpl_GetStreamSourceFreq,
7182 IWineD3DDeviceImpl_SetTexture,
7183 IWineD3DDeviceImpl_GetTexture,
7184 IWineD3DDeviceImpl_SetTextureStageState,
7185 IWineD3DDeviceImpl_GetTextureStageState,
7186 IWineD3DDeviceImpl_SetTransform,
7187 IWineD3DDeviceImpl_GetTransform,
7188 IWineD3DDeviceImpl_SetVertexDeclaration,
7189 IWineD3DDeviceImpl_GetVertexDeclaration,
7190 IWineD3DDeviceImpl_SetVertexShader,
7191 IWineD3DDeviceImpl_GetVertexShader,
7192 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7193 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7194 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7195 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7196 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7197 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7198 IWineD3DDeviceImpl_SetViewport,
7199 IWineD3DDeviceImpl_GetViewport,
7200 IWineD3DDeviceImpl_MultiplyTransform,
7201 IWineD3DDeviceImpl_ValidateDevice,
7202 IWineD3DDeviceImpl_ProcessVertices,
7203 /*** State block ***/
7204 IWineD3DDeviceImpl_BeginStateBlock,
7205 IWineD3DDeviceImpl_EndStateBlock,
7206 /*** Scene management ***/
7207 IWineD3DDeviceImpl_BeginScene,
7208 IWineD3DDeviceImpl_EndScene,
7209 IWineD3DDeviceImpl_Present,
7210 IWineD3DDeviceImpl_Clear,
7211 IWineD3DDeviceImpl_ClearRendertargetView,
7212 /*** Drawing ***/
7213 IWineD3DDeviceImpl_SetPrimitiveType,
7214 IWineD3DDeviceImpl_GetPrimitiveType,
7215 IWineD3DDeviceImpl_DrawPrimitive,
7216 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7217 IWineD3DDeviceImpl_DrawPrimitiveUP,
7218 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7219 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7220 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7221 IWineD3DDeviceImpl_DrawRectPatch,
7222 IWineD3DDeviceImpl_DrawTriPatch,
7223 IWineD3DDeviceImpl_DeletePatch,
7224 IWineD3DDeviceImpl_ColorFill,
7225 IWineD3DDeviceImpl_UpdateTexture,
7226 IWineD3DDeviceImpl_UpdateSurface,
7227 IWineD3DDeviceImpl_GetFrontBufferData,
7228 /*** object tracking ***/
7229 IWineD3DDeviceImpl_EnumResources
7232 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
7233 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
7234 IUnknown *parent, IWineD3DDeviceParent *device_parent)
7236 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
7237 const struct fragment_pipeline *fragment_pipeline;
7238 struct shader_caps shader_caps;
7239 struct fragment_caps ffp_caps;
7240 WINED3DDISPLAYMODE mode;
7241 unsigned int i;
7242 HRESULT hr;
7244 device->lpVtbl = &IWineD3DDevice_Vtbl;
7245 device->ref = 1;
7246 device->wineD3D = (IWineD3D *)wined3d;
7247 IWineD3D_AddRef(device->wineD3D);
7248 device->adapter = wined3d->adapter_count ? adapter : NULL;
7249 device->parent = parent;
7250 device->device_parent = device_parent;
7251 list_init(&device->resources);
7252 list_init(&device->shaders);
7254 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7255 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
7257 /* Get the initial screen setup for ddraw. */
7258 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
7259 if (FAILED(hr))
7261 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7262 IWineD3D_Release(device->wineD3D);
7263 return hr;
7265 device->ddraw_width = mode.Width;
7266 device->ddraw_height = mode.Height;
7267 device->ddraw_format = mode.Format;
7269 /* Save the creation parameters. */
7270 device->createParms.AdapterOrdinal = adapter_idx;
7271 device->createParms.DeviceType = device_type;
7272 device->createParms.hFocusWindow = focus_window;
7273 device->createParms.BehaviorFlags = flags;
7275 device->adapterNo = adapter_idx;
7276 device->devType = device_type;
7277 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7279 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7280 device->shader_backend = select_shader_backend(adapter, device_type);
7282 memset(&shader_caps, 0, sizeof(shader_caps));
7283 device->shader_backend->shader_get_caps(device_type, &adapter->gl_info, &shader_caps);
7284 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7285 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7286 device->vs_clipping = shader_caps.VSClipping;
7288 memset(&ffp_caps, 0, sizeof(ffp_caps));
7289 fragment_pipeline = select_fragment_implementation(adapter, device_type);
7290 device->frag_pipe = fragment_pipeline;
7291 fragment_pipeline->get_caps(device_type, &adapter->gl_info, &ffp_caps);
7292 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7293 device->max_ffp_texture_stages = ffp_caps.MaxTextureBlendStages;
7295 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7296 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7297 if (FAILED(hr))
7299 ERR("Failed to compile state table, hr %#x.\n", hr);
7300 IWineD3D_Release(device->wineD3D);
7301 return hr;
7304 device->blitter = select_blit_implementation(adapter, device_type);
7306 return WINED3D_OK;
7310 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7311 DWORD rep = This->StateTable[state].representative;
7312 struct wined3d_context *context;
7313 DWORD idx;
7314 BYTE shift;
7315 UINT i;
7317 for(i = 0; i < This->numContexts; i++) {
7318 context = This->contexts[i];
7319 if(isStateDirty(context, rep)) continue;
7321 context->dirtyArray[context->numDirtyEntries++] = rep;
7322 idx = rep >> 5;
7323 shift = rep & 0x1f;
7324 context->isStateDirty[idx] |= (1 << shift);
7328 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7330 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.wineD3DDevice;
7331 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7332 *width = device->pbufferWidth;
7333 *height = device->pbufferHeight;
7336 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7338 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7339 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7340 *width = surface->pow2Width;
7341 *height = surface->pow2Height;
7344 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7346 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7347 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7348 * current context's drawable, which is the size of the back buffer of the swapchain
7349 * the active context belongs to. The back buffer of the swapchain is stored as the
7350 * surface the context belongs to. */
7351 *width = surface->currentDesc.Width;
7352 *height = surface->currentDesc.Height;