push 5bc4839baba05cc4333240c25295b8dd6e351557
[wine/hacks.git] / dlls / wined3d / device.c
bloba5a6c2e5859b9b9d60f3c17ee2b6e8c652f57468
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, parent);
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 goto err_out;
1788 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1789 if(!This->palettes[0]) {
1790 ERR("Out of memory!\n");
1791 goto err_out;
1793 for (i = 0; i < 256; ++i) {
1794 This->palettes[0][i].peRed = 0xFF;
1795 This->palettes[0][i].peGreen = 0xFF;
1796 This->palettes[0][i].peBlue = 0xFF;
1797 This->palettes[0][i].peFlags = 0xFF;
1799 This->currentPalette = 0;
1801 /* Initialize the texture unit mapping to a 1:1 mapping */
1802 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1804 if (state < gl_info->limits.fragment_samplers)
1806 This->texUnitMap[state] = state;
1807 This->rev_tex_unit_map[state] = state;
1808 } else {
1809 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1810 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1814 /* Setup the implicit swapchain. This also initializes a context. */
1815 TRACE("Creating implicit swapchain\n");
1816 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1817 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1818 if (FAILED(hr))
1820 WARN("Failed to create implicit swapchain\n");
1821 goto err_out;
1824 This->NumberOfSwapChains = 1;
1825 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1826 if(!This->swapchains) {
1827 ERR("Out of memory!\n");
1828 goto err_out;
1830 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1832 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1833 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1834 This->render_targets[0] = swapchain->backBuffer[0];
1836 else {
1837 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1838 This->render_targets[0] = swapchain->frontBuffer;
1840 IWineD3DSurface_AddRef(This->render_targets[0]);
1842 /* Depth Stencil support */
1843 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1844 if (NULL != This->stencilBufferTarget) {
1845 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1848 hr = This->shader_backend->shader_alloc_private(iface);
1849 if(FAILED(hr)) {
1850 TRACE("Shader private data couldn't be allocated\n");
1851 goto err_out;
1853 hr = This->frag_pipe->alloc_private(iface);
1854 if(FAILED(hr)) {
1855 TRACE("Fragment pipeline private data couldn't be allocated\n");
1856 goto err_out;
1858 hr = This->blitter->alloc_private(iface);
1859 if(FAILED(hr)) {
1860 TRACE("Blitter private data couldn't be allocated\n");
1861 goto err_out;
1864 /* Set up some starting GL setup */
1866 /* Setup all the devices defaults */
1867 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1869 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1871 create_dummy_textures(This);
1873 ENTER_GL();
1875 /* Initialize the current view state */
1876 This->view_ident = 1;
1877 This->contexts[0]->last_was_rhw = 0;
1878 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1879 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1881 switch(wined3d_settings.offscreen_rendering_mode) {
1882 case ORM_FBO:
1883 case ORM_PBUFFER:
1884 This->offscreenBuffer = GL_BACK;
1885 break;
1887 case ORM_BACKBUFFER:
1889 if (context_get_current()->aux_buffers > 0)
1891 TRACE("Using auxilliary buffer for offscreen rendering\n");
1892 This->offscreenBuffer = GL_AUX0;
1893 } else {
1894 TRACE("Using back buffer for offscreen rendering\n");
1895 This->offscreenBuffer = GL_BACK;
1900 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1901 LEAVE_GL();
1903 context_release(context);
1905 /* Clear the screen */
1906 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1907 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1908 0x00, 1.0f, 0);
1910 This->d3d_initialized = TRUE;
1912 if(wined3d_settings.logo) {
1913 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1915 This->highest_dirty_ps_const = 0;
1916 This->highest_dirty_vs_const = 0;
1917 return WINED3D_OK;
1919 err_out:
1920 HeapFree(GetProcessHeap(), 0, This->render_targets);
1921 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1922 HeapFree(GetProcessHeap(), 0, This->swapchains);
1923 This->NumberOfSwapChains = 0;
1924 if(This->palettes) {
1925 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1926 HeapFree(GetProcessHeap(), 0, This->palettes);
1928 This->NumberOfPalettes = 0;
1929 if(swapchain) {
1930 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1932 if(This->stateBlock) {
1933 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1934 This->stateBlock = NULL;
1936 if (This->blit_priv) {
1937 This->blitter->free_private(iface);
1939 if (This->fragment_priv) {
1940 This->frag_pipe->free_private(iface);
1942 if (This->shader_priv) {
1943 This->shader_backend->shader_free_private(iface);
1945 return hr;
1948 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1949 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1952 IWineD3DSwapChainImpl *swapchain = NULL;
1953 HRESULT hr;
1955 /* Setup the implicit swapchain */
1956 TRACE("Creating implicit swapchain\n");
1957 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1958 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1959 if (FAILED(hr))
1961 WARN("Failed to create implicit swapchain\n");
1962 goto err_out;
1965 This->NumberOfSwapChains = 1;
1966 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1967 if(!This->swapchains) {
1968 ERR("Out of memory!\n");
1969 goto err_out;
1971 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1972 return WINED3D_OK;
1974 err_out:
1975 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1976 return hr;
1979 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1981 IWineD3DResource_UnLoad(resource);
1982 IWineD3DResource_Release(resource);
1983 return WINED3D_OK;
1986 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1987 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1989 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1990 const struct wined3d_gl_info *gl_info;
1991 struct wined3d_context *context;
1992 int sampler;
1993 UINT i;
1994 TRACE("(%p)\n", This);
1996 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1998 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1999 * it was created. Thus make sure a context is active for the glDelete* calls
2001 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
2002 gl_info = context->gl_info;
2004 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2006 /* Unload resources */
2007 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2009 TRACE("Deleting high order patches\n");
2010 for(i = 0; i < PATCHMAP_SIZE; i++) {
2011 struct list *e1, *e2;
2012 struct WineD3DRectPatch *patch;
2013 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2014 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2015 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2019 /* Delete the palette conversion shader if it is around */
2020 if(This->paletteConversionShader) {
2021 ENTER_GL();
2022 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2023 LEAVE_GL();
2024 This->paletteConversionShader = 0;
2027 /* Delete the pbuffer context if there is any */
2028 if(This->pbufferContext) context_destroy(This, This->pbufferContext);
2030 /* Delete the mouse cursor texture */
2031 if(This->cursorTexture) {
2032 ENTER_GL();
2033 glDeleteTextures(1, &This->cursorTexture);
2034 LEAVE_GL();
2035 This->cursorTexture = 0;
2038 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2039 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2041 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2042 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2045 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2046 * private data, it might contain opengl pointers
2048 if(This->depth_blt_texture) {
2049 ENTER_GL();
2050 glDeleteTextures(1, &This->depth_blt_texture);
2051 LEAVE_GL();
2052 This->depth_blt_texture = 0;
2054 if (This->depth_blt_rb) {
2055 ENTER_GL();
2056 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2057 LEAVE_GL();
2058 This->depth_blt_rb = 0;
2059 This->depth_blt_rb_w = 0;
2060 This->depth_blt_rb_h = 0;
2063 /* Release the update stateblock */
2064 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2065 if(This->updateStateBlock != This->stateBlock)
2066 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2068 This->updateStateBlock = NULL;
2070 { /* because were not doing proper internal refcounts releasing the primary state block
2071 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2072 to set this->stateBlock = NULL; first */
2073 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2074 This->stateBlock = NULL;
2076 /* Release the stateblock */
2077 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2078 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2082 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2083 This->blitter->free_private(iface);
2084 This->frag_pipe->free_private(iface);
2085 This->shader_backend->shader_free_private(iface);
2087 /* Release the buffers (with sanity checks)*/
2088 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2089 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2090 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2091 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2093 This->stencilBufferTarget = NULL;
2095 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2096 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2097 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2099 TRACE("Setting rendertarget to NULL\n");
2100 This->render_targets[0] = NULL;
2102 if (This->auto_depth_stencil_buffer) {
2103 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
2105 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2107 This->auto_depth_stencil_buffer = NULL;
2110 context_release(context);
2112 for(i=0; i < This->NumberOfSwapChains; i++) {
2113 TRACE("Releasing the implicit swapchain %d\n", i);
2114 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2115 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2119 HeapFree(GetProcessHeap(), 0, This->swapchains);
2120 This->swapchains = NULL;
2121 This->NumberOfSwapChains = 0;
2123 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2124 HeapFree(GetProcessHeap(), 0, This->palettes);
2125 This->palettes = NULL;
2126 This->NumberOfPalettes = 0;
2128 HeapFree(GetProcessHeap(), 0, This->render_targets);
2129 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2130 This->render_targets = NULL;
2131 This->draw_buffers = NULL;
2133 This->d3d_initialized = FALSE;
2134 return WINED3D_OK;
2137 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2139 unsigned int i;
2141 for(i=0; i < This->NumberOfSwapChains; i++) {
2142 TRACE("Releasing the implicit swapchain %d\n", i);
2143 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2144 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2148 HeapFree(GetProcessHeap(), 0, This->swapchains);
2149 This->swapchains = NULL;
2150 This->NumberOfSwapChains = 0;
2151 return WINED3D_OK;
2154 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2155 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2156 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2158 * There is no way to deactivate thread safety once it is enabled.
2160 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2163 /*For now just store the flag(needed in case of ddraw) */
2164 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2166 return;
2169 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2170 const WINED3DDISPLAYMODE* pMode) {
2171 DEVMODEW devmode;
2172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2173 LONG ret;
2174 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
2175 RECT clip_rc;
2177 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2179 /* Resize the screen even without a window:
2180 * The app could have unset it with SetCooperativeLevel, but not called
2181 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2182 * but we don't have any hwnd
2185 memset(&devmode, 0, sizeof(devmode));
2186 devmode.dmSize = sizeof(devmode);
2187 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2188 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2189 devmode.dmPelsWidth = pMode->Width;
2190 devmode.dmPelsHeight = pMode->Height;
2192 devmode.dmDisplayFrequency = pMode->RefreshRate;
2193 if (pMode->RefreshRate != 0) {
2194 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2197 /* Only change the mode if necessary */
2198 if( (This->ddraw_width == pMode->Width) &&
2199 (This->ddraw_height == pMode->Height) &&
2200 (This->ddraw_format == pMode->Format) &&
2201 (pMode->RefreshRate == 0) ) {
2202 return WINED3D_OK;
2205 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2206 if (ret != DISP_CHANGE_SUCCESSFUL) {
2207 if(devmode.dmDisplayFrequency != 0) {
2208 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2209 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2210 devmode.dmDisplayFrequency = 0;
2211 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2213 if(ret != DISP_CHANGE_SUCCESSFUL) {
2214 return WINED3DERR_NOTAVAILABLE;
2218 /* Store the new values */
2219 This->ddraw_width = pMode->Width;
2220 This->ddraw_height = pMode->Height;
2221 This->ddraw_format = pMode->Format;
2223 /* And finally clip mouse to our screen */
2224 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2225 ClipCursor(&clip_rc);
2227 return WINED3D_OK;
2230 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2232 *ppD3D= This->wineD3D;
2233 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2234 IWineD3D_AddRef(*ppD3D);
2235 return WINED3D_OK;
2238 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2241 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2242 (This->adapter->TextureRam/(1024*1024)),
2243 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2244 /* return simulated texture memory left */
2245 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2248 /*****
2249 * Get / Set Stream Source
2250 *****/
2251 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2252 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2255 IWineD3DBuffer *oldSrc;
2257 if (StreamNumber >= MAX_STREAMS) {
2258 WARN("Stream out of range %d\n", StreamNumber);
2259 return WINED3DERR_INVALIDCALL;
2260 } else if(OffsetInBytes & 0x3) {
2261 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2262 return WINED3DERR_INVALIDCALL;
2265 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2266 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2268 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2270 if(oldSrc == pStreamData &&
2271 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2272 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2273 TRACE("Application is setting the old values over, nothing to do\n");
2274 return WINED3D_OK;
2277 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2278 if (pStreamData) {
2279 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2280 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2283 /* Handle recording of state blocks */
2284 if (This->isRecordingState) {
2285 TRACE("Recording... not performing anything\n");
2286 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2287 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2288 return WINED3D_OK;
2291 if (pStreamData != NULL) {
2292 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2293 IWineD3DBuffer_AddRef(pStreamData);
2295 if (oldSrc != NULL) {
2296 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2297 IWineD3DBuffer_Release(oldSrc);
2300 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2302 return WINED3D_OK;
2305 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2306 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2310 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2311 This->stateBlock->streamSource[StreamNumber],
2312 This->stateBlock->streamOffset[StreamNumber],
2313 This->stateBlock->streamStride[StreamNumber]);
2315 if (StreamNumber >= MAX_STREAMS) {
2316 WARN("Stream out of range %d\n", StreamNumber);
2317 return WINED3DERR_INVALIDCALL;
2319 *pStream = This->stateBlock->streamSource[StreamNumber];
2320 *pStride = This->stateBlock->streamStride[StreamNumber];
2321 if (pOffset) {
2322 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2325 if (*pStream != NULL) {
2326 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2328 return WINED3D_OK;
2331 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2333 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2334 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2336 /* Verify input at least in d3d9 this is invalid*/
2337 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2338 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2339 return WINED3DERR_INVALIDCALL;
2341 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2342 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2343 return WINED3DERR_INVALIDCALL;
2345 if( Divider == 0 ){
2346 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2347 return WINED3DERR_INVALIDCALL;
2350 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2351 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2353 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2354 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2356 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2357 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2358 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2361 return WINED3D_OK;
2364 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2367 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2368 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2370 TRACE("(%p) : returning %d\n", This, *Divider);
2372 return WINED3D_OK;
2375 /*****
2376 * Get / Set & Multiply Transform
2377 *****/
2378 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2381 /* Most of this routine, comments included copied from ddraw tree initially: */
2382 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2384 /* Handle recording of state blocks */
2385 if (This->isRecordingState) {
2386 TRACE("Recording... not performing anything\n");
2387 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2388 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2389 return WINED3D_OK;
2393 * If the new matrix is the same as the current one,
2394 * we cut off any further processing. this seems to be a reasonable
2395 * optimization because as was noticed, some apps (warcraft3 for example)
2396 * tend towards setting the same matrix repeatedly for some reason.
2398 * From here on we assume that the new matrix is different, wherever it matters.
2400 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2401 TRACE("The app is setting the same matrix over again\n");
2402 return WINED3D_OK;
2403 } else {
2404 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2408 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2409 where ViewMat = Camera space, WorldMat = world space.
2411 In OpenGL, camera and world space is combined into GL_MODELVIEW
2412 matrix. The Projection matrix stay projection matrix.
2415 /* Capture the times we can just ignore the change for now */
2416 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2417 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2418 /* Handled by the state manager */
2421 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2422 return WINED3D_OK;
2425 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2427 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2428 *pMatrix = This->stateBlock->transforms[State];
2429 return WINED3D_OK;
2432 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2433 const WINED3DMATRIX *mat = NULL;
2434 WINED3DMATRIX temp;
2436 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2437 * below means it will be recorded in a state block change, but it
2438 * works regardless where it is recorded.
2439 * If this is found to be wrong, change to StateBlock.
2441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2442 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2444 if (State <= HIGHEST_TRANSFORMSTATE)
2446 mat = &This->updateStateBlock->transforms[State];
2447 } else {
2448 FIXME("Unhandled transform state!!\n");
2451 multiply_matrix(&temp, mat, pMatrix);
2453 /* Apply change via set transform - will reapply to eg. lights this way */
2454 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2457 /*****
2458 * Get / Set Light
2459 *****/
2460 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2461 you can reference any indexes you want as long as that number max are enabled at any
2462 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2463 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2464 but when recording, just build a chain pretty much of commands to be replayed. */
2466 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2467 float rho;
2468 struct wined3d_light_info *object = NULL;
2469 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2470 struct list *e;
2472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2473 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2475 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2476 * the gl driver.
2478 if(!pLight) {
2479 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2480 return WINED3DERR_INVALIDCALL;
2483 switch(pLight->Type) {
2484 case WINED3DLIGHT_POINT:
2485 case WINED3DLIGHT_SPOT:
2486 case WINED3DLIGHT_PARALLELPOINT:
2487 case WINED3DLIGHT_GLSPOT:
2488 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2489 * most wanted
2491 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2493 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2494 return WINED3DERR_INVALIDCALL;
2496 break;
2498 case WINED3DLIGHT_DIRECTIONAL:
2499 /* Ignores attenuation */
2500 break;
2502 default:
2503 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2504 return WINED3DERR_INVALIDCALL;
2507 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2509 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2510 if(object->OriginalIndex == Index) break;
2511 object = NULL;
2514 if(!object) {
2515 TRACE("Adding new light\n");
2516 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2517 if(!object) {
2518 ERR("Out of memory error when allocating a light\n");
2519 return E_OUTOFMEMORY;
2521 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2522 object->glIndex = -1;
2523 object->OriginalIndex = Index;
2526 /* Initialize the object */
2527 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,
2528 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2529 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2530 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2531 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2532 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2533 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2535 /* Save away the information */
2536 object->OriginalParms = *pLight;
2538 switch (pLight->Type) {
2539 case WINED3DLIGHT_POINT:
2540 /* Position */
2541 object->lightPosn[0] = pLight->Position.x;
2542 object->lightPosn[1] = pLight->Position.y;
2543 object->lightPosn[2] = pLight->Position.z;
2544 object->lightPosn[3] = 1.0f;
2545 object->cutoff = 180.0f;
2546 /* FIXME: Range */
2547 break;
2549 case WINED3DLIGHT_DIRECTIONAL:
2550 /* Direction */
2551 object->lightPosn[0] = -pLight->Direction.x;
2552 object->lightPosn[1] = -pLight->Direction.y;
2553 object->lightPosn[2] = -pLight->Direction.z;
2554 object->lightPosn[3] = 0.0f;
2555 object->exponent = 0.0f;
2556 object->cutoff = 180.0f;
2557 break;
2559 case WINED3DLIGHT_SPOT:
2560 /* Position */
2561 object->lightPosn[0] = pLight->Position.x;
2562 object->lightPosn[1] = pLight->Position.y;
2563 object->lightPosn[2] = pLight->Position.z;
2564 object->lightPosn[3] = 1.0f;
2566 /* Direction */
2567 object->lightDirn[0] = pLight->Direction.x;
2568 object->lightDirn[1] = pLight->Direction.y;
2569 object->lightDirn[2] = pLight->Direction.z;
2570 object->lightDirn[3] = 1.0f;
2573 * opengl-ish and d3d-ish spot lights use too different models for the
2574 * light "intensity" as a function of the angle towards the main light direction,
2575 * so we only can approximate very roughly.
2576 * however spot lights are rather rarely used in games (if ever used at all).
2577 * furthermore if still used, probably nobody pays attention to such details.
2579 if (pLight->Falloff == 0) {
2580 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2581 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2582 * will always be 1.0 for both of them, and we don't have to care for the
2583 * rest of the rather complex calculation
2585 object->exponent = 0.0f;
2586 } else {
2587 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2588 if (rho < 0.0001f) rho = 0.0001f;
2589 object->exponent = -0.3f/logf(cosf(rho/2));
2591 if (object->exponent > 128.0f)
2593 object->exponent = 128.0f;
2595 object->cutoff = pLight->Phi*90/M_PI;
2597 /* FIXME: Range */
2598 break;
2600 default:
2601 FIXME("Unrecognized light type %d\n", pLight->Type);
2604 /* Update the live definitions if the light is currently assigned a glIndex */
2605 if (object->glIndex != -1 && !This->isRecordingState) {
2606 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2608 return WINED3D_OK;
2611 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2613 struct wined3d_light_info *lightInfo = NULL;
2614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2615 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2616 struct list *e;
2617 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2619 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2621 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2622 if(lightInfo->OriginalIndex == Index) break;
2623 lightInfo = NULL;
2626 if (lightInfo == NULL) {
2627 TRACE("Light information requested but light not defined\n");
2628 return WINED3DERR_INVALIDCALL;
2631 *pLight = lightInfo->OriginalParms;
2632 return WINED3D_OK;
2635 /*****
2636 * Get / Set Light Enable
2637 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2638 *****/
2639 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2641 struct wined3d_light_info *lightInfo = NULL;
2642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2643 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2644 struct list *e;
2645 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2647 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2649 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2650 if(lightInfo->OriginalIndex == Index) break;
2651 lightInfo = NULL;
2653 TRACE("Found light: %p\n", lightInfo);
2655 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2656 if (lightInfo == NULL) {
2658 TRACE("Light enabled requested but light not defined, so defining one!\n");
2659 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2661 /* Search for it again! Should be fairly quick as near head of list */
2662 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2664 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2665 if(lightInfo->OriginalIndex == Index) break;
2666 lightInfo = NULL;
2668 if (lightInfo == NULL) {
2669 FIXME("Adding default lights has failed dismally\n");
2670 return WINED3DERR_INVALIDCALL;
2674 if(!Enable) {
2675 if(lightInfo->glIndex != -1) {
2676 if(!This->isRecordingState) {
2677 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2680 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2681 lightInfo->glIndex = -1;
2682 } else {
2683 TRACE("Light already disabled, nothing to do\n");
2685 lightInfo->enabled = FALSE;
2686 } else {
2687 lightInfo->enabled = TRUE;
2688 if (lightInfo->glIndex != -1) {
2689 /* nop */
2690 TRACE("Nothing to do as light was enabled\n");
2691 } else {
2692 int i;
2693 /* Find a free gl light */
2694 for(i = 0; i < This->maxConcurrentLights; i++) {
2695 if(This->updateStateBlock->activeLights[i] == NULL) {
2696 This->updateStateBlock->activeLights[i] = lightInfo;
2697 lightInfo->glIndex = i;
2698 break;
2701 if(lightInfo->glIndex == -1) {
2702 /* Our tests show that Windows returns D3D_OK in this situation, even with
2703 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2704 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2705 * as well for those lights.
2707 * TODO: Test how this affects rendering
2709 WARN("Too many concurrently active lights\n");
2710 return WINED3D_OK;
2713 /* i == lightInfo->glIndex */
2714 if(!This->isRecordingState) {
2715 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2720 return WINED3D_OK;
2723 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2725 struct wined3d_light_info *lightInfo = NULL;
2726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2727 struct list *e;
2728 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2729 TRACE("(%p) : for idx(%d)\n", This, Index);
2731 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2733 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2734 if(lightInfo->OriginalIndex == Index) break;
2735 lightInfo = NULL;
2738 if (lightInfo == NULL) {
2739 TRACE("Light enabled state requested but light not defined\n");
2740 return WINED3DERR_INVALIDCALL;
2742 /* true is 128 according to SetLightEnable */
2743 *pEnable = lightInfo->enabled ? 128 : 0;
2744 return WINED3D_OK;
2747 /*****
2748 * Get / Set Clip Planes
2749 *****/
2750 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2752 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2754 /* Validate Index */
2755 if (Index >= This->adapter->gl_info.limits.clipplanes)
2757 TRACE("Application has requested clipplane this device doesn't support\n");
2758 return WINED3DERR_INVALIDCALL;
2761 This->updateStateBlock->changed.clipplane |= 1 << Index;
2763 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2764 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2765 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2766 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2767 TRACE("Application is setting old values over, nothing to do\n");
2768 return WINED3D_OK;
2771 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2772 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2773 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2774 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2776 /* Handle recording of state blocks */
2777 if (This->isRecordingState) {
2778 TRACE("Recording... not performing anything\n");
2779 return WINED3D_OK;
2782 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2784 return WINED3D_OK;
2787 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2788 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2789 TRACE("(%p) : for idx %d\n", This, Index);
2791 /* Validate Index */
2792 if (Index >= This->adapter->gl_info.limits.clipplanes)
2794 TRACE("Application has requested clipplane this device doesn't support\n");
2795 return WINED3DERR_INVALIDCALL;
2798 pPlane[0] = This->stateBlock->clipplane[Index][0];
2799 pPlane[1] = This->stateBlock->clipplane[Index][1];
2800 pPlane[2] = This->stateBlock->clipplane[Index][2];
2801 pPlane[3] = This->stateBlock->clipplane[Index][3];
2802 return WINED3D_OK;
2805 /*****
2806 * Get / Set Clip Plane Status
2807 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2808 *****/
2809 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2811 FIXME("(%p) : stub\n", This);
2812 if (NULL == pClipStatus) {
2813 return WINED3DERR_INVALIDCALL;
2815 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2816 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2817 return WINED3D_OK;
2820 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2822 FIXME("(%p) : stub\n", This);
2823 if (NULL == pClipStatus) {
2824 return WINED3DERR_INVALIDCALL;
2826 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2827 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2828 return WINED3D_OK;
2831 /*****
2832 * Get / Set Material
2833 *****/
2834 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2837 This->updateStateBlock->changed.material = TRUE;
2838 This->updateStateBlock->material = *pMaterial;
2840 /* Handle recording of state blocks */
2841 if (This->isRecordingState) {
2842 TRACE("Recording... not performing anything\n");
2843 return WINED3D_OK;
2846 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2847 return WINED3D_OK;
2850 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2852 *pMaterial = This->updateStateBlock->material;
2853 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2854 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2855 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2856 pMaterial->Ambient.b, pMaterial->Ambient.a);
2857 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2858 pMaterial->Specular.b, pMaterial->Specular.a);
2859 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2860 pMaterial->Emissive.b, pMaterial->Emissive.a);
2861 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2863 return WINED3D_OK;
2866 /*****
2867 * Get / Set Indices
2868 *****/
2869 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2870 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2873 IWineD3DBuffer *oldIdxs;
2875 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2876 oldIdxs = This->updateStateBlock->pIndexData;
2878 This->updateStateBlock->changed.indices = TRUE;
2879 This->updateStateBlock->pIndexData = pIndexData;
2880 This->updateStateBlock->IndexFmt = fmt;
2882 /* Handle recording of state blocks */
2883 if (This->isRecordingState) {
2884 TRACE("Recording... not performing anything\n");
2885 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2886 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2887 return WINED3D_OK;
2890 if(oldIdxs != pIndexData) {
2891 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2892 if(pIndexData) {
2893 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2894 IWineD3DBuffer_AddRef(pIndexData);
2896 if(oldIdxs) {
2897 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2898 IWineD3DBuffer_Release(oldIdxs);
2902 return WINED3D_OK;
2905 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2907 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2909 *ppIndexData = This->stateBlock->pIndexData;
2911 /* up ref count on ppindexdata */
2912 if (*ppIndexData) {
2913 IWineD3DBuffer_AddRef(*ppIndexData);
2914 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2915 }else{
2916 TRACE("(%p) No index data set\n", This);
2918 TRACE("Returning %p\n", *ppIndexData);
2920 return WINED3D_OK;
2923 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2924 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2926 TRACE("(%p)->(%d)\n", This, BaseIndex);
2928 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2929 TRACE("Application is setting the old value over, nothing to do\n");
2930 return WINED3D_OK;
2933 This->updateStateBlock->baseVertexIndex = BaseIndex;
2935 if (This->isRecordingState) {
2936 TRACE("Recording... not performing anything\n");
2937 return WINED3D_OK;
2939 /* The base vertex index affects the stream sources */
2940 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2941 return WINED3D_OK;
2944 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2946 TRACE("(%p) : base_index %p\n", This, base_index);
2948 *base_index = This->stateBlock->baseVertexIndex;
2950 TRACE("Returning %u\n", *base_index);
2952 return WINED3D_OK;
2955 /*****
2956 * Get / Set Viewports
2957 *****/
2958 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2961 TRACE("(%p)\n", This);
2962 This->updateStateBlock->changed.viewport = TRUE;
2963 This->updateStateBlock->viewport = *pViewport;
2965 /* Handle recording of state blocks */
2966 if (This->isRecordingState) {
2967 TRACE("Recording... not performing anything\n");
2968 return WINED3D_OK;
2971 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2972 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2974 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2975 return WINED3D_OK;
2979 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2981 TRACE("(%p)\n", This);
2982 *pViewport = This->stateBlock->viewport;
2983 return WINED3D_OK;
2986 /*****
2987 * Get / Set Render States
2988 * TODO: Verify against dx9 definitions
2989 *****/
2990 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2992 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2993 DWORD oldValue = This->stateBlock->renderState[State];
2995 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2997 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2998 This->updateStateBlock->renderState[State] = Value;
3000 /* Handle recording of state blocks */
3001 if (This->isRecordingState) {
3002 TRACE("Recording... not performing anything\n");
3003 return WINED3D_OK;
3006 /* Compared here and not before the assignment to allow proper stateblock recording */
3007 if(Value == oldValue) {
3008 TRACE("Application is setting the old value over, nothing to do\n");
3009 } else {
3010 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3013 return WINED3D_OK;
3016 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3018 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3019 *pValue = This->stateBlock->renderState[State];
3020 return WINED3D_OK;
3023 /*****
3024 * Get / Set Sampler States
3025 * TODO: Verify against dx9 definitions
3026 *****/
3028 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3030 DWORD oldValue;
3032 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3033 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3035 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3036 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3039 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3040 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3041 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3044 * SetSampler is designed to allow for more than the standard up to 8 textures
3045 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3046 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3048 * http://developer.nvidia.com/object/General_FAQ.html#t6
3050 * There are two new settings for GForce
3051 * the sampler one:
3052 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3053 * and the texture one:
3054 * GL_MAX_TEXTURE_COORDS_ARB.
3055 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3056 ******************/
3058 oldValue = This->stateBlock->samplerState[Sampler][Type];
3059 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3060 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3062 /* Handle recording of state blocks */
3063 if (This->isRecordingState) {
3064 TRACE("Recording... not performing anything\n");
3065 return WINED3D_OK;
3068 if(oldValue == Value) {
3069 TRACE("Application is setting the old value over, nothing to do\n");
3070 return WINED3D_OK;
3073 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3075 return WINED3D_OK;
3078 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3081 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3082 This, Sampler, debug_d3dsamplerstate(Type), Type);
3084 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3085 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3088 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3089 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3090 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3092 *Value = This->stateBlock->samplerState[Sampler][Type];
3093 TRACE("(%p) : Returning %#x\n", This, *Value);
3095 return WINED3D_OK;
3098 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3101 This->updateStateBlock->changed.scissorRect = TRUE;
3102 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3103 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3104 return WINED3D_OK;
3106 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3108 if(This->isRecordingState) {
3109 TRACE("Recording... not performing anything\n");
3110 return WINED3D_OK;
3113 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3115 return WINED3D_OK;
3118 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3121 *pRect = This->updateStateBlock->scissorRect;
3122 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3123 return WINED3D_OK;
3126 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3128 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3130 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3132 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3133 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3135 This->updateStateBlock->vertexDecl = pDecl;
3136 This->updateStateBlock->changed.vertexDecl = TRUE;
3138 if (This->isRecordingState) {
3139 TRACE("Recording... not performing anything\n");
3140 return WINED3D_OK;
3141 } else if(pDecl == oldDecl) {
3142 /* Checked after the assignment to allow proper stateblock recording */
3143 TRACE("Application is setting the old declaration over, nothing to do\n");
3144 return WINED3D_OK;
3147 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3148 return WINED3D_OK;
3151 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3154 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3156 *ppDecl = This->stateBlock->vertexDecl;
3157 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3158 return WINED3D_OK;
3161 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3163 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3165 This->updateStateBlock->vertexShader = pShader;
3166 This->updateStateBlock->changed.vertexShader = TRUE;
3168 if (This->isRecordingState) {
3169 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3170 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3171 TRACE("Recording... not performing anything\n");
3172 return WINED3D_OK;
3173 } else if(oldShader == pShader) {
3174 /* Checked here to allow proper stateblock recording */
3175 TRACE("App is setting the old shader over, nothing to do\n");
3176 return WINED3D_OK;
3179 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3180 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3181 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3183 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3185 return WINED3D_OK;
3188 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3191 if (NULL == ppShader) {
3192 return WINED3DERR_INVALIDCALL;
3194 *ppShader = This->stateBlock->vertexShader;
3195 if( NULL != *ppShader)
3196 IWineD3DVertexShader_AddRef(*ppShader);
3198 TRACE("(%p) : returning %p\n", This, *ppShader);
3199 return WINED3D_OK;
3202 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3203 IWineD3DDevice *iface,
3204 UINT start,
3205 CONST BOOL *srcData,
3206 UINT count) {
3208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3209 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3211 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3212 iface, srcData, start, count);
3214 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3216 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3217 for (i = 0; i < cnt; i++)
3218 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3220 for (i = start; i < cnt + start; ++i) {
3221 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3224 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3226 return WINED3D_OK;
3229 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3230 IWineD3DDevice *iface,
3231 UINT start,
3232 BOOL *dstData,
3233 UINT count) {
3235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3236 int cnt = min(count, MAX_CONST_B - start);
3238 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3239 iface, dstData, start, count);
3241 if (dstData == NULL || cnt < 0)
3242 return WINED3DERR_INVALIDCALL;
3244 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3245 return WINED3D_OK;
3248 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3249 IWineD3DDevice *iface,
3250 UINT start,
3251 CONST int *srcData,
3252 UINT count) {
3254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3255 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3257 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3258 iface, srcData, start, count);
3260 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3262 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3263 for (i = 0; i < cnt; i++)
3264 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3265 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3267 for (i = start; i < cnt + start; ++i) {
3268 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3271 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3273 return WINED3D_OK;
3276 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3277 IWineD3DDevice *iface,
3278 UINT start,
3279 int *dstData,
3280 UINT count) {
3282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3283 int cnt = min(count, MAX_CONST_I - start);
3285 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3286 iface, dstData, start, count);
3288 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3289 return WINED3DERR_INVALIDCALL;
3291 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3292 return WINED3D_OK;
3295 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3296 IWineD3DDevice *iface,
3297 UINT start,
3298 CONST float *srcData,
3299 UINT count) {
3301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3302 UINT i;
3304 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3305 iface, srcData, start, count);
3307 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3308 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3309 return WINED3DERR_INVALIDCALL;
3311 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3312 if(TRACE_ON(d3d)) {
3313 for (i = 0; i < count; i++)
3314 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3315 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3318 if (!This->isRecordingState)
3320 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3321 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3324 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3325 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3327 return WINED3D_OK;
3330 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3331 IWineD3DDevice *iface,
3332 UINT start,
3333 float *dstData,
3334 UINT count) {
3336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3337 int cnt = min(count, This->d3d_vshader_constantF - start);
3339 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3340 iface, dstData, start, count);
3342 if (dstData == NULL || cnt < 0)
3343 return WINED3DERR_INVALIDCALL;
3345 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3346 return WINED3D_OK;
3349 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3350 DWORD i;
3351 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3353 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3357 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3359 DWORD i = This->rev_tex_unit_map[unit];
3360 DWORD j = This->texUnitMap[stage];
3362 This->texUnitMap[stage] = unit;
3363 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3365 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3368 This->rev_tex_unit_map[unit] = stage;
3369 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3371 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3375 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3376 int i;
3378 This->fixed_function_usage_map = 0;
3379 for (i = 0; i < MAX_TEXTURES; ++i) {
3380 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3381 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3382 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3383 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3384 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3385 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3386 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3387 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3389 if (color_op == WINED3DTOP_DISABLE) {
3390 /* Not used, and disable higher stages */
3391 break;
3394 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3395 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3396 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3397 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3398 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3399 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3400 This->fixed_function_usage_map |= (1 << i);
3403 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3404 This->fixed_function_usage_map |= (1 << (i + 1));
3409 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3410 unsigned int i, tex;
3411 WORD ffu_map;
3413 device_update_fixed_function_usage_map(This);
3414 ffu_map = This->fixed_function_usage_map;
3416 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3417 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3418 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3420 if (!(ffu_map & 1)) continue;
3422 if (This->texUnitMap[i] != i) {
3423 device_map_stage(This, i, i);
3424 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3425 markTextureStagesDirty(This, i);
3428 return;
3431 /* Now work out the mapping */
3432 tex = 0;
3433 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3435 if (!(ffu_map & 1)) continue;
3437 if (This->texUnitMap[i] != tex) {
3438 device_map_stage(This, i, tex);
3439 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3440 markTextureStagesDirty(This, i);
3443 ++tex;
3447 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3448 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3449 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3450 unsigned int i;
3452 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3453 if (sampler_type[i] && This->texUnitMap[i] != i)
3455 device_map_stage(This, i, i);
3456 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3457 if (i < MAX_TEXTURES) {
3458 markTextureStagesDirty(This, i);
3464 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3465 const DWORD *vshader_sampler_tokens, DWORD unit)
3467 DWORD current_mapping = This->rev_tex_unit_map[unit];
3469 /* Not currently used */
3470 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3472 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3473 /* Used by a fragment sampler */
3475 if (!pshader_sampler_tokens) {
3476 /* No pixel shader, check fixed function */
3477 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3480 /* Pixel shader, check the shader's sampler map */
3481 return !pshader_sampler_tokens[current_mapping];
3484 /* Used by a vertex sampler */
3485 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3488 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3489 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3490 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3491 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3492 int start = min(MAX_COMBINED_SAMPLERS, This->adapter->gl_info.limits.combined_samplers) - 1;
3493 int i;
3495 if (ps) {
3496 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3498 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3499 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3500 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3503 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3504 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3505 if (vshader_sampler_type[i])
3507 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3509 /* Already mapped somewhere */
3510 continue;
3513 while (start >= 0) {
3514 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3516 device_map_stage(This, vsampler_idx, start);
3517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3519 --start;
3520 break;
3523 --start;
3529 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3530 BOOL vs = use_vs(This->stateBlock);
3531 BOOL ps = use_ps(This->stateBlock);
3533 * Rules are:
3534 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3535 * that would be really messy and require shader recompilation
3536 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3537 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3539 if (ps) {
3540 device_map_psamplers(This);
3541 } else {
3542 device_map_fixed_function_samplers(This);
3545 if (vs) {
3546 device_map_vsamplers(This, ps);
3550 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3552 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3553 This->updateStateBlock->pixelShader = pShader;
3554 This->updateStateBlock->changed.pixelShader = TRUE;
3556 /* Handle recording of state blocks */
3557 if (This->isRecordingState) {
3558 TRACE("Recording... not performing anything\n");
3561 if (This->isRecordingState) {
3562 TRACE("Recording... not performing anything\n");
3563 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3564 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3565 return WINED3D_OK;
3568 if(pShader == oldShader) {
3569 TRACE("App is setting the old pixel shader over, nothing to do\n");
3570 return WINED3D_OK;
3573 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3574 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3576 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3577 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3579 return WINED3D_OK;
3582 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3585 if (NULL == ppShader) {
3586 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3587 return WINED3DERR_INVALIDCALL;
3590 *ppShader = This->stateBlock->pixelShader;
3591 if (NULL != *ppShader) {
3592 IWineD3DPixelShader_AddRef(*ppShader);
3594 TRACE("(%p) : returning %p\n", This, *ppShader);
3595 return WINED3D_OK;
3598 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3599 IWineD3DDevice *iface,
3600 UINT start,
3601 CONST BOOL *srcData,
3602 UINT count) {
3604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3605 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3607 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3608 iface, srcData, start, count);
3610 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3612 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3613 for (i = 0; i < cnt; i++)
3614 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3616 for (i = start; i < cnt + start; ++i) {
3617 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3620 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3622 return WINED3D_OK;
3625 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3626 IWineD3DDevice *iface,
3627 UINT start,
3628 BOOL *dstData,
3629 UINT count) {
3631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3632 int cnt = min(count, MAX_CONST_B - start);
3634 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3635 iface, dstData, start, count);
3637 if (dstData == NULL || cnt < 0)
3638 return WINED3DERR_INVALIDCALL;
3640 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3641 return WINED3D_OK;
3644 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3645 IWineD3DDevice *iface,
3646 UINT start,
3647 CONST int *srcData,
3648 UINT count) {
3650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3651 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3653 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3654 iface, srcData, start, count);
3656 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3658 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3659 for (i = 0; i < cnt; i++)
3660 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3661 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3663 for (i = start; i < cnt + start; ++i) {
3664 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3667 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3669 return WINED3D_OK;
3672 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3673 IWineD3DDevice *iface,
3674 UINT start,
3675 int *dstData,
3676 UINT count) {
3678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3679 int cnt = min(count, MAX_CONST_I - start);
3681 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3682 iface, dstData, start, count);
3684 if (dstData == NULL || cnt < 0)
3685 return WINED3DERR_INVALIDCALL;
3687 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3688 return WINED3D_OK;
3691 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3692 IWineD3DDevice *iface,
3693 UINT start,
3694 CONST float *srcData,
3695 UINT count) {
3697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3698 UINT i;
3700 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3701 iface, srcData, start, count);
3703 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3704 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3705 return WINED3DERR_INVALIDCALL;
3707 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3708 if(TRACE_ON(d3d)) {
3709 for (i = 0; i < count; i++)
3710 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3711 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3714 if (!This->isRecordingState)
3716 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3720 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3721 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3723 return WINED3D_OK;
3726 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3727 IWineD3DDevice *iface,
3728 UINT start,
3729 float *dstData,
3730 UINT count) {
3732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3733 int cnt = min(count, This->d3d_pshader_constantF - start);
3735 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3736 iface, dstData, start, count);
3738 if (dstData == NULL || cnt < 0)
3739 return WINED3DERR_INVALIDCALL;
3741 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3742 return WINED3D_OK;
3745 /* Context activation is done by the caller. */
3746 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3747 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3748 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3749 DWORD DestFVF)
3751 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3752 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3753 unsigned int i;
3754 WINED3DVIEWPORT vp;
3755 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3756 BOOL doClip;
3757 DWORD numTextures;
3759 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3761 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3764 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3766 ERR("Source has no position mask\n");
3767 return WINED3DERR_INVALIDCALL;
3770 /* We might access VBOs from this code, so hold the lock */
3771 ENTER_GL();
3773 if (dest->resource.allocatedMemory == NULL) {
3774 buffer_get_sysmem(dest);
3777 /* Get a pointer into the destination vbo(create one if none exists) and
3778 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3780 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3782 dest->flags |= WINED3D_BUFFER_CREATEBO;
3783 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3786 if (dest->buffer_object)
3788 unsigned char extrabytes = 0;
3789 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3790 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3791 * this may write 4 extra bytes beyond the area that should be written
3793 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3794 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3795 if(!dest_conv_addr) {
3796 ERR("Out of memory\n");
3797 /* Continue without storing converted vertices */
3799 dest_conv = dest_conv_addr;
3802 /* Should I clip?
3803 * a) WINED3DRS_CLIPPING is enabled
3804 * b) WINED3DVOP_CLIP is passed
3806 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3807 static BOOL warned = FALSE;
3809 * The clipping code is not quite correct. Some things need
3810 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3811 * so disable clipping for now.
3812 * (The graphics in Half-Life are broken, and my processvertices
3813 * test crashes with IDirect3DDevice3)
3814 doClip = TRUE;
3816 doClip = FALSE;
3817 if(!warned) {
3818 warned = TRUE;
3819 FIXME("Clipping is broken and disabled for now\n");
3821 } else doClip = FALSE;
3822 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3824 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3825 WINED3DTS_VIEW,
3826 &view_mat);
3827 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3828 WINED3DTS_PROJECTION,
3829 &proj_mat);
3830 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3831 WINED3DTS_WORLDMATRIX(0),
3832 &world_mat);
3834 TRACE("View mat:\n");
3835 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);
3836 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);
3837 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);
3838 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);
3840 TRACE("Proj mat:\n");
3841 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);
3842 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);
3843 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);
3844 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);
3846 TRACE("World mat:\n");
3847 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);
3848 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);
3849 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);
3850 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);
3852 /* Get the viewport */
3853 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3854 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3855 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3857 multiply_matrix(&mat,&view_mat,&world_mat);
3858 multiply_matrix(&mat,&proj_mat,&mat);
3860 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3862 for (i = 0; i < dwCount; i+= 1) {
3863 unsigned int tex_index;
3865 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3866 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3867 /* The position first */
3868 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3869 const float *p = (const float *)(element->data + i * element->stride);
3870 float x, y, z, rhw;
3871 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3873 /* Multiplication with world, view and projection matrix */
3874 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);
3875 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);
3876 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);
3877 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);
3879 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3881 /* WARNING: The following things are taken from d3d7 and were not yet checked
3882 * against d3d8 or d3d9!
3885 /* Clipping conditions: From msdn
3887 * A vertex is clipped if it does not match the following requirements
3888 * -rhw < x <= rhw
3889 * -rhw < y <= rhw
3890 * 0 < z <= rhw
3891 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3893 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3894 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3898 if( !doClip ||
3899 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3900 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3901 ( rhw > eps ) ) ) {
3903 /* "Normal" viewport transformation (not clipped)
3904 * 1) The values are divided by rhw
3905 * 2) The y axis is negative, so multiply it with -1
3906 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3907 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3908 * 4) Multiply x with Width/2 and add Width/2
3909 * 5) The same for the height
3910 * 6) Add the viewpoint X and Y to the 2D coordinates and
3911 * The minimum Z value to z
3912 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3914 * Well, basically it's simply a linear transformation into viewport
3915 * coordinates
3918 x /= rhw;
3919 y /= rhw;
3920 z /= rhw;
3922 y *= -1;
3924 x *= vp.Width / 2;
3925 y *= vp.Height / 2;
3926 z *= vp.MaxZ - vp.MinZ;
3928 x += vp.Width / 2 + vp.X;
3929 y += vp.Height / 2 + vp.Y;
3930 z += vp.MinZ;
3932 rhw = 1 / rhw;
3933 } else {
3934 /* That vertex got clipped
3935 * Contrary to OpenGL it is not dropped completely, it just
3936 * undergoes a different calculation.
3938 TRACE("Vertex got clipped\n");
3939 x += rhw;
3940 y += rhw;
3942 x /= 2;
3943 y /= 2;
3945 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3946 * outside of the main vertex buffer memory. That needs some more
3947 * investigation...
3951 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3954 ( (float *) dest_ptr)[0] = x;
3955 ( (float *) dest_ptr)[1] = y;
3956 ( (float *) dest_ptr)[2] = z;
3957 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3959 dest_ptr += 3 * sizeof(float);
3961 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3962 dest_ptr += sizeof(float);
3965 if(dest_conv) {
3966 float w = 1 / rhw;
3967 ( (float *) dest_conv)[0] = x * w;
3968 ( (float *) dest_conv)[1] = y * w;
3969 ( (float *) dest_conv)[2] = z * w;
3970 ( (float *) dest_conv)[3] = w;
3972 dest_conv += 3 * sizeof(float);
3974 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3975 dest_conv += sizeof(float);
3979 if (DestFVF & WINED3DFVF_PSIZE) {
3980 dest_ptr += sizeof(DWORD);
3981 if(dest_conv) dest_conv += sizeof(DWORD);
3983 if (DestFVF & WINED3DFVF_NORMAL) {
3984 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3985 const float *normal = (const float *)(element->data + i * element->stride);
3986 /* AFAIK this should go into the lighting information */
3987 FIXME("Didn't expect the destination to have a normal\n");
3988 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3989 if(dest_conv) {
3990 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3994 if (DestFVF & WINED3DFVF_DIFFUSE) {
3995 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3996 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3997 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3999 static BOOL warned = FALSE;
4001 if(!warned) {
4002 ERR("No diffuse color in source, but destination has one\n");
4003 warned = TRUE;
4006 *( (DWORD *) dest_ptr) = 0xffffffff;
4007 dest_ptr += sizeof(DWORD);
4009 if(dest_conv) {
4010 *( (DWORD *) dest_conv) = 0xffffffff;
4011 dest_conv += sizeof(DWORD);
4014 else {
4015 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4016 if(dest_conv) {
4017 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4018 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4019 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4020 dest_conv += sizeof(DWORD);
4025 if (DestFVF & WINED3DFVF_SPECULAR)
4027 /* What's the color value in the feedback buffer? */
4028 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4029 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4030 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4032 static BOOL warned = FALSE;
4034 if(!warned) {
4035 ERR("No specular color in source, but destination has one\n");
4036 warned = TRUE;
4039 *( (DWORD *) dest_ptr) = 0xFF000000;
4040 dest_ptr += sizeof(DWORD);
4042 if(dest_conv) {
4043 *( (DWORD *) dest_conv) = 0xFF000000;
4044 dest_conv += sizeof(DWORD);
4047 else {
4048 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4049 if(dest_conv) {
4050 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4051 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4052 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4053 dest_conv += sizeof(DWORD);
4058 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4059 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4060 const float *tex_coord = (const float *)(element->data + i * element->stride);
4061 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4063 ERR("No source texture, but destination requests one\n");
4064 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4065 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4067 else {
4068 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4069 if(dest_conv) {
4070 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4076 if(dest_conv) {
4077 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4078 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4079 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4080 dwCount * get_flexible_vertex_size(DestFVF),
4081 dest_conv_addr));
4082 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4083 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4086 LEAVE_GL();
4088 return WINED3D_OK;
4090 #undef copy_and_next
4092 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4093 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4094 DWORD DestFVF)
4096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4097 struct wined3d_stream_info stream_info;
4098 struct wined3d_context *context;
4099 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4100 HRESULT hr;
4102 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4104 if(pVertexDecl) {
4105 ERR("Output vertex declaration not implemented yet\n");
4108 /* Need any context to write to the vbo. */
4109 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4111 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4112 * control the streamIsUP flag, thus restore it afterwards.
4114 This->stateBlock->streamIsUP = FALSE;
4115 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4116 This->stateBlock->streamIsUP = streamWasUP;
4118 if(vbo || SrcStartIndex) {
4119 unsigned int i;
4120 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4121 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4123 * Also get the start index in, but only loop over all elements if there's something to add at all.
4125 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4127 struct wined3d_stream_info_element *e;
4129 if (!(stream_info.use_map & (1 << i))) continue;
4131 e = &stream_info.elements[i];
4132 if (e->buffer_object)
4134 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4135 e->buffer_object = 0;
4136 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4137 ENTER_GL();
4138 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4139 vb->buffer_object = 0;
4140 LEAVE_GL();
4142 if (e->data) e->data += e->stride * SrcStartIndex;
4146 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4147 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4149 context_release(context);
4151 return hr;
4154 /*****
4155 * Get / Set Texture Stage States
4156 * TODO: Verify against dx9 definitions
4157 *****/
4158 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4160 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4162 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4164 if (Stage >= MAX_TEXTURES) {
4165 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4166 return WINED3D_OK;
4169 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4170 This->updateStateBlock->textureState[Stage][Type] = Value;
4172 if (This->isRecordingState) {
4173 TRACE("Recording... not performing anything\n");
4174 return WINED3D_OK;
4177 /* Checked after the assignments to allow proper stateblock recording */
4178 if(oldValue == Value) {
4179 TRACE("App is setting the old value over, nothing to do\n");
4180 return WINED3D_OK;
4183 if(Stage > This->stateBlock->lowest_disabled_stage &&
4184 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4185 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4186 * Changes in other states are important on disabled stages too
4188 return WINED3D_OK;
4191 if(Type == WINED3DTSS_COLOROP) {
4192 unsigned int i;
4194 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4195 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4196 * they have to be disabled
4198 * The current stage is dirtified below.
4200 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4201 TRACE("Additionally dirtifying stage %u\n", i);
4202 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4204 This->stateBlock->lowest_disabled_stage = Stage;
4205 TRACE("New lowest disabled: %u\n", Stage);
4206 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4207 /* Previously disabled stage enabled. Stages above it may need enabling
4208 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4209 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4211 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4214 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4216 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4217 break;
4219 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4220 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4222 This->stateBlock->lowest_disabled_stage = i;
4223 TRACE("New lowest disabled: %u\n", i);
4227 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4229 return WINED3D_OK;
4232 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4234 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4235 *pValue = This->updateStateBlock->textureState[Stage][Type];
4236 return WINED3D_OK;
4239 /*****
4240 * Get / Set Texture
4241 *****/
4242 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4243 DWORD stage, IWineD3DBaseTexture *texture)
4245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4246 IWineD3DBaseTexture *prev;
4248 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4250 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4251 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4253 /* Windows accepts overflowing this array... we do not. */
4254 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4256 WARN("Ignoring invalid stage %u.\n", stage);
4257 return WINED3D_OK;
4260 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4261 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4263 WARN("Rejecting attempt to set scratch texture.\n");
4264 return WINED3DERR_INVALIDCALL;
4267 This->updateStateBlock->changed.textures |= 1 << stage;
4269 prev = This->updateStateBlock->textures[stage];
4270 TRACE("Previous texture %p.\n", prev);
4272 if (texture == prev)
4274 TRACE("App is setting the same texture again, nothing to do.\n");
4275 return WINED3D_OK;
4278 TRACE("Setting new texture to %p.\n", texture);
4279 This->updateStateBlock->textures[stage] = texture;
4281 if (This->isRecordingState)
4283 TRACE("Recording... not performing anything\n");
4285 if (texture) IWineD3DBaseTexture_AddRef(texture);
4286 if (prev) IWineD3DBaseTexture_Release(prev);
4288 return WINED3D_OK;
4291 if (texture)
4293 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4294 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4295 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4297 IWineD3DBaseTexture_AddRef(texture);
4299 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4301 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4304 if (!prev && stage < MAX_TEXTURES)
4306 /* The source arguments for color and alpha ops have different
4307 * meanings when a NULL texture is bound, so the COLOROP and
4308 * ALPHAOP have to be dirtified. */
4309 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4310 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4313 if (bind_count == 1) t->baseTexture.sampler = stage;
4316 if (prev)
4318 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4319 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4321 IWineD3DBaseTexture_Release(prev);
4323 if (!texture && stage < MAX_TEXTURES)
4325 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4326 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4329 if (bind_count && t->baseTexture.sampler == stage)
4331 unsigned int i;
4333 /* Search for other stages the texture is bound to. Shouldn't
4334 * happen if applications bind textures to a single stage only. */
4335 TRACE("Searching for other stages the texture is bound to.\n");
4336 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4338 if (This->updateStateBlock->textures[i] == prev)
4340 TRACE("Texture is also bound to stage %u.\n", i);
4341 t->baseTexture.sampler = i;
4342 break;
4348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4350 return WINED3D_OK;
4353 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4356 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4358 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4359 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4362 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4363 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4364 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4367 *ppTexture=This->stateBlock->textures[Stage];
4368 if (*ppTexture)
4369 IWineD3DBaseTexture_AddRef(*ppTexture);
4371 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4373 return WINED3D_OK;
4376 /*****
4377 * Get Back Buffer
4378 *****/
4379 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4380 IWineD3DSurface **ppBackBuffer) {
4381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4382 IWineD3DSwapChain *swapChain;
4383 HRESULT hr;
4385 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4387 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4388 if (hr == WINED3D_OK) {
4389 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4390 IWineD3DSwapChain_Release(swapChain);
4391 } else {
4392 *ppBackBuffer = NULL;
4394 return hr;
4397 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4399 WARN("(%p) : stub, calling idirect3d for now\n", This);
4400 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4403 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4405 IWineD3DSwapChain *swapChain;
4406 HRESULT hr;
4408 if(iSwapChain > 0) {
4409 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4410 if (hr == WINED3D_OK) {
4411 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4412 IWineD3DSwapChain_Release(swapChain);
4413 } else {
4414 FIXME("(%p) Error getting display mode\n", This);
4416 } else {
4417 /* Don't read the real display mode,
4418 but return the stored mode instead. X11 can't change the color
4419 depth, and some apps are pretty angry if they SetDisplayMode from
4420 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4422 Also don't relay to the swapchain because with ddraw it's possible
4423 that there isn't a swapchain at all */
4424 pMode->Width = This->ddraw_width;
4425 pMode->Height = This->ddraw_height;
4426 pMode->Format = This->ddraw_format;
4427 pMode->RefreshRate = 0;
4428 hr = WINED3D_OK;
4431 return hr;
4434 /*****
4435 * Stateblock related functions
4436 *****/
4438 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4440 IWineD3DStateBlock *stateblock;
4441 HRESULT hr;
4443 TRACE("(%p)\n", This);
4445 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4447 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4448 if (FAILED(hr)) return hr;
4450 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4451 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4452 This->isRecordingState = TRUE;
4454 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4456 return WINED3D_OK;
4459 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4461 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4463 if (!This->isRecordingState) {
4464 WARN("(%p) not recording! returning error\n", This);
4465 *ppStateBlock = NULL;
4466 return WINED3DERR_INVALIDCALL;
4469 stateblock_init_contained_states(object);
4471 *ppStateBlock = (IWineD3DStateBlock*) object;
4472 This->isRecordingState = FALSE;
4473 This->updateStateBlock = This->stateBlock;
4474 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4475 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4476 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4477 return WINED3D_OK;
4480 /*****
4481 * Scene related functions
4482 *****/
4483 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4484 /* At the moment we have no need for any functionality at the beginning
4485 of a scene */
4486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4487 TRACE("(%p)\n", This);
4489 if(This->inScene) {
4490 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4491 return WINED3DERR_INVALIDCALL;
4493 This->inScene = TRUE;
4494 return WINED3D_OK;
4497 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4499 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4500 struct wined3d_context *context;
4502 TRACE("(%p)\n", This);
4504 if(!This->inScene) {
4505 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4506 return WINED3DERR_INVALIDCALL;
4509 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4510 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4511 wglFlush();
4512 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4513 * fails. */
4514 context_release(context);
4516 This->inScene = FALSE;
4517 return WINED3D_OK;
4520 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4521 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4522 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4524 IWineD3DSwapChain *swapChain = NULL;
4525 int i;
4526 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4528 TRACE("(%p) Presenting the frame\n", This);
4530 for(i = 0 ; i < swapchains ; i ++) {
4532 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4533 TRACE("presentinng chain %d, %p\n", i, swapChain);
4534 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4535 IWineD3DSwapChain_Release(swapChain);
4538 return WINED3D_OK;
4541 /* Not called from the VTable (internal subroutine) */
4542 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4543 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4544 float Z, DWORD Stencil) {
4545 GLbitfield glMask = 0;
4546 unsigned int i;
4547 WINED3DRECT curRect;
4548 RECT vp_rect;
4549 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4550 UINT drawable_width, drawable_height;
4551 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4552 IWineD3DSwapChainImpl *swapchain = NULL;
4553 struct wined3d_context *context;
4555 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4556 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4557 * for the cleared parts, and the untouched parts.
4559 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4560 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4561 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4562 * checking all this if the dest surface is in the drawable anyway.
4564 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4565 while(1) {
4566 if(vp->X != 0 || vp->Y != 0 ||
4567 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4568 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4569 break;
4571 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4572 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4573 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4574 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4575 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4576 break;
4578 if(Count > 0 && pRects && (
4579 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4580 pRects[0].x2 < target->currentDesc.Width ||
4581 pRects[0].y2 < target->currentDesc.Height)) {
4582 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4583 break;
4585 break;
4589 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4591 target->get_drawable_size(context, &drawable_width, &drawable_height);
4593 ENTER_GL();
4595 /* Only set the values up once, as they are not changing */
4596 if (Flags & WINED3DCLEAR_STENCIL) {
4597 glClearStencil(Stencil);
4598 checkGLcall("glClearStencil");
4599 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4600 glStencilMask(0xFFFFFFFF);
4603 if (Flags & WINED3DCLEAR_ZBUFFER) {
4604 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4605 glDepthMask(GL_TRUE);
4606 glClearDepth(Z);
4607 checkGLcall("glClearDepth");
4608 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4609 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4611 if (vp->X != 0 || vp->Y != 0 ||
4612 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4613 surface_load_ds_location(This->stencilBufferTarget, context, location);
4615 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4616 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4617 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4618 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4619 surface_load_ds_location(This->stencilBufferTarget, context, location);
4621 else if (Count > 0 && pRects && (
4622 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4623 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4624 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4625 surface_load_ds_location(This->stencilBufferTarget, context, location);
4629 if (Flags & WINED3DCLEAR_TARGET) {
4630 TRACE("Clearing screen with glClear to color %x\n", Color);
4631 glClearColor(D3DCOLOR_R(Color),
4632 D3DCOLOR_G(Color),
4633 D3DCOLOR_B(Color),
4634 D3DCOLOR_A(Color));
4635 checkGLcall("glClearColor");
4637 /* Clear ALL colors! */
4638 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4639 glMask = glMask | GL_COLOR_BUFFER_BIT;
4642 vp_rect.left = vp->X;
4643 vp_rect.top = vp->Y;
4644 vp_rect.right = vp->X + vp->Width;
4645 vp_rect.bottom = vp->Y + vp->Height;
4646 if (!(Count > 0 && pRects)) {
4647 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4648 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4650 if (context->render_offscreen)
4652 glScissor(vp_rect.left, vp_rect.top,
4653 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4654 } else {
4655 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4656 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4658 checkGLcall("glScissor");
4659 glClear(glMask);
4660 checkGLcall("glClear");
4661 } else {
4662 /* Now process each rect in turn */
4663 for (i = 0; i < Count; i++) {
4664 /* Note gl uses lower left, width/height */
4665 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4666 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4667 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4669 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4670 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4671 curRect.x1, (target->currentDesc.Height - curRect.y2),
4672 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4674 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4675 * The rectangle is not cleared, no error is returned, but further rectanlges are
4676 * still cleared if they are valid
4678 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4679 TRACE("Rectangle with negative dimensions, ignoring\n");
4680 continue;
4683 if (context->render_offscreen)
4685 glScissor(curRect.x1, curRect.y1,
4686 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4687 } else {
4688 glScissor(curRect.x1, drawable_height - curRect.y2,
4689 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4691 checkGLcall("glScissor");
4693 glClear(glMask);
4694 checkGLcall("glClear");
4698 /* Restore the old values (why..?) */
4699 if (Flags & WINED3DCLEAR_STENCIL) {
4700 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4702 if (Flags & WINED3DCLEAR_TARGET) {
4703 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4704 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4705 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4706 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4707 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4709 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4710 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4712 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4714 if (Flags & WINED3DCLEAR_ZBUFFER) {
4715 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4716 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4717 surface_modify_ds_location(This->stencilBufferTarget, location);
4720 LEAVE_GL();
4722 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
4723 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
4724 wglFlush();
4726 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
4729 context_release(context);
4731 return WINED3D_OK;
4734 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4735 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4737 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4739 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4740 Count, pRects, Flags, Color, Z, Stencil);
4742 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4743 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4744 /* TODO: What about depth stencil buffers without stencil bits? */
4745 return WINED3DERR_INVALIDCALL;
4748 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4751 /*****
4752 * Drawing functions
4753 *****/
4755 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4756 WINED3DPRIMITIVETYPE primitive_type)
4758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4760 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4762 This->updateStateBlock->changed.primitive_type = TRUE;
4763 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4766 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4767 WINED3DPRIMITIVETYPE *primitive_type)
4769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4771 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4773 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4775 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4778 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4782 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4784 if(!This->stateBlock->vertexDecl) {
4785 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4786 return WINED3DERR_INVALIDCALL;
4789 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4790 if(This->stateBlock->streamIsUP) {
4791 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4792 This->stateBlock->streamIsUP = FALSE;
4795 if(This->stateBlock->loadBaseVertexIndex != 0) {
4796 This->stateBlock->loadBaseVertexIndex = 0;
4797 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4799 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4800 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4801 return WINED3D_OK;
4804 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4807 UINT idxStride = 2;
4808 IWineD3DBuffer *pIB;
4809 GLuint vbo;
4811 pIB = This->stateBlock->pIndexData;
4812 if (!pIB) {
4813 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4814 * without an index buffer set. (The first time at least...)
4815 * D3D8 simply dies, but I doubt it can do much harm to return
4816 * D3DERR_INVALIDCALL there as well. */
4817 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4818 return WINED3DERR_INVALIDCALL;
4821 if(!This->stateBlock->vertexDecl) {
4822 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4823 return WINED3DERR_INVALIDCALL;
4826 if(This->stateBlock->streamIsUP) {
4827 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4828 This->stateBlock->streamIsUP = FALSE;
4830 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4832 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4834 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4835 idxStride = 2;
4836 } else {
4837 idxStride = 4;
4840 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4841 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4842 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4845 drawPrimitive(iface, index_count, startIndex, idxStride,
4846 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4848 return WINED3D_OK;
4851 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4852 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4854 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4855 IWineD3DBuffer *vb;
4857 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4858 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4860 if(!This->stateBlock->vertexDecl) {
4861 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4862 return WINED3DERR_INVALIDCALL;
4865 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4866 vb = This->stateBlock->streamSource[0];
4867 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4868 if (vb) IWineD3DBuffer_Release(vb);
4869 This->stateBlock->streamOffset[0] = 0;
4870 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4871 This->stateBlock->streamIsUP = TRUE;
4872 This->stateBlock->loadBaseVertexIndex = 0;
4874 /* TODO: Only mark dirty if drawing from a different UP address */
4875 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4877 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4879 /* MSDN specifies stream zero settings must be set to NULL */
4880 This->stateBlock->streamStride[0] = 0;
4881 This->stateBlock->streamSource[0] = NULL;
4883 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4884 * the new stream sources or use UP drawing again
4886 return WINED3D_OK;
4889 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4890 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4891 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4893 int idxStride;
4894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4895 IWineD3DBuffer *vb;
4896 IWineD3DBuffer *ib;
4898 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4899 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4901 if(!This->stateBlock->vertexDecl) {
4902 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4903 return WINED3DERR_INVALIDCALL;
4906 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4907 idxStride = 2;
4908 } else {
4909 idxStride = 4;
4912 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4913 vb = This->stateBlock->streamSource[0];
4914 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4915 if (vb) IWineD3DBuffer_Release(vb);
4916 This->stateBlock->streamIsUP = TRUE;
4917 This->stateBlock->streamOffset[0] = 0;
4918 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4920 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4921 This->stateBlock->baseVertexIndex = 0;
4922 This->stateBlock->loadBaseVertexIndex = 0;
4923 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4924 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4925 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4927 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4929 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4930 This->stateBlock->streamSource[0] = NULL;
4931 This->stateBlock->streamStride[0] = 0;
4932 ib = This->stateBlock->pIndexData;
4933 if(ib) {
4934 IWineD3DBuffer_Release(ib);
4935 This->stateBlock->pIndexData = NULL;
4937 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4938 * SetStreamSource to specify a vertex buffer
4941 return WINED3D_OK;
4944 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4945 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4949 /* Mark the state dirty until we have nicer tracking
4950 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4951 * that value.
4953 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4954 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4955 This->stateBlock->baseVertexIndex = 0;
4956 This->up_strided = DrawPrimStrideData;
4957 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4958 This->up_strided = NULL;
4959 return WINED3D_OK;
4962 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4963 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4964 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4967 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4969 /* Mark the state dirty until we have nicer tracking
4970 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4971 * that value.
4973 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4974 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4975 This->stateBlock->streamIsUP = TRUE;
4976 This->stateBlock->baseVertexIndex = 0;
4977 This->up_strided = DrawPrimStrideData;
4978 drawPrimitive(iface, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData);
4979 This->up_strided = NULL;
4980 return WINED3D_OK;
4983 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
4984 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
4985 * not callable by the app directly no parameter validation checks are needed here.
4987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4988 WINED3DLOCKED_BOX src;
4989 WINED3DLOCKED_BOX dst;
4990 HRESULT hr;
4991 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
4993 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4994 * dirtification to improve loading performance.
4996 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4997 if(FAILED(hr)) return hr;
4998 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4999 if(FAILED(hr)) {
5000 IWineD3DVolume_UnlockBox(pSourceVolume);
5001 return hr;
5004 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5006 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5007 if(FAILED(hr)) {
5008 IWineD3DVolume_UnlockBox(pSourceVolume);
5009 } else {
5010 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5012 return hr;
5015 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
5016 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
5018 unsigned int level_count, i;
5019 WINED3DRESOURCETYPE type;
5020 HRESULT hr;
5022 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
5024 /* Verify that the source and destination textures are non-NULL. */
5025 if (!src_texture || !dst_texture)
5027 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5028 return WINED3DERR_INVALIDCALL;
5031 if (src_texture == dst_texture)
5033 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5034 return WINED3DERR_INVALIDCALL;
5037 /* Verify that the source and destination textures are the same type. */
5038 type = IWineD3DBaseTexture_GetType(src_texture);
5039 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
5041 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5042 return WINED3DERR_INVALIDCALL;
5045 /* Check that both textures have the identical numbers of levels. */
5046 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
5047 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
5049 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5050 return WINED3DERR_INVALIDCALL;
5053 /* Make sure that the destination texture is loaded. */
5054 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
5056 /* Update every surface level of the texture. */
5057 switch (type)
5059 case WINED3DRTYPE_TEXTURE:
5061 IWineD3DSurface *src_surface;
5062 IWineD3DSurface *dst_surface;
5064 for (i = 0; i < level_count; ++i)
5066 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
5067 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
5068 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5069 IWineD3DSurface_Release(dst_surface);
5070 IWineD3DSurface_Release(src_surface);
5071 if (FAILED(hr))
5073 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5074 return hr;
5077 break;
5080 case WINED3DRTYPE_CUBETEXTURE:
5082 IWineD3DSurface *src_surface;
5083 IWineD3DSurface *dst_surface;
5084 WINED3DCUBEMAP_FACES face;
5086 for (i = 0; i < level_count; ++i)
5088 /* Update each cube face. */
5089 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
5091 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
5092 face, i, &src_surface);
5093 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5094 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
5095 face, i, &dst_surface);
5096 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5097 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5098 IWineD3DSurface_Release(dst_surface);
5099 IWineD3DSurface_Release(src_surface);
5100 if (FAILED(hr))
5102 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5103 return hr;
5107 break;
5110 case WINED3DRTYPE_VOLUMETEXTURE:
5112 IWineD3DVolume *src_volume;
5113 IWineD3DVolume *dst_volume;
5115 for (i = 0; i < level_count; ++i)
5117 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5118 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5119 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5120 IWineD3DVolume_Release(dst_volume);
5121 IWineD3DVolume_Release(src_volume);
5122 if (FAILED(hr))
5124 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5125 return hr;
5128 break;
5131 default:
5132 FIXME("Unsupported texture type %#x.\n", type);
5133 return WINED3DERR_INVALIDCALL;
5136 return WINED3D_OK;
5139 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5140 IWineD3DSwapChain *swapChain;
5141 HRESULT hr;
5142 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5143 if(hr == WINED3D_OK) {
5144 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5145 IWineD3DSwapChain_Release(swapChain);
5147 return hr;
5150 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5152 IWineD3DBaseTextureImpl *texture;
5153 DWORD i;
5155 TRACE("(%p) : %p\n", This, pNumPasses);
5157 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5158 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5159 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5160 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5162 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5163 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5164 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5167 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5168 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5170 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5171 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5172 return E_FAIL;
5174 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5175 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5176 return E_FAIL;
5178 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5179 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5180 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5181 return E_FAIL;
5185 /* return a sensible default */
5186 *pNumPasses = 1;
5188 TRACE("returning D3D_OK\n");
5189 return WINED3D_OK;
5192 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5194 int i;
5196 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5198 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5199 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
5200 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
5202 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5207 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5209 int j;
5210 UINT NewSize;
5211 PALETTEENTRY **palettes;
5213 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5215 if (PaletteNumber >= MAX_PALETTES) {
5216 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5217 return WINED3DERR_INVALIDCALL;
5220 if (PaletteNumber >= This->NumberOfPalettes) {
5221 NewSize = This->NumberOfPalettes;
5222 do {
5223 NewSize *= 2;
5224 } while(PaletteNumber >= NewSize);
5225 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5226 if (!palettes) {
5227 ERR("Out of memory!\n");
5228 return E_OUTOFMEMORY;
5230 This->palettes = palettes;
5231 This->NumberOfPalettes = NewSize;
5234 if (!This->palettes[PaletteNumber]) {
5235 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5236 if (!This->palettes[PaletteNumber]) {
5237 ERR("Out of memory!\n");
5238 return E_OUTOFMEMORY;
5242 for (j = 0; j < 256; ++j) {
5243 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5244 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5245 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5246 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5248 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5249 TRACE("(%p) : returning\n", This);
5250 return WINED3D_OK;
5253 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5255 int j;
5256 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5257 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5258 /* What happens in such situation isn't documented; Native seems to silently abort
5259 on such conditions. Return Invalid Call. */
5260 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5261 return WINED3DERR_INVALIDCALL;
5263 for (j = 0; j < 256; ++j) {
5264 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5265 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5266 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5267 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5269 TRACE("(%p) : returning\n", This);
5270 return WINED3D_OK;
5273 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5275 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5276 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5277 (tested with reference rasterizer). Return Invalid Call. */
5278 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5279 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5280 return WINED3DERR_INVALIDCALL;
5282 /*TODO: stateblocks */
5283 if (This->currentPalette != PaletteNumber) {
5284 This->currentPalette = PaletteNumber;
5285 dirtify_p8_texture_samplers(This);
5287 TRACE("(%p) : returning\n", This);
5288 return WINED3D_OK;
5291 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5293 if (PaletteNumber == NULL) {
5294 WARN("(%p) : returning Invalid Call\n", This);
5295 return WINED3DERR_INVALIDCALL;
5297 /*TODO: stateblocks */
5298 *PaletteNumber = This->currentPalette;
5299 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5300 return WINED3D_OK;
5303 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5305 static BOOL warned;
5306 if (!warned)
5308 FIXME("(%p) : stub\n", This);
5309 warned = TRUE;
5312 This->softwareVertexProcessing = bSoftware;
5313 return WINED3D_OK;
5317 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5319 static BOOL warned;
5320 if (!warned)
5322 FIXME("(%p) : stub\n", This);
5323 warned = TRUE;
5325 return This->softwareVertexProcessing;
5329 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5331 IWineD3DSwapChain *swapChain;
5332 HRESULT hr;
5334 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5336 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5337 if(hr == WINED3D_OK){
5338 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5339 IWineD3DSwapChain_Release(swapChain);
5340 }else{
5341 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5343 return hr;
5347 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5349 static BOOL warned;
5350 if(nSegments != 0.0f) {
5351 if (!warned)
5353 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5354 warned = TRUE;
5357 return WINED3D_OK;
5360 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5362 static BOOL warned;
5363 if (!warned)
5365 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5366 warned = TRUE;
5368 return 0.0f;
5371 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5373 /** TODO: remove casts to IWineD3DSurfaceImpl
5374 * NOTE: move code to surface to accomplish this
5375 ****************************************/
5376 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5377 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5378 int srcWidth, srcHeight;
5379 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5380 WINED3DFORMAT destFormat, srcFormat;
5381 UINT destSize;
5382 int srcLeft, destLeft, destTop;
5383 WINED3DPOOL srcPool, destPool;
5384 int offset = 0;
5385 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5386 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5387 GLenum dummy;
5388 DWORD sampler;
5389 int bpp;
5390 CONVERT_TYPES convert = NO_CONVERSION;
5391 struct wined3d_context *context;
5393 WINED3DSURFACE_DESC winedesc;
5395 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5397 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5398 srcSurfaceWidth = winedesc.width;
5399 srcSurfaceHeight = winedesc.height;
5400 srcPool = winedesc.pool;
5401 srcFormat = winedesc.format;
5403 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5404 destSurfaceWidth = winedesc.width;
5405 destSurfaceHeight = winedesc.height;
5406 destPool = winedesc.pool;
5407 destFormat = winedesc.format;
5408 destSize = winedesc.size;
5410 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5411 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5412 return WINED3DERR_INVALIDCALL;
5415 /* This call loads the opengl surface directly, instead of copying the surface to the
5416 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5417 * copy in sysmem and use regular surface loading.
5419 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5420 if(convert != NO_CONVERSION) {
5421 return IWineD3DSurface_BltFast(pDestinationSurface,
5422 pDestPoint ? pDestPoint->x : 0,
5423 pDestPoint ? pDestPoint->y : 0,
5424 pSourceSurface, pSourceRect, 0);
5427 if (destFormat == WINED3DFMT_UNKNOWN) {
5428 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5429 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5431 /* Get the update surface description */
5432 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5435 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5437 ENTER_GL();
5438 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5439 checkGLcall("glActiveTextureARB");
5440 LEAVE_GL();
5442 /* Make sure the surface is loaded and up to date */
5443 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5444 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5446 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5447 dst_format_desc = dst_impl->resource.format_desc;
5449 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5450 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5451 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5452 srcLeft = pSourceRect ? pSourceRect->left : 0;
5453 destLeft = pDestPoint ? pDestPoint->x : 0;
5454 destTop = pDestPoint ? pDestPoint->y : 0;
5457 /* This function doesn't support compressed textures
5458 the pitch is just bytesPerPixel * width */
5459 if(srcWidth != srcSurfaceWidth || srcLeft ){
5460 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5461 offset += srcLeft * src_format_desc->byte_count;
5462 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5464 /* TODO DXT formats */
5466 if(pSourceRect != NULL && pSourceRect->top != 0){
5467 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5469 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5470 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5471 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5473 /* Sanity check */
5474 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5476 /* need to lock the surface to get the data */
5477 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5480 ENTER_GL();
5482 /* TODO: Cube and volume support */
5483 if(rowoffset != 0){
5484 /* not a whole row so we have to do it a line at a time */
5485 int j;
5487 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5488 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5490 for (j = destTop; j < (srcHeight + destTop); ++j)
5492 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5493 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5494 data += rowoffset;
5497 } else { /* Full width, so just write out the whole texture */
5498 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5500 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5502 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5504 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5505 FIXME("Updating part of a compressed texture is not supported.\n");
5507 if (destFormat != srcFormat)
5509 FIXME("Updating mixed format compressed textures is not supported.\n");
5511 else
5513 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5514 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5517 else
5519 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5520 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5523 checkGLcall("glTexSubImage2D");
5525 LEAVE_GL();
5526 context_release(context);
5528 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5529 sampler = This->rev_tex_unit_map[0];
5530 if (sampler != WINED3D_UNMAPPED_STAGE)
5532 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5535 return WINED3D_OK;
5538 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5540 struct WineD3DRectPatch *patch;
5541 GLenum old_primitive_type;
5542 unsigned int i;
5543 struct list *e;
5544 BOOL found;
5545 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5547 if(!(Handle || pRectPatchInfo)) {
5548 /* TODO: Write a test for the return value, thus the FIXME */
5549 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5550 return WINED3DERR_INVALIDCALL;
5553 if(Handle) {
5554 i = PATCHMAP_HASHFUNC(Handle);
5555 found = FALSE;
5556 LIST_FOR_EACH(e, &This->patches[i]) {
5557 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5558 if(patch->Handle == Handle) {
5559 found = TRUE;
5560 break;
5564 if(!found) {
5565 TRACE("Patch does not exist. Creating a new one\n");
5566 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5567 patch->Handle = Handle;
5568 list_add_head(&This->patches[i], &patch->entry);
5569 } else {
5570 TRACE("Found existing patch %p\n", patch);
5572 } else {
5573 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5574 * attributes we have to tesselate, read back, and draw. This needs a patch
5575 * management structure instance. Create one.
5577 * A possible improvement is to check if a vertex shader is used, and if not directly
5578 * draw the patch.
5580 FIXME("Drawing an uncached patch. This is slow\n");
5581 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5584 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5585 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5586 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5587 HRESULT hr;
5588 TRACE("Tesselation density or patch info changed, retesselating\n");
5590 if(pRectPatchInfo) {
5591 patch->RectPatchInfo = *pRectPatchInfo;
5593 patch->numSegs[0] = pNumSegs[0];
5594 patch->numSegs[1] = pNumSegs[1];
5595 patch->numSegs[2] = pNumSegs[2];
5596 patch->numSegs[3] = pNumSegs[3];
5598 hr = tesselate_rectpatch(This, patch);
5599 if(FAILED(hr)) {
5600 WARN("Patch tesselation failed\n");
5602 /* Do not release the handle to store the params of the patch */
5603 if(!Handle) {
5604 HeapFree(GetProcessHeap(), 0, patch);
5606 return hr;
5610 This->currentPatch = patch;
5611 old_primitive_type = This->stateBlock->gl_primitive_type;
5612 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5613 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5614 This->stateBlock->gl_primitive_type = old_primitive_type;
5615 This->currentPatch = NULL;
5617 /* Destroy uncached patches */
5618 if(!Handle) {
5619 HeapFree(GetProcessHeap(), 0, patch->mem);
5620 HeapFree(GetProcessHeap(), 0, patch);
5622 return WINED3D_OK;
5625 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5627 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5628 FIXME("(%p) : Stub\n", This);
5629 return WINED3D_OK;
5632 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5634 int i;
5635 struct WineD3DRectPatch *patch;
5636 struct list *e;
5637 TRACE("(%p) Handle(%d)\n", This, Handle);
5639 i = PATCHMAP_HASHFUNC(Handle);
5640 LIST_FOR_EACH(e, &This->patches[i]) {
5641 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5642 if(patch->Handle == Handle) {
5643 TRACE("Deleting patch %p\n", patch);
5644 list_remove(&patch->entry);
5645 HeapFree(GetProcessHeap(), 0, patch->mem);
5646 HeapFree(GetProcessHeap(), 0, patch);
5647 return WINED3D_OK;
5651 /* TODO: Write a test for the return value */
5652 FIXME("Attempt to destroy nonexistent patch\n");
5653 return WINED3DERR_INVALIDCALL;
5656 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5657 HRESULT hr;
5658 IWineD3DSwapChain *swapchain;
5660 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5661 if (SUCCEEDED(hr)) {
5662 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5663 return swapchain;
5666 return NULL;
5669 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5670 const WINED3DRECT *rect, const float color[4])
5672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5673 struct wined3d_context *context;
5674 IWineD3DSwapChain *swapchain;
5676 swapchain = get_swapchain(surface);
5677 if (swapchain) {
5678 GLenum buffer;
5680 TRACE("Surface %p is onscreen\n", surface);
5682 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5683 ENTER_GL();
5684 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5685 buffer = surface_get_gl_buffer(surface, swapchain);
5686 glDrawBuffer(buffer);
5687 checkGLcall("glDrawBuffer()");
5688 } else {
5689 TRACE("Surface %p is offscreen\n", surface);
5691 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5692 ENTER_GL();
5693 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5694 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5695 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5698 if (rect) {
5699 glEnable(GL_SCISSOR_TEST);
5700 if(!swapchain) {
5701 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5702 } else {
5703 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5704 rect->x2 - rect->x1, rect->y2 - rect->y1);
5706 checkGLcall("glScissor");
5707 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5708 } else {
5709 glDisable(GL_SCISSOR_TEST);
5711 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5713 glDisable(GL_BLEND);
5714 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5716 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5719 glClearColor(color[0], color[1], color[2], color[3]);
5720 glClear(GL_COLOR_BUFFER_BIT);
5721 checkGLcall("glClear");
5723 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5724 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5725 glDrawBuffer(GL_BACK);
5726 checkGLcall("glDrawBuffer()");
5729 LEAVE_GL();
5730 context_release(context);
5733 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5734 unsigned int r, g, b, a;
5735 DWORD ret;
5737 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5738 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5739 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5740 return color;
5742 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5744 a = (color & 0xff000000) >> 24;
5745 r = (color & 0x00ff0000) >> 16;
5746 g = (color & 0x0000ff00) >> 8;
5747 b = (color & 0x000000ff) >> 0;
5749 switch(destfmt)
5751 case WINED3DFMT_B5G6R5_UNORM:
5752 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5753 r = (r * 32) / 256;
5754 g = (g * 64) / 256;
5755 b = (b * 32) / 256;
5756 ret = r << 11;
5757 ret |= g << 5;
5758 ret |= b;
5759 TRACE("Returning %08x\n", ret);
5760 return ret;
5762 case WINED3DFMT_B5G5R5X1_UNORM:
5763 case WINED3DFMT_B5G5R5A1_UNORM:
5764 a = (a * 2) / 256;
5765 r = (r * 32) / 256;
5766 g = (g * 32) / 256;
5767 b = (b * 32) / 256;
5768 ret = a << 15;
5769 ret |= r << 10;
5770 ret |= g << 5;
5771 ret |= b << 0;
5772 TRACE("Returning %08x\n", ret);
5773 return ret;
5775 case WINED3DFMT_A8_UNORM:
5776 TRACE("Returning %08x\n", a);
5777 return a;
5779 case WINED3DFMT_B4G4R4X4_UNORM:
5780 case WINED3DFMT_B4G4R4A4_UNORM:
5781 a = (a * 16) / 256;
5782 r = (r * 16) / 256;
5783 g = (g * 16) / 256;
5784 b = (b * 16) / 256;
5785 ret = a << 12;
5786 ret |= r << 8;
5787 ret |= g << 4;
5788 ret |= b << 0;
5789 TRACE("Returning %08x\n", ret);
5790 return ret;
5792 case WINED3DFMT_B2G3R3_UNORM:
5793 r = (r * 8) / 256;
5794 g = (g * 8) / 256;
5795 b = (b * 4) / 256;
5796 ret = r << 5;
5797 ret |= g << 2;
5798 ret |= b << 0;
5799 TRACE("Returning %08x\n", ret);
5800 return ret;
5802 case WINED3DFMT_R8G8B8X8_UNORM:
5803 case WINED3DFMT_R8G8B8A8_UNORM:
5804 ret = a << 24;
5805 ret |= b << 16;
5806 ret |= g << 8;
5807 ret |= r << 0;
5808 TRACE("Returning %08x\n", ret);
5809 return ret;
5811 case WINED3DFMT_B10G10R10A2_UNORM:
5812 a = (a * 4) / 256;
5813 r = (r * 1024) / 256;
5814 g = (g * 1024) / 256;
5815 b = (b * 1024) / 256;
5816 ret = a << 30;
5817 ret |= r << 20;
5818 ret |= g << 10;
5819 ret |= b << 0;
5820 TRACE("Returning %08x\n", ret);
5821 return ret;
5823 case WINED3DFMT_R10G10B10A2_UNORM:
5824 a = (a * 4) / 256;
5825 r = (r * 1024) / 256;
5826 g = (g * 1024) / 256;
5827 b = (b * 1024) / 256;
5828 ret = a << 30;
5829 ret |= b << 20;
5830 ret |= g << 10;
5831 ret |= r << 0;
5832 TRACE("Returning %08x\n", ret);
5833 return ret;
5835 default:
5836 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5837 return 0;
5841 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5843 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5844 WINEDDBLTFX BltFx;
5845 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5847 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5848 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5849 return WINED3DERR_INVALIDCALL;
5852 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5853 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5854 color_fill_fbo(iface, pSurface, pRect, c);
5855 return WINED3D_OK;
5856 } else {
5857 /* Just forward this to the DirectDraw blitting engine */
5858 memset(&BltFx, 0, sizeof(BltFx));
5859 BltFx.dwSize = sizeof(BltFx);
5860 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5861 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5862 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5866 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5867 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5869 IWineD3DResource *resource;
5870 IWineD3DSurface *surface;
5871 HRESULT hr;
5873 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5874 if (FAILED(hr))
5876 ERR("Failed to get resource, hr %#x\n", hr);
5877 return;
5880 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5882 FIXME("Only supported on surface resources\n");
5883 IWineD3DResource_Release(resource);
5884 return;
5887 surface = (IWineD3DSurface *)resource;
5889 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5891 color_fill_fbo(iface, surface, NULL, color);
5893 else
5895 WINEDDBLTFX BltFx;
5896 WINED3DCOLOR c;
5898 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5900 c = ((DWORD)(color[2] * 255.0f));
5901 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5902 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5903 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5905 /* Just forward this to the DirectDraw blitting engine */
5906 memset(&BltFx, 0, sizeof(BltFx));
5907 BltFx.dwSize = sizeof(BltFx);
5908 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5909 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5910 if (FAILED(hr))
5912 ERR("Blt failed, hr %#x\n", hr);
5916 IWineD3DResource_Release(resource);
5919 /* rendertarget and depth stencil functions */
5920 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5923 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5925 ERR("(%p) : Only %d render targets are supported.\n",
5926 This, This->adapter->gl_info.limits.buffers);
5927 return WINED3DERR_INVALIDCALL;
5930 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5931 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5932 /* Note inc ref on returned surface */
5933 if(*ppRenderTarget != NULL)
5934 IWineD3DSurface_AddRef(*ppRenderTarget);
5935 return WINED3D_OK;
5938 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5940 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5941 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5942 IWineD3DSwapChainImpl *Swapchain;
5943 HRESULT hr;
5945 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5947 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5948 if(hr != WINED3D_OK) {
5949 ERR("Can't get the swapchain\n");
5950 return hr;
5953 /* Make sure to release the swapchain */
5954 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5956 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5957 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5958 return WINED3DERR_INVALIDCALL;
5960 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5961 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5962 return WINED3DERR_INVALIDCALL;
5965 if(Swapchain->frontBuffer != Front) {
5966 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5968 if(Swapchain->frontBuffer)
5970 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5971 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5973 Swapchain->frontBuffer = Front;
5975 if(Swapchain->frontBuffer) {
5976 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5977 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5981 if(Back && !Swapchain->backBuffer) {
5982 /* We need memory for the back buffer array - only one back buffer this way */
5983 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5984 if(!Swapchain->backBuffer) {
5985 ERR("Out of memory\n");
5986 return E_OUTOFMEMORY;
5990 if(Swapchain->backBuffer[0] != Back) {
5991 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5993 /* What to do about the context here in the case of multithreading? Not sure.
5994 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5996 WARN("No active context?\n");
5998 ENTER_GL();
5999 if(!Swapchain->backBuffer[0]) {
6000 /* GL was told to draw to the front buffer at creation,
6001 * undo that
6003 glDrawBuffer(GL_BACK);
6004 checkGLcall("glDrawBuffer(GL_BACK)");
6005 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6006 Swapchain->presentParms.BackBufferCount = 1;
6007 } else if (!Back) {
6008 /* That makes problems - disable for now */
6009 /* glDrawBuffer(GL_FRONT); */
6010 checkGLcall("glDrawBuffer(GL_FRONT)");
6011 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6012 Swapchain->presentParms.BackBufferCount = 0;
6014 LEAVE_GL();
6016 if(Swapchain->backBuffer[0])
6018 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6019 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6021 Swapchain->backBuffer[0] = Back;
6023 if(Swapchain->backBuffer[0]) {
6024 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6025 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6026 } else {
6027 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6028 Swapchain->backBuffer = NULL;
6033 return WINED3D_OK;
6036 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6038 *ppZStencilSurface = This->stencilBufferTarget;
6039 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6041 if(*ppZStencilSurface != NULL) {
6042 /* Note inc ref on returned surface */
6043 IWineD3DSurface_AddRef(*ppZStencilSurface);
6044 return WINED3D_OK;
6045 } else {
6046 return WINED3DERR_NOTFOUND;
6050 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6051 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6054 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6055 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6056 const struct wined3d_gl_info *gl_info;
6057 struct wined3d_context *context;
6058 GLenum gl_filter;
6059 POINT offset = {0, 0};
6061 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6062 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6063 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6064 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6066 switch (filter) {
6067 case WINED3DTEXF_LINEAR:
6068 gl_filter = GL_LINEAR;
6069 break;
6071 default:
6072 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6073 case WINED3DTEXF_NONE:
6074 case WINED3DTEXF_POINT:
6075 gl_filter = GL_NEAREST;
6076 break;
6079 /* Attach src surface to src fbo */
6080 src_swapchain = get_swapchain(src_surface);
6081 dst_swapchain = get_swapchain(dst_surface);
6083 if (src_swapchain) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
6084 else if (dst_swapchain) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6085 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6087 gl_info = context->gl_info;
6089 if (src_swapchain) {
6090 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6092 TRACE("Source surface %p is onscreen\n", src_surface);
6093 /* Make sure the drawable is up to date. In the offscreen case
6094 * attach_surface_fbo() implicitly takes care of this. */
6095 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6097 if(buffer == GL_FRONT) {
6098 RECT windowsize;
6099 UINT h;
6100 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6101 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6102 h = windowsize.bottom - windowsize.top;
6103 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6104 src_rect->y1 = offset.y + h - src_rect->y1;
6105 src_rect->y2 = offset.y + h - src_rect->y2;
6106 } else {
6107 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6108 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6111 ENTER_GL();
6112 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
6113 glReadBuffer(buffer);
6114 checkGLcall("glReadBuffer()");
6115 } else {
6116 TRACE("Source surface %p is offscreen\n", src_surface);
6117 ENTER_GL();
6118 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
6119 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
6120 glReadBuffer(GL_COLOR_ATTACHMENT0);
6121 checkGLcall("glReadBuffer()");
6122 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
6124 LEAVE_GL();
6126 /* Attach dst surface to dst fbo */
6127 if (dst_swapchain) {
6128 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6130 TRACE("Destination surface %p is onscreen\n", dst_surface);
6131 /* Make sure the drawable is up to date. In the offscreen case
6132 * attach_surface_fbo() implicitly takes care of this. */
6133 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6135 if(buffer == GL_FRONT) {
6136 RECT windowsize;
6137 UINT h;
6138 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6139 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6140 h = windowsize.bottom - windowsize.top;
6141 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6142 dst_rect->y1 = offset.y + h - dst_rect->y1;
6143 dst_rect->y2 = offset.y + h - dst_rect->y2;
6144 } else {
6145 /* Screen coords = window coords, surface height = window height */
6146 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6147 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6150 ENTER_GL();
6151 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
6152 glDrawBuffer(buffer);
6153 checkGLcall("glDrawBuffer()");
6154 } else {
6155 TRACE("Destination surface %p is offscreen\n", dst_surface);
6157 ENTER_GL();
6158 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
6159 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
6160 glDrawBuffer(GL_COLOR_ATTACHMENT0);
6161 checkGLcall("glDrawBuffer()");
6162 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
6164 glDisable(GL_SCISSOR_TEST);
6165 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6167 if (flip) {
6168 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6169 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
6170 checkGLcall("glBlitFramebuffer()");
6171 } else {
6172 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6173 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
6174 checkGLcall("glBlitFramebuffer()");
6177 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6179 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6180 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6181 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6182 glDrawBuffer(GL_BACK);
6183 checkGLcall("glDrawBuffer()");
6185 LEAVE_GL();
6187 context_release(context);
6190 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
6191 BOOL set_viewport) {
6192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6194 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6196 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
6198 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6199 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
6200 return WINED3DERR_INVALIDCALL;
6203 /* MSDN says that null disables the render target
6204 but a device must always be associated with a render target
6205 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6207 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6208 FIXME("Trying to set render target 0 to NULL\n");
6209 return WINED3DERR_INVALIDCALL;
6211 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6212 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);
6213 return WINED3DERR_INVALIDCALL;
6216 /* If we are trying to set what we already have, don't bother */
6217 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6218 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6219 return WINED3D_OK;
6221 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6222 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6223 This->render_targets[RenderTargetIndex] = pRenderTarget;
6225 /* Render target 0 is special */
6226 if(RenderTargetIndex == 0 && set_viewport) {
6227 /* Finally, reset the viewport and scissor rect as the MSDN states.
6228 * Tests show that stateblock recording is ignored, the change goes
6229 * directly into the primary stateblock.
6231 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6232 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6233 This->stateBlock->viewport.X = 0;
6234 This->stateBlock->viewport.Y = 0;
6235 This->stateBlock->viewport.MaxZ = 1.0f;
6236 This->stateBlock->viewport.MinZ = 0.0f;
6237 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6239 This->stateBlock->scissorRect.top = 0;
6240 This->stateBlock->scissorRect.left = 0;
6241 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
6242 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
6243 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6245 return WINED3D_OK;
6248 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6250 HRESULT hr = WINED3D_OK;
6251 IWineD3DSurface *tmp;
6253 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6255 if (pNewZStencil == This->stencilBufferTarget) {
6256 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6257 } else {
6258 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6259 * depending on the renter target implementation being used.
6260 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6261 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6262 * stencil buffer and incur an extra memory overhead
6263 ******************************************************/
6265 if (This->stencilBufferTarget) {
6266 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6267 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6268 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6269 } else {
6270 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6271 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
6272 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6273 context_release(context);
6277 tmp = This->stencilBufferTarget;
6278 This->stencilBufferTarget = pNewZStencil;
6279 /* should we be calling the parent or the wined3d surface? */
6280 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6281 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6282 hr = WINED3D_OK;
6284 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6285 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6286 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6287 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6288 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6292 return hr;
6295 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6296 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6298 /* TODO: the use of Impl is deprecated. */
6299 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6300 WINED3DLOCKED_RECT lockedRect;
6302 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6304 /* some basic validation checks */
6305 if(This->cursorTexture) {
6306 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6307 ENTER_GL();
6308 glDeleteTextures(1, &This->cursorTexture);
6309 LEAVE_GL();
6310 context_release(context);
6311 This->cursorTexture = 0;
6314 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6315 This->haveHardwareCursor = TRUE;
6316 else
6317 This->haveHardwareCursor = FALSE;
6319 if(pCursorBitmap) {
6320 WINED3DLOCKED_RECT rect;
6322 /* MSDN: Cursor must be A8R8G8B8 */
6323 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6325 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6326 return WINED3DERR_INVALIDCALL;
6329 /* MSDN: Cursor must be smaller than the display mode */
6330 if(pSur->currentDesc.Width > This->ddraw_width ||
6331 pSur->currentDesc.Height > This->ddraw_height) {
6332 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);
6333 return WINED3DERR_INVALIDCALL;
6336 if (!This->haveHardwareCursor) {
6337 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6339 /* Do not store the surface's pointer because the application may
6340 * release it after setting the cursor image. Windows doesn't
6341 * addref the set surface, so we can't do this either without
6342 * creating circular refcount dependencies. Copy out the gl texture
6343 * instead.
6345 This->cursorWidth = pSur->currentDesc.Width;
6346 This->cursorHeight = pSur->currentDesc.Height;
6347 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6349 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6350 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6351 struct wined3d_context *context;
6352 char *mem, *bits = rect.pBits;
6353 GLint intfmt = glDesc->glInternal;
6354 GLint format = glDesc->glFormat;
6355 GLint type = glDesc->glType;
6356 INT height = This->cursorHeight;
6357 INT width = This->cursorWidth;
6358 INT bpp = glDesc->byte_count;
6359 DWORD sampler;
6360 INT i;
6362 /* Reformat the texture memory (pitch and width can be
6363 * different) */
6364 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6365 for(i = 0; i < height; i++)
6366 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6367 IWineD3DSurface_UnlockRect(pCursorBitmap);
6369 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6371 ENTER_GL();
6373 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6375 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6376 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6379 /* Make sure that a proper texture unit is selected */
6380 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6381 checkGLcall("glActiveTextureARB");
6382 sampler = This->rev_tex_unit_map[0];
6383 if (sampler != WINED3D_UNMAPPED_STAGE)
6385 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6387 /* Create a new cursor texture */
6388 glGenTextures(1, &This->cursorTexture);
6389 checkGLcall("glGenTextures");
6390 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6391 checkGLcall("glBindTexture");
6392 /* Copy the bitmap memory into the cursor texture */
6393 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6394 HeapFree(GetProcessHeap(), 0, mem);
6395 checkGLcall("glTexImage2D");
6397 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6399 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6400 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6403 LEAVE_GL();
6405 context_release(context);
6407 else
6409 FIXME("A cursor texture was not returned.\n");
6410 This->cursorTexture = 0;
6413 else
6415 /* Draw a hardware cursor */
6416 ICONINFO cursorInfo;
6417 HCURSOR cursor;
6418 /* Create and clear maskBits because it is not needed for
6419 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6420 * chunks. */
6421 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6422 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6423 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6424 WINED3DLOCK_NO_DIRTY_UPDATE |
6425 WINED3DLOCK_READONLY
6427 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6428 pSur->currentDesc.Height);
6430 cursorInfo.fIcon = FALSE;
6431 cursorInfo.xHotspot = XHotSpot;
6432 cursorInfo.yHotspot = YHotSpot;
6433 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6434 1, 1, maskBits);
6435 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6436 1, 32, lockedRect.pBits);
6437 IWineD3DSurface_UnlockRect(pCursorBitmap);
6438 /* Create our cursor and clean up. */
6439 cursor = CreateIconIndirect(&cursorInfo);
6440 SetCursor(cursor);
6441 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6442 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6443 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6444 This->hardwareCursor = cursor;
6445 HeapFree(GetProcessHeap(), 0, maskBits);
6449 This->xHotSpot = XHotSpot;
6450 This->yHotSpot = YHotSpot;
6451 return WINED3D_OK;
6454 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6456 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6458 This->xScreenSpace = XScreenSpace;
6459 This->yScreenSpace = YScreenSpace;
6461 return;
6465 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6467 BOOL oldVisible = This->bCursorVisible;
6468 POINT pt;
6470 TRACE("(%p) : visible(%d)\n", This, bShow);
6473 * When ShowCursor is first called it should make the cursor appear at the OS's last
6474 * known cursor position. Because of this, some applications just repetitively call
6475 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6477 GetCursorPos(&pt);
6478 This->xScreenSpace = pt.x;
6479 This->yScreenSpace = pt.y;
6481 if (This->haveHardwareCursor) {
6482 This->bCursorVisible = bShow;
6483 if (bShow)
6484 SetCursor(This->hardwareCursor);
6485 else
6486 SetCursor(NULL);
6488 else
6490 if (This->cursorTexture)
6491 This->bCursorVisible = bShow;
6494 return oldVisible;
6497 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6499 IWineD3DResourceImpl *resource;
6500 TRACE("(%p) : state (%u)\n", This, This->state);
6502 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6503 switch (This->state) {
6504 case WINED3D_OK:
6505 return WINED3D_OK;
6506 case WINED3DERR_DEVICELOST:
6508 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6509 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6510 return WINED3DERR_DEVICENOTRESET;
6512 return WINED3DERR_DEVICELOST;
6514 case WINED3DERR_DRIVERINTERNALERROR:
6515 return WINED3DERR_DRIVERINTERNALERROR;
6518 /* Unknown state */
6519 return WINED3DERR_DRIVERINTERNALERROR;
6522 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6523 TRACE("checking resource %p for eviction\n", resource);
6524 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6525 TRACE("Evicting %p\n", resource);
6526 IWineD3DResource_UnLoad(resource);
6528 IWineD3DResource_Release(resource);
6529 return S_OK;
6532 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6534 TRACE("(%p)\n", This);
6536 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6537 return WINED3D_OK;
6540 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6542 IWineD3DDeviceImpl *device = surface->resource.wineD3DDevice;
6543 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6545 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6546 if(surface->Flags & SFLAG_DIBSECTION) {
6547 /* Release the DC */
6548 SelectObject(surface->hDC, surface->dib.holdbitmap);
6549 DeleteDC(surface->hDC);
6550 /* Release the DIB section */
6551 DeleteObject(surface->dib.DIBsection);
6552 surface->dib.bitmap_data = NULL;
6553 surface->resource.allocatedMemory = NULL;
6554 surface->Flags &= ~SFLAG_DIBSECTION;
6556 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6557 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6558 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6559 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6561 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6562 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6563 } else {
6564 surface->pow2Width = surface->pow2Height = 1;
6565 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6566 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6568 surface->glRect.left = 0;
6569 surface->glRect.top = 0;
6570 surface->glRect.right = surface->pow2Width;
6571 surface->glRect.bottom = surface->pow2Height;
6573 if (surface->texture_name)
6575 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6576 ENTER_GL();
6577 glDeleteTextures(1, &surface->texture_name);
6578 LEAVE_GL();
6579 context_release(context);
6580 surface->texture_name = 0;
6581 surface->Flags &= ~SFLAG_CLIENT;
6583 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6584 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6585 surface->Flags |= SFLAG_NONPOW2;
6586 } else {
6587 surface->Flags &= ~SFLAG_NONPOW2;
6589 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6590 surface->resource.allocatedMemory = NULL;
6591 surface->resource.heapMemory = NULL;
6592 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6593 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6594 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6595 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6596 } else {
6597 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6601 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6602 TRACE("Unloading resource %p\n", resource);
6603 IWineD3DResource_UnLoad(resource);
6604 IWineD3DResource_Release(resource);
6605 return S_OK;
6608 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6610 UINT i, count;
6611 WINED3DDISPLAYMODE m;
6612 HRESULT hr;
6614 /* All Windowed modes are supported, as is leaving the current mode */
6615 if(pp->Windowed) return TRUE;
6616 if(!pp->BackBufferWidth) return TRUE;
6617 if(!pp->BackBufferHeight) return TRUE;
6619 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6620 for(i = 0; i < count; i++) {
6621 memset(&m, 0, sizeof(m));
6622 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6623 if(FAILED(hr)) {
6624 ERR("EnumAdapterModes failed\n");
6626 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6627 /* Mode found, it is supported */
6628 return TRUE;
6631 /* Mode not found -> not supported */
6632 return FALSE;
6635 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6637 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6638 const struct wined3d_gl_info *gl_info;
6639 struct wined3d_context *context;
6640 UINT i;
6641 IWineD3DBaseShaderImpl *shader;
6643 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6644 gl_info = context->gl_info;
6646 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6647 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6648 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6651 ENTER_GL();
6652 if(This->depth_blt_texture) {
6653 glDeleteTextures(1, &This->depth_blt_texture);
6654 This->depth_blt_texture = 0;
6656 if (This->depth_blt_rb) {
6657 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6658 This->depth_blt_rb = 0;
6659 This->depth_blt_rb_w = 0;
6660 This->depth_blt_rb_h = 0;
6662 LEAVE_GL();
6664 This->blitter->free_private(iface);
6665 This->frag_pipe->free_private(iface);
6666 This->shader_backend->shader_free_private(iface);
6668 ENTER_GL();
6669 for (i = 0; i < This->adapter->gl_info.limits.textures; ++i)
6671 /* Textures are recreated below */
6672 glDeleteTextures(1, &This->dummyTextureName[i]);
6673 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6674 This->dummyTextureName[i] = 0;
6676 LEAVE_GL();
6678 context_release(context);
6680 while (This->numContexts)
6682 context_destroy(This, This->contexts[0]);
6684 HeapFree(GetProcessHeap(), 0, swapchain->context);
6685 swapchain->context = NULL;
6686 swapchain->num_contexts = 0;
6689 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6691 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6692 HRESULT hr;
6693 IWineD3DSurfaceImpl *target;
6695 /* Recreate the primary swapchain's context */
6696 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6697 if(swapchain->backBuffer) {
6698 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6699 } else {
6700 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6702 swapchain->context[0] = context_create(This, target, swapchain->win_handle, FALSE, &swapchain->presentParms);
6703 swapchain->num_contexts = 1;
6705 create_dummy_textures(This);
6707 context_release(swapchain->context[0]);
6709 hr = This->shader_backend->shader_alloc_private(iface);
6710 if(FAILED(hr)) {
6711 ERR("Failed to recreate shader private data\n");
6712 goto err_out;
6714 hr = This->frag_pipe->alloc_private(iface);
6715 if(FAILED(hr)) {
6716 TRACE("Fragment pipeline private data couldn't be allocated\n");
6717 goto err_out;
6719 hr = This->blitter->alloc_private(iface);
6720 if(FAILED(hr)) {
6721 TRACE("Blitter private data couldn't be allocated\n");
6722 goto err_out;
6725 return WINED3D_OK;
6727 err_out:
6728 This->blitter->free_private(iface);
6729 This->frag_pipe->free_private(iface);
6730 This->shader_backend->shader_free_private(iface);
6731 return hr;
6734 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6736 IWineD3DSwapChainImpl *swapchain;
6737 HRESULT hr;
6738 BOOL DisplayModeChanged = FALSE;
6739 WINED3DDISPLAYMODE mode;
6740 TRACE("(%p)\n", This);
6742 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6743 if(FAILED(hr)) {
6744 ERR("Failed to get the first implicit swapchain\n");
6745 return hr;
6748 if(!is_display_mode_supported(This, pPresentationParameters)) {
6749 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6750 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6751 pPresentationParameters->BackBufferHeight);
6752 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6753 return WINED3DERR_INVALIDCALL;
6756 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6757 * on an existing gl context, so there's no real need for recreation.
6759 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6761 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6763 TRACE("New params:\n");
6764 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6765 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6766 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6767 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6768 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6769 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6770 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6771 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6772 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6773 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6774 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6775 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6776 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6778 /* No special treatment of these parameters. Just store them */
6779 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6780 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6781 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6782 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6784 /* What to do about these? */
6785 if(pPresentationParameters->BackBufferCount != 0 &&
6786 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6787 ERR("Cannot change the back buffer count yet\n");
6789 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6790 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6791 ERR("Cannot change the back buffer format yet\n");
6793 if(pPresentationParameters->hDeviceWindow != NULL &&
6794 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6795 ERR("Cannot change the device window yet\n");
6797 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6798 HRESULT hrc;
6800 TRACE("Creating the depth stencil buffer\n");
6802 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6803 This->parent,
6804 pPresentationParameters->BackBufferWidth,
6805 pPresentationParameters->BackBufferHeight,
6806 pPresentationParameters->AutoDepthStencilFormat,
6807 pPresentationParameters->MultiSampleType,
6808 pPresentationParameters->MultiSampleQuality,
6809 FALSE,
6810 &This->auto_depth_stencil_buffer);
6812 if (FAILED(hrc)) {
6813 ERR("Failed to create the depth stencil buffer\n");
6814 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6815 return WINED3DERR_INVALIDCALL;
6819 /* Reset the depth stencil */
6820 if (pPresentationParameters->EnableAutoDepthStencil)
6821 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6822 else
6823 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6825 TRACE("Resetting stateblock\n");
6826 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6827 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6829 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6831 if(pPresentationParameters->Windowed) {
6832 mode.Width = swapchain->orig_width;
6833 mode.Height = swapchain->orig_height;
6834 mode.RefreshRate = 0;
6835 mode.Format = swapchain->presentParms.BackBufferFormat;
6836 } else {
6837 mode.Width = pPresentationParameters->BackBufferWidth;
6838 mode.Height = pPresentationParameters->BackBufferHeight;
6839 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6840 mode.Format = swapchain->presentParms.BackBufferFormat;
6843 /* Should Width == 800 && Height == 0 set 800x600? */
6844 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6845 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6846 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6848 UINT i;
6850 if(!pPresentationParameters->Windowed) {
6851 DisplayModeChanged = TRUE;
6853 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6854 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6856 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6857 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6858 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6860 if(This->auto_depth_stencil_buffer) {
6861 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6865 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6866 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6867 DisplayModeChanged) {
6869 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6871 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
6872 if(swapchain->presentParms.Windowed) {
6873 /* switch from windowed to fs */
6874 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
6875 pPresentationParameters->BackBufferWidth,
6876 pPresentationParameters->BackBufferHeight);
6877 } else {
6878 /* Fullscreen -> fullscreen mode change */
6879 MoveWindow(swapchain->win_handle, 0, 0,
6880 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6881 TRUE);
6883 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
6884 /* Fullscreen -> windowed switch */
6885 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
6887 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6888 } else if(!pPresentationParameters->Windowed) {
6889 DWORD style = This->style, exStyle = This->exStyle;
6890 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6891 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6892 * Reset to clear up their mess. Guild Wars also loses the device during that.
6894 This->style = 0;
6895 This->exStyle = 0;
6896 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
6897 pPresentationParameters->BackBufferWidth,
6898 pPresentationParameters->BackBufferHeight);
6899 This->style = style;
6900 This->exStyle = exStyle;
6903 /* Note: No parent needed for initial internal stateblock */
6904 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6905 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6906 else TRACE("Created stateblock %p\n", This->stateBlock);
6907 This->updateStateBlock = This->stateBlock;
6908 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6910 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6911 if(FAILED(hr)) {
6912 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6915 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6916 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6918 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6919 * first use
6921 return hr;
6924 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6926 /** FIXME: always true at the moment **/
6927 if(!bEnableDialogs) {
6928 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6930 return WINED3D_OK;
6934 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6936 TRACE("(%p) : pParameters %p\n", This, pParameters);
6938 *pParameters = This->createParms;
6939 return WINED3D_OK;
6942 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6943 IWineD3DSwapChain *swapchain;
6945 TRACE("Relaying to swapchain\n");
6947 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6948 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6949 IWineD3DSwapChain_Release(swapchain);
6951 return;
6954 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6955 IWineD3DSwapChain *swapchain;
6957 TRACE("Relaying to swapchain\n");
6959 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6960 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6961 IWineD3DSwapChain_Release(swapchain);
6963 return;
6967 /** ********************************************************
6968 * Notification functions
6969 ** ********************************************************/
6970 /** This function must be called in the release of a resource when ref == 0,
6971 * the contents of resource must still be correct,
6972 * any handles to other resource held by the caller must be closed
6973 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6974 *****************************************************/
6975 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6977 TRACE("(%p) : Adding resource %p\n", This, resource);
6979 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6982 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6984 TRACE("(%p) : Removing resource %p\n", This, resource);
6986 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6989 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6991 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6992 int counter;
6994 TRACE("(%p) : resource %p\n", This, resource);
6996 context_resource_released((IWineD3DDevice *)This, resource, type);
6998 switch (type) {
6999 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7000 case WINED3DRTYPE_SURFACE: {
7001 unsigned int i;
7003 if (This->d3d_initialized)
7005 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
7007 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7008 This->render_targets[i] = NULL;
7011 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7012 This->stencilBufferTarget = NULL;
7016 break;
7018 case WINED3DRTYPE_TEXTURE:
7019 case WINED3DRTYPE_CUBETEXTURE:
7020 case WINED3DRTYPE_VOLUMETEXTURE:
7021 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7022 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7023 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7024 This->stateBlock->textures[counter] = NULL;
7026 if (This->updateStateBlock != This->stateBlock ){
7027 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7028 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7029 This->updateStateBlock->textures[counter] = NULL;
7033 break;
7034 case WINED3DRTYPE_VOLUME:
7035 /* TODO: nothing really? */
7036 break;
7037 case WINED3DRTYPE_BUFFER:
7039 int streamNumber;
7040 TRACE("Cleaning up stream pointers\n");
7042 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7043 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7044 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7046 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7047 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7048 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7049 This->updateStateBlock->streamSource[streamNumber] = 0;
7050 /* Set changed flag? */
7053 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) */
7054 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7055 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7056 This->stateBlock->streamSource[streamNumber] = 0;
7061 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7062 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7063 This->updateStateBlock->pIndexData = NULL;
7066 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7067 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7068 This->stateBlock->pIndexData = NULL;
7072 break;
7074 default:
7075 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7076 break;
7080 /* Remove the resource from the resourceStore */
7081 device_resource_remove(This, resource);
7083 TRACE("Resource released\n");
7087 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7089 IWineD3DResourceImpl *resource, *cursor;
7090 HRESULT ret;
7091 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7093 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7094 TRACE("enumerating resource %p\n", resource);
7095 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7096 ret = pCallback((IWineD3DResource *) resource, pData);
7097 if(ret == S_FALSE) {
7098 TRACE("Canceling enumeration\n");
7099 break;
7102 return WINED3D_OK;
7105 /**********************************************************
7106 * IWineD3DDevice VTbl follows
7107 **********************************************************/
7109 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7111 /*** IUnknown methods ***/
7112 IWineD3DDeviceImpl_QueryInterface,
7113 IWineD3DDeviceImpl_AddRef,
7114 IWineD3DDeviceImpl_Release,
7115 /*** IWineD3DDevice methods ***/
7116 IWineD3DDeviceImpl_GetParent,
7117 /*** Creation methods**/
7118 IWineD3DDeviceImpl_CreateBuffer,
7119 IWineD3DDeviceImpl_CreateVertexBuffer,
7120 IWineD3DDeviceImpl_CreateIndexBuffer,
7121 IWineD3DDeviceImpl_CreateStateBlock,
7122 IWineD3DDeviceImpl_CreateSurface,
7123 IWineD3DDeviceImpl_CreateRendertargetView,
7124 IWineD3DDeviceImpl_CreateTexture,
7125 IWineD3DDeviceImpl_CreateVolumeTexture,
7126 IWineD3DDeviceImpl_CreateVolume,
7127 IWineD3DDeviceImpl_CreateCubeTexture,
7128 IWineD3DDeviceImpl_CreateQuery,
7129 IWineD3DDeviceImpl_CreateSwapChain,
7130 IWineD3DDeviceImpl_CreateVertexDeclaration,
7131 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7132 IWineD3DDeviceImpl_CreateVertexShader,
7133 IWineD3DDeviceImpl_CreatePixelShader,
7134 IWineD3DDeviceImpl_CreatePalette,
7135 /*** Odd functions **/
7136 IWineD3DDeviceImpl_Init3D,
7137 IWineD3DDeviceImpl_InitGDI,
7138 IWineD3DDeviceImpl_Uninit3D,
7139 IWineD3DDeviceImpl_UninitGDI,
7140 IWineD3DDeviceImpl_SetMultithreaded,
7141 IWineD3DDeviceImpl_EvictManagedResources,
7142 IWineD3DDeviceImpl_GetAvailableTextureMem,
7143 IWineD3DDeviceImpl_GetBackBuffer,
7144 IWineD3DDeviceImpl_GetCreationParameters,
7145 IWineD3DDeviceImpl_GetDeviceCaps,
7146 IWineD3DDeviceImpl_GetDirect3D,
7147 IWineD3DDeviceImpl_GetDisplayMode,
7148 IWineD3DDeviceImpl_SetDisplayMode,
7149 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7150 IWineD3DDeviceImpl_GetRasterStatus,
7151 IWineD3DDeviceImpl_GetSwapChain,
7152 IWineD3DDeviceImpl_Reset,
7153 IWineD3DDeviceImpl_SetDialogBoxMode,
7154 IWineD3DDeviceImpl_SetCursorProperties,
7155 IWineD3DDeviceImpl_SetCursorPosition,
7156 IWineD3DDeviceImpl_ShowCursor,
7157 IWineD3DDeviceImpl_TestCooperativeLevel,
7158 /*** Getters and setters **/
7159 IWineD3DDeviceImpl_SetClipPlane,
7160 IWineD3DDeviceImpl_GetClipPlane,
7161 IWineD3DDeviceImpl_SetClipStatus,
7162 IWineD3DDeviceImpl_GetClipStatus,
7163 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7164 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7165 IWineD3DDeviceImpl_SetDepthStencilSurface,
7166 IWineD3DDeviceImpl_GetDepthStencilSurface,
7167 IWineD3DDeviceImpl_SetGammaRamp,
7168 IWineD3DDeviceImpl_GetGammaRamp,
7169 IWineD3DDeviceImpl_SetIndexBuffer,
7170 IWineD3DDeviceImpl_GetIndexBuffer,
7171 IWineD3DDeviceImpl_SetBaseVertexIndex,
7172 IWineD3DDeviceImpl_GetBaseVertexIndex,
7173 IWineD3DDeviceImpl_SetLight,
7174 IWineD3DDeviceImpl_GetLight,
7175 IWineD3DDeviceImpl_SetLightEnable,
7176 IWineD3DDeviceImpl_GetLightEnable,
7177 IWineD3DDeviceImpl_SetMaterial,
7178 IWineD3DDeviceImpl_GetMaterial,
7179 IWineD3DDeviceImpl_SetNPatchMode,
7180 IWineD3DDeviceImpl_GetNPatchMode,
7181 IWineD3DDeviceImpl_SetPaletteEntries,
7182 IWineD3DDeviceImpl_GetPaletteEntries,
7183 IWineD3DDeviceImpl_SetPixelShader,
7184 IWineD3DDeviceImpl_GetPixelShader,
7185 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7186 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7187 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7188 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7189 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7190 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7191 IWineD3DDeviceImpl_SetRenderState,
7192 IWineD3DDeviceImpl_GetRenderState,
7193 IWineD3DDeviceImpl_SetRenderTarget,
7194 IWineD3DDeviceImpl_GetRenderTarget,
7195 IWineD3DDeviceImpl_SetFrontBackBuffers,
7196 IWineD3DDeviceImpl_SetSamplerState,
7197 IWineD3DDeviceImpl_GetSamplerState,
7198 IWineD3DDeviceImpl_SetScissorRect,
7199 IWineD3DDeviceImpl_GetScissorRect,
7200 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7201 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7202 IWineD3DDeviceImpl_SetStreamSource,
7203 IWineD3DDeviceImpl_GetStreamSource,
7204 IWineD3DDeviceImpl_SetStreamSourceFreq,
7205 IWineD3DDeviceImpl_GetStreamSourceFreq,
7206 IWineD3DDeviceImpl_SetTexture,
7207 IWineD3DDeviceImpl_GetTexture,
7208 IWineD3DDeviceImpl_SetTextureStageState,
7209 IWineD3DDeviceImpl_GetTextureStageState,
7210 IWineD3DDeviceImpl_SetTransform,
7211 IWineD3DDeviceImpl_GetTransform,
7212 IWineD3DDeviceImpl_SetVertexDeclaration,
7213 IWineD3DDeviceImpl_GetVertexDeclaration,
7214 IWineD3DDeviceImpl_SetVertexShader,
7215 IWineD3DDeviceImpl_GetVertexShader,
7216 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7217 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7218 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7219 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7220 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7221 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7222 IWineD3DDeviceImpl_SetViewport,
7223 IWineD3DDeviceImpl_GetViewport,
7224 IWineD3DDeviceImpl_MultiplyTransform,
7225 IWineD3DDeviceImpl_ValidateDevice,
7226 IWineD3DDeviceImpl_ProcessVertices,
7227 /*** State block ***/
7228 IWineD3DDeviceImpl_BeginStateBlock,
7229 IWineD3DDeviceImpl_EndStateBlock,
7230 /*** Scene management ***/
7231 IWineD3DDeviceImpl_BeginScene,
7232 IWineD3DDeviceImpl_EndScene,
7233 IWineD3DDeviceImpl_Present,
7234 IWineD3DDeviceImpl_Clear,
7235 IWineD3DDeviceImpl_ClearRendertargetView,
7236 /*** Drawing ***/
7237 IWineD3DDeviceImpl_SetPrimitiveType,
7238 IWineD3DDeviceImpl_GetPrimitiveType,
7239 IWineD3DDeviceImpl_DrawPrimitive,
7240 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7241 IWineD3DDeviceImpl_DrawPrimitiveUP,
7242 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7243 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7244 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7245 IWineD3DDeviceImpl_DrawRectPatch,
7246 IWineD3DDeviceImpl_DrawTriPatch,
7247 IWineD3DDeviceImpl_DeletePatch,
7248 IWineD3DDeviceImpl_ColorFill,
7249 IWineD3DDeviceImpl_UpdateTexture,
7250 IWineD3DDeviceImpl_UpdateSurface,
7251 IWineD3DDeviceImpl_GetFrontBufferData,
7252 /*** object tracking ***/
7253 IWineD3DDeviceImpl_EnumResources
7256 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7257 DWORD rep = This->StateTable[state].representative;
7258 struct wined3d_context *context;
7259 DWORD idx;
7260 BYTE shift;
7261 UINT i;
7263 for(i = 0; i < This->numContexts; i++) {
7264 context = This->contexts[i];
7265 if(isStateDirty(context, rep)) continue;
7267 context->dirtyArray[context->numDirtyEntries++] = rep;
7268 idx = rep >> 5;
7269 shift = rep & 0x1f;
7270 context->isStateDirty[idx] |= (1 << shift);
7274 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7276 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.wineD3DDevice;
7277 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7278 *width = device->pbufferWidth;
7279 *height = device->pbufferHeight;
7282 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7284 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7285 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7286 *width = surface->pow2Width;
7287 *height = surface->pow2Height;
7290 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7292 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7293 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7294 * current context's drawable, which is the size of the back buffer of the swapchain
7295 * the active context belongs to. The back buffer of the swapchain is stored as the
7296 * surface the context belongs to. */
7297 *width = surface->currentDesc.Width;
7298 *height = surface->currentDesc.Height;