wined3d: Add a usage flag for static buffer declarations.
[wine/hacks.git] / dlls / wined3d / device.c
blobe6931ea98a9f9a833548c9c59d6d040c25abea53
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);
1215 /*********************
1216 * Create the back, front and stencil buffers
1217 *******************/
1218 if(object->presentParms.BackBufferCount > 0) {
1219 UINT i;
1221 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1222 if(!object->backBuffer) {
1223 ERR("Out of memory\n");
1224 hr = E_OUTOFMEMORY;
1225 goto error;
1228 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1229 TRACE("calling rendertarget CB\n");
1230 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1231 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1232 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1233 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1234 if(SUCCEEDED(hr)) {
1235 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1236 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1237 } else {
1238 ERR("Cannot create new back buffer\n");
1239 goto error;
1241 if(surface_type == SURFACE_OPENGL) {
1242 ENTER_GL();
1243 glDrawBuffer(GL_BACK);
1244 checkGLcall("glDrawBuffer(GL_BACK)");
1245 LEAVE_GL();
1248 } else {
1249 object->backBuffer = NULL;
1251 /* Single buffering - draw to front buffer */
1252 if(surface_type == SURFACE_OPENGL) {
1253 ENTER_GL();
1254 glDrawBuffer(GL_FRONT);
1255 checkGLcall("glDrawBuffer(GL_FRONT)");
1256 LEAVE_GL();
1260 if (object->context[0]) context_release(object->context[0]);
1262 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1263 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1264 TRACE("Creating depth stencil buffer\n");
1265 if (This->auto_depth_stencil_buffer == NULL ) {
1266 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1267 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1268 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1269 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1270 &This->auto_depth_stencil_buffer);
1271 if (SUCCEEDED(hr)) {
1272 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1273 } else {
1274 ERR("Failed to create the auto depth stencil\n");
1275 goto error;
1280 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1282 TRACE("Created swapchain %p\n", object);
1283 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1284 return WINED3D_OK;
1286 error:
1287 if (displaymode_set) {
1288 DEVMODEW devmode;
1289 RECT clip_rc;
1291 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1292 ClipCursor(NULL);
1294 /* Change the display settings */
1295 memset(&devmode, 0, sizeof(devmode));
1296 devmode.dmSize = sizeof(devmode);
1297 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1298 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1299 devmode.dmPelsWidth = object->orig_width;
1300 devmode.dmPelsHeight = object->orig_height;
1301 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1304 if (object->backBuffer) {
1305 UINT i;
1306 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1307 if (object->backBuffer[i]) IWineD3DSurface_Release(object->backBuffer[i]);
1309 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1310 object->backBuffer = NULL;
1312 if(object->context && object->context[0])
1314 context_release(object->context[0]);
1315 context_destroy(This, object->context[0]);
1317 if (object->frontBuffer) IWineD3DSurface_Release(object->frontBuffer);
1318 HeapFree(GetProcessHeap(), 0, object);
1319 return hr;
1322 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1323 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1325 TRACE("(%p)\n", This);
1327 return This->NumberOfSwapChains;
1330 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1332 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1334 if(iSwapChain < This->NumberOfSwapChains) {
1335 *pSwapChain = This->swapchains[iSwapChain];
1336 IWineD3DSwapChain_AddRef(*pSwapChain);
1337 TRACE("(%p) returning %p\n", This, *pSwapChain);
1338 return WINED3D_OK;
1339 } else {
1340 TRACE("Swapchain out of range\n");
1341 *pSwapChain = NULL;
1342 return WINED3DERR_INVALIDCALL;
1346 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1347 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1348 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1351 IWineD3DVertexDeclarationImpl *object = NULL;
1352 HRESULT hr;
1354 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1355 iface, declaration, parent, elements, element_count);
1357 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1358 if(!object)
1360 ERR("Failed to allocate vertex declaration memory.\n");
1361 return E_OUTOFMEMORY;
1364 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1365 if (FAILED(hr))
1367 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1368 HeapFree(GetProcessHeap(), 0, object);
1369 return hr;
1372 TRACE("Created vertex declaration %p.\n", object);
1373 *declaration = (IWineD3DVertexDeclaration *)object;
1375 return WINED3D_OK;
1378 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1379 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1381 unsigned int idx, idx2;
1382 unsigned int offset;
1383 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1384 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1385 BOOL has_blend_idx = has_blend &&
1386 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1387 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1388 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1389 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1390 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1391 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1392 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1394 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1395 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1396 WINED3DVERTEXELEMENT *elements = NULL;
1398 unsigned int size;
1399 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1400 if (has_blend_idx) num_blends--;
1402 /* Compute declaration size */
1403 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1404 has_psize + has_diffuse + has_specular + num_textures;
1406 /* convert the declaration */
1407 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1408 if (!elements) return ~0U;
1410 idx = 0;
1411 if (has_pos) {
1412 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1413 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1414 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1416 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1417 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1418 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1420 else {
1421 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1422 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1424 elements[idx].usage_idx = 0;
1425 idx++;
1427 if (has_blend && (num_blends > 0)) {
1428 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1429 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1430 else {
1431 switch(num_blends) {
1432 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1433 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1434 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1435 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1436 default:
1437 ERR("Unexpected amount of blend values: %u\n", num_blends);
1440 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1441 elements[idx].usage_idx = 0;
1442 idx++;
1444 if (has_blend_idx) {
1445 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1446 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1447 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1448 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1449 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1450 else
1451 elements[idx].format = WINED3DFMT_R32_FLOAT;
1452 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1453 elements[idx].usage_idx = 0;
1454 idx++;
1456 if (has_normal) {
1457 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1458 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1459 elements[idx].usage_idx = 0;
1460 idx++;
1462 if (has_psize) {
1463 elements[idx].format = WINED3DFMT_R32_FLOAT;
1464 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1465 elements[idx].usage_idx = 0;
1466 idx++;
1468 if (has_diffuse) {
1469 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1470 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1471 elements[idx].usage_idx = 0;
1472 idx++;
1474 if (has_specular) {
1475 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1476 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1477 elements[idx].usage_idx = 1;
1478 idx++;
1480 for (idx2 = 0; idx2 < num_textures; idx2++) {
1481 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1482 switch (numcoords) {
1483 case WINED3DFVF_TEXTUREFORMAT1:
1484 elements[idx].format = WINED3DFMT_R32_FLOAT;
1485 break;
1486 case WINED3DFVF_TEXTUREFORMAT2:
1487 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1488 break;
1489 case WINED3DFVF_TEXTUREFORMAT3:
1490 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1491 break;
1492 case WINED3DFVF_TEXTUREFORMAT4:
1493 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1494 break;
1496 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1497 elements[idx].usage_idx = idx2;
1498 idx++;
1501 /* Now compute offsets, and initialize the rest of the fields */
1502 for (idx = 0, offset = 0; idx < size; ++idx)
1504 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1505 elements[idx].input_slot = 0;
1506 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1507 elements[idx].offset = offset;
1508 offset += format_desc->component_count * format_desc->component_size;
1511 *ppVertexElements = elements;
1512 return size;
1515 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1516 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1517 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1520 WINED3DVERTEXELEMENT *elements;
1521 unsigned int size;
1522 DWORD hr;
1524 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1526 size = ConvertFvfToDeclaration(This, fvf, &elements);
1527 if (size == ~0U) return E_OUTOFMEMORY;
1529 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1530 HeapFree(GetProcessHeap(), 0, elements);
1531 return hr;
1534 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1535 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1536 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1537 const struct wined3d_parent_ops *parent_ops)
1539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1540 IWineD3DVertexShaderImpl *object;
1541 HRESULT hr;
1543 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1544 if (!object)
1546 ERR("Failed to allocate shader memory.\n");
1547 return E_OUTOFMEMORY;
1550 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1551 if (FAILED(hr))
1553 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1554 HeapFree(GetProcessHeap(), 0, object);
1555 return hr;
1558 TRACE("Created vertex shader %p.\n", object);
1559 *ppVertexShader = (IWineD3DVertexShader *)object;
1561 return WINED3D_OK;
1564 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1565 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1566 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1567 const struct wined3d_parent_ops *parent_ops)
1569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1570 IWineD3DPixelShaderImpl *object;
1571 HRESULT hr;
1573 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1574 if (!object)
1576 ERR("Failed to allocate shader memory.\n");
1577 return E_OUTOFMEMORY;
1580 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1581 if (FAILED(hr))
1583 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1584 HeapFree(GetProcessHeap(), 0, object);
1585 return hr;
1588 TRACE("Created pixel shader %p.\n", object);
1589 *ppPixelShader = (IWineD3DPixelShader *)object;
1591 return WINED3D_OK;
1594 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1595 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1598 IWineD3DPaletteImpl *object;
1599 HRESULT hr;
1600 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1602 /* Create the new object */
1603 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1604 if(!object) {
1605 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1606 return E_OUTOFMEMORY;
1609 object->lpVtbl = &IWineD3DPalette_Vtbl;
1610 object->ref = 1;
1611 object->Flags = Flags;
1612 object->parent = Parent;
1613 object->wineD3DDevice = This;
1614 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1615 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1617 if(!object->hpal) {
1618 HeapFree( GetProcessHeap(), 0, object);
1619 return E_OUTOFMEMORY;
1622 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1623 if(FAILED(hr)) {
1624 IWineD3DPalette_Release((IWineD3DPalette *) object);
1625 return hr;
1628 *Palette = (IWineD3DPalette *) object;
1630 return WINED3D_OK;
1633 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1634 HBITMAP hbm;
1635 BITMAP bm;
1636 HRESULT hr;
1637 HDC dcb = NULL, dcs = NULL;
1638 WINEDDCOLORKEY colorkey;
1640 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1641 if(hbm)
1643 GetObjectA(hbm, sizeof(BITMAP), &bm);
1644 dcb = CreateCompatibleDC(NULL);
1645 if(!dcb) goto out;
1646 SelectObject(dcb, hbm);
1648 else
1650 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1651 * couldn't be loaded
1653 memset(&bm, 0, sizeof(bm));
1654 bm.bmWidth = 32;
1655 bm.bmHeight = 32;
1658 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1659 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1660 NULL, &wined3d_null_parent_ops);
1661 if(FAILED(hr)) {
1662 ERR("Wine logo requested, but failed to create surface\n");
1663 goto out;
1666 if(dcb) {
1667 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1668 if(FAILED(hr)) goto out;
1669 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1670 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1672 colorkey.dwColorSpaceLowValue = 0;
1673 colorkey.dwColorSpaceHighValue = 0;
1674 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1675 } else {
1676 /* Fill the surface with a white color to show that wined3d is there */
1677 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1680 out:
1681 if(dcb) {
1682 DeleteDC(dcb);
1684 if(hbm) {
1685 DeleteObject(hbm);
1687 return;
1690 /* Context activation is done by the caller. */
1691 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1693 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1694 unsigned int i;
1695 /* Under DirectX you can have texture stage operations even if no texture is
1696 bound, whereas opengl will only do texture operations when a valid texture is
1697 bound. We emulate this by creating dummy textures and binding them to each
1698 texture stage, but disable all stages by default. Hence if a stage is enabled
1699 then the default texture will kick in until replaced by a SetTexture call */
1700 ENTER_GL();
1702 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1704 /* The dummy texture does not have client storage backing */
1705 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1706 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1709 for (i = 0; i < gl_info->limits.textures; ++i)
1711 GLubyte white = 255;
1713 /* Make appropriate texture active */
1714 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1715 checkGLcall("glActiveTextureARB");
1717 /* Generate an opengl texture name */
1718 glGenTextures(1, &This->dummyTextureName[i]);
1719 checkGLcall("glGenTextures");
1720 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1722 /* Generate a dummy 2d texture (not using 1d because they cause many
1723 * DRI drivers fall back to sw) */
1724 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1725 checkGLcall("glBindTexture");
1727 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1728 checkGLcall("glTexImage2D");
1731 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1733 /* Reenable because if supported it is enabled by default */
1734 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1735 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1738 LEAVE_GL();
1741 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1742 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1745 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1746 IWineD3DSwapChainImpl *swapchain = NULL;
1747 struct wined3d_context *context;
1748 HRESULT hr;
1749 DWORD state;
1750 unsigned int i;
1752 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1754 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1755 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1757 /* TODO: Test if OpenGL is compiled in and loaded */
1759 TRACE("(%p) : Creating stateblock\n", This);
1760 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1761 hr = IWineD3DDevice_CreateStateBlock(iface,
1762 WINED3DSBT_INIT,
1763 (IWineD3DStateBlock **)&This->stateBlock,
1764 NULL);
1765 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1766 WARN("Failed to create stateblock\n");
1767 goto err_out;
1769 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1770 This->updateStateBlock = This->stateBlock;
1771 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1773 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1774 sizeof(IWineD3DSurface *) * gl_info->limits.buffers);
1775 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1776 sizeof(GLenum) * gl_info->limits.buffers);
1778 This->NumberOfPalettes = 1;
1779 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1780 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1781 ERR("Out of memory!\n");
1782 goto err_out;
1784 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1785 if(!This->palettes[0]) {
1786 ERR("Out of memory!\n");
1787 goto err_out;
1789 for (i = 0; i < 256; ++i) {
1790 This->palettes[0][i].peRed = 0xFF;
1791 This->palettes[0][i].peGreen = 0xFF;
1792 This->palettes[0][i].peBlue = 0xFF;
1793 This->palettes[0][i].peFlags = 0xFF;
1795 This->currentPalette = 0;
1797 /* Initialize the texture unit mapping to a 1:1 mapping */
1798 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1800 if (state < gl_info->limits.fragment_samplers)
1802 This->texUnitMap[state] = state;
1803 This->rev_tex_unit_map[state] = state;
1804 } else {
1805 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1806 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1810 /* Setup the implicit swapchain. This also initializes a context. */
1811 TRACE("Creating implicit swapchain\n");
1812 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1813 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1814 if (FAILED(hr))
1816 WARN("Failed to create implicit swapchain\n");
1817 goto err_out;
1820 This->NumberOfSwapChains = 1;
1821 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1822 if(!This->swapchains) {
1823 ERR("Out of memory!\n");
1824 goto err_out;
1826 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1828 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1829 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1830 This->render_targets[0] = swapchain->backBuffer[0];
1832 else {
1833 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1834 This->render_targets[0] = swapchain->frontBuffer;
1836 IWineD3DSurface_AddRef(This->render_targets[0]);
1838 /* Depth Stencil support */
1839 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1840 if (NULL != This->stencilBufferTarget) {
1841 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1844 hr = This->shader_backend->shader_alloc_private(iface);
1845 if(FAILED(hr)) {
1846 TRACE("Shader private data couldn't be allocated\n");
1847 goto err_out;
1849 hr = This->frag_pipe->alloc_private(iface);
1850 if(FAILED(hr)) {
1851 TRACE("Fragment pipeline private data couldn't be allocated\n");
1852 goto err_out;
1854 hr = This->blitter->alloc_private(iface);
1855 if(FAILED(hr)) {
1856 TRACE("Blitter private data couldn't be allocated\n");
1857 goto err_out;
1860 /* Set up some starting GL setup */
1862 /* Setup all the devices defaults */
1863 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1865 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1867 create_dummy_textures(This);
1869 ENTER_GL();
1871 /* Initialize the current view state */
1872 This->view_ident = 1;
1873 This->contexts[0]->last_was_rhw = 0;
1874 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1875 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1877 switch(wined3d_settings.offscreen_rendering_mode) {
1878 case ORM_FBO:
1879 case ORM_PBUFFER:
1880 This->offscreenBuffer = GL_BACK;
1881 break;
1883 case ORM_BACKBUFFER:
1885 if (context_get_current()->aux_buffers > 0)
1887 TRACE("Using auxilliary buffer for offscreen rendering\n");
1888 This->offscreenBuffer = GL_AUX0;
1889 } else {
1890 TRACE("Using back buffer for offscreen rendering\n");
1891 This->offscreenBuffer = GL_BACK;
1896 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1897 LEAVE_GL();
1899 context_release(context);
1901 /* Clear the screen */
1902 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1903 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1904 0x00, 1.0f, 0);
1906 This->d3d_initialized = TRUE;
1908 if(wined3d_settings.logo) {
1909 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1911 This->highest_dirty_ps_const = 0;
1912 This->highest_dirty_vs_const = 0;
1913 return WINED3D_OK;
1915 err_out:
1916 HeapFree(GetProcessHeap(), 0, This->render_targets);
1917 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1918 HeapFree(GetProcessHeap(), 0, This->swapchains);
1919 This->NumberOfSwapChains = 0;
1920 if(This->palettes) {
1921 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1922 HeapFree(GetProcessHeap(), 0, This->palettes);
1924 This->NumberOfPalettes = 0;
1925 if(swapchain) {
1926 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1928 if(This->stateBlock) {
1929 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1930 This->stateBlock = NULL;
1932 if (This->blit_priv) {
1933 This->blitter->free_private(iface);
1935 if (This->fragment_priv) {
1936 This->frag_pipe->free_private(iface);
1938 if (This->shader_priv) {
1939 This->shader_backend->shader_free_private(iface);
1941 return hr;
1944 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1945 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1948 IWineD3DSwapChainImpl *swapchain = NULL;
1949 HRESULT hr;
1951 /* Setup the implicit swapchain */
1952 TRACE("Creating implicit swapchain\n");
1953 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1954 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1955 if (FAILED(hr))
1957 WARN("Failed to create implicit swapchain\n");
1958 goto err_out;
1961 This->NumberOfSwapChains = 1;
1962 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1963 if(!This->swapchains) {
1964 ERR("Out of memory!\n");
1965 goto err_out;
1967 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1968 return WINED3D_OK;
1970 err_out:
1971 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1972 return hr;
1975 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1977 IWineD3DResource_UnLoad(resource);
1978 IWineD3DResource_Release(resource);
1979 return WINED3D_OK;
1982 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1983 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1986 const struct wined3d_gl_info *gl_info;
1987 struct wined3d_context *context;
1988 int sampler;
1989 UINT i;
1990 TRACE("(%p)\n", This);
1992 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1994 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1995 * it was created. Thus make sure a context is active for the glDelete* calls
1997 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1998 gl_info = context->gl_info;
2000 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2002 /* Unload resources */
2003 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2005 TRACE("Deleting high order patches\n");
2006 for(i = 0; i < PATCHMAP_SIZE; i++) {
2007 struct list *e1, *e2;
2008 struct WineD3DRectPatch *patch;
2009 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2010 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2011 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2015 /* Delete the palette conversion shader if it is around */
2016 if(This->paletteConversionShader) {
2017 ENTER_GL();
2018 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2019 LEAVE_GL();
2020 This->paletteConversionShader = 0;
2023 /* Delete the pbuffer context if there is any */
2024 if(This->pbufferContext) context_destroy(This, This->pbufferContext);
2026 /* Delete the mouse cursor texture */
2027 if(This->cursorTexture) {
2028 ENTER_GL();
2029 glDeleteTextures(1, &This->cursorTexture);
2030 LEAVE_GL();
2031 This->cursorTexture = 0;
2034 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2035 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2037 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2038 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2041 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2042 * private data, it might contain opengl pointers
2044 if(This->depth_blt_texture) {
2045 ENTER_GL();
2046 glDeleteTextures(1, &This->depth_blt_texture);
2047 LEAVE_GL();
2048 This->depth_blt_texture = 0;
2050 if (This->depth_blt_rb) {
2051 ENTER_GL();
2052 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2053 LEAVE_GL();
2054 This->depth_blt_rb = 0;
2055 This->depth_blt_rb_w = 0;
2056 This->depth_blt_rb_h = 0;
2059 /* Release the update stateblock */
2060 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2061 if(This->updateStateBlock != This->stateBlock)
2062 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2064 This->updateStateBlock = NULL;
2066 { /* because were not doing proper internal refcounts releasing the primary state block
2067 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2068 to set this->stateBlock = NULL; first */
2069 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2070 This->stateBlock = NULL;
2072 /* Release the stateblock */
2073 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2074 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2078 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2079 This->blitter->free_private(iface);
2080 This->frag_pipe->free_private(iface);
2081 This->shader_backend->shader_free_private(iface);
2083 /* Release the buffers (with sanity checks)*/
2084 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2085 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2086 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2087 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2089 This->stencilBufferTarget = NULL;
2091 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2092 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2093 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2095 TRACE("Setting rendertarget to NULL\n");
2096 This->render_targets[0] = NULL;
2098 if (This->auto_depth_stencil_buffer) {
2099 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
2101 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2103 This->auto_depth_stencil_buffer = NULL;
2106 context_release(context);
2108 for(i=0; i < This->NumberOfSwapChains; i++) {
2109 TRACE("Releasing the implicit swapchain %d\n", i);
2110 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2111 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2115 HeapFree(GetProcessHeap(), 0, This->swapchains);
2116 This->swapchains = NULL;
2117 This->NumberOfSwapChains = 0;
2119 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2120 HeapFree(GetProcessHeap(), 0, This->palettes);
2121 This->palettes = NULL;
2122 This->NumberOfPalettes = 0;
2124 HeapFree(GetProcessHeap(), 0, This->render_targets);
2125 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2126 This->render_targets = NULL;
2127 This->draw_buffers = NULL;
2129 This->d3d_initialized = FALSE;
2130 return WINED3D_OK;
2133 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2135 unsigned int i;
2137 for(i=0; i < This->NumberOfSwapChains; i++) {
2138 TRACE("Releasing the implicit swapchain %d\n", i);
2139 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2140 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2144 HeapFree(GetProcessHeap(), 0, This->swapchains);
2145 This->swapchains = NULL;
2146 This->NumberOfSwapChains = 0;
2147 return WINED3D_OK;
2150 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2151 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2152 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2154 * There is no way to deactivate thread safety once it is enabled.
2156 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2159 /*For now just store the flag(needed in case of ddraw) */
2160 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2162 return;
2165 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2166 const WINED3DDISPLAYMODE* pMode) {
2167 DEVMODEW devmode;
2168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2169 LONG ret;
2170 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
2171 RECT clip_rc;
2173 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2175 /* Resize the screen even without a window:
2176 * The app could have unset it with SetCooperativeLevel, but not called
2177 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2178 * but we don't have any hwnd
2181 memset(&devmode, 0, sizeof(devmode));
2182 devmode.dmSize = sizeof(devmode);
2183 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2184 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2185 devmode.dmPelsWidth = pMode->Width;
2186 devmode.dmPelsHeight = pMode->Height;
2188 devmode.dmDisplayFrequency = pMode->RefreshRate;
2189 if (pMode->RefreshRate != 0) {
2190 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2193 /* Only change the mode if necessary */
2194 if( (This->ddraw_width == pMode->Width) &&
2195 (This->ddraw_height == pMode->Height) &&
2196 (This->ddraw_format == pMode->Format) &&
2197 (pMode->RefreshRate == 0) ) {
2198 return WINED3D_OK;
2201 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2202 if (ret != DISP_CHANGE_SUCCESSFUL) {
2203 if(devmode.dmDisplayFrequency != 0) {
2204 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2205 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2206 devmode.dmDisplayFrequency = 0;
2207 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2209 if(ret != DISP_CHANGE_SUCCESSFUL) {
2210 return WINED3DERR_NOTAVAILABLE;
2214 /* Store the new values */
2215 This->ddraw_width = pMode->Width;
2216 This->ddraw_height = pMode->Height;
2217 This->ddraw_format = pMode->Format;
2219 /* And finally clip mouse to our screen */
2220 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2221 ClipCursor(&clip_rc);
2223 return WINED3D_OK;
2226 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2228 *ppD3D= This->wineD3D;
2229 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2230 IWineD3D_AddRef(*ppD3D);
2231 return WINED3D_OK;
2234 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2237 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2238 (This->adapter->TextureRam/(1024*1024)),
2239 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2240 /* return simulated texture memory left */
2241 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2244 /*****
2245 * Get / Set Stream Source
2246 *****/
2247 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2248 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2251 IWineD3DBuffer *oldSrc;
2253 if (StreamNumber >= MAX_STREAMS) {
2254 WARN("Stream out of range %d\n", StreamNumber);
2255 return WINED3DERR_INVALIDCALL;
2256 } else if(OffsetInBytes & 0x3) {
2257 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2258 return WINED3DERR_INVALIDCALL;
2261 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2262 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2264 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2266 if(oldSrc == pStreamData &&
2267 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2268 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2269 TRACE("Application is setting the old values over, nothing to do\n");
2270 return WINED3D_OK;
2273 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2274 if (pStreamData) {
2275 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2276 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2279 /* Handle recording of state blocks */
2280 if (This->isRecordingState) {
2281 TRACE("Recording... not performing anything\n");
2282 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2283 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2284 return WINED3D_OK;
2287 if (pStreamData != NULL) {
2288 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2289 IWineD3DBuffer_AddRef(pStreamData);
2291 if (oldSrc != NULL) {
2292 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2293 IWineD3DBuffer_Release(oldSrc);
2296 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2298 return WINED3D_OK;
2301 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2302 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2306 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2307 This->stateBlock->streamSource[StreamNumber],
2308 This->stateBlock->streamOffset[StreamNumber],
2309 This->stateBlock->streamStride[StreamNumber]);
2311 if (StreamNumber >= MAX_STREAMS) {
2312 WARN("Stream out of range %d\n", StreamNumber);
2313 return WINED3DERR_INVALIDCALL;
2315 *pStream = This->stateBlock->streamSource[StreamNumber];
2316 *pStride = This->stateBlock->streamStride[StreamNumber];
2317 if (pOffset) {
2318 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2321 if (*pStream != NULL) {
2322 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2324 return WINED3D_OK;
2327 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2329 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2330 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2332 /* Verify input at least in d3d9 this is invalid*/
2333 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2334 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2335 return WINED3DERR_INVALIDCALL;
2337 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2338 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2339 return WINED3DERR_INVALIDCALL;
2341 if( Divider == 0 ){
2342 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2343 return WINED3DERR_INVALIDCALL;
2346 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2347 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2349 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2350 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2352 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2353 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2354 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2357 return WINED3D_OK;
2360 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2363 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2364 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2366 TRACE("(%p) : returning %d\n", This, *Divider);
2368 return WINED3D_OK;
2371 /*****
2372 * Get / Set & Multiply Transform
2373 *****/
2374 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2377 /* Most of this routine, comments included copied from ddraw tree initially: */
2378 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2380 /* Handle recording of state blocks */
2381 if (This->isRecordingState) {
2382 TRACE("Recording... not performing anything\n");
2383 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2384 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2385 return WINED3D_OK;
2389 * If the new matrix is the same as the current one,
2390 * we cut off any further processing. this seems to be a reasonable
2391 * optimization because as was noticed, some apps (warcraft3 for example)
2392 * tend towards setting the same matrix repeatedly for some reason.
2394 * From here on we assume that the new matrix is different, wherever it matters.
2396 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2397 TRACE("The app is setting the same matrix over again\n");
2398 return WINED3D_OK;
2399 } else {
2400 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2404 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2405 where ViewMat = Camera space, WorldMat = world space.
2407 In OpenGL, camera and world space is combined into GL_MODELVIEW
2408 matrix. The Projection matrix stay projection matrix.
2411 /* Capture the times we can just ignore the change for now */
2412 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2413 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2414 /* Handled by the state manager */
2417 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2418 return WINED3D_OK;
2421 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2423 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2424 *pMatrix = This->stateBlock->transforms[State];
2425 return WINED3D_OK;
2428 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2429 const WINED3DMATRIX *mat = NULL;
2430 WINED3DMATRIX temp;
2432 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2433 * below means it will be recorded in a state block change, but it
2434 * works regardless where it is recorded.
2435 * If this is found to be wrong, change to StateBlock.
2437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2438 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2440 if (State <= HIGHEST_TRANSFORMSTATE)
2442 mat = &This->updateStateBlock->transforms[State];
2443 } else {
2444 FIXME("Unhandled transform state!!\n");
2447 multiply_matrix(&temp, mat, pMatrix);
2449 /* Apply change via set transform - will reapply to eg. lights this way */
2450 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2453 /*****
2454 * Get / Set Light
2455 *****/
2456 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2457 you can reference any indexes you want as long as that number max are enabled at any
2458 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2459 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2460 but when recording, just build a chain pretty much of commands to be replayed. */
2462 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2463 float rho;
2464 struct wined3d_light_info *object = NULL;
2465 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2466 struct list *e;
2468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2469 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2471 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2472 * the gl driver.
2474 if(!pLight) {
2475 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2476 return WINED3DERR_INVALIDCALL;
2479 switch(pLight->Type) {
2480 case WINED3DLIGHT_POINT:
2481 case WINED3DLIGHT_SPOT:
2482 case WINED3DLIGHT_PARALLELPOINT:
2483 case WINED3DLIGHT_GLSPOT:
2484 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2485 * most wanted
2487 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2489 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2490 return WINED3DERR_INVALIDCALL;
2492 break;
2494 case WINED3DLIGHT_DIRECTIONAL:
2495 /* Ignores attenuation */
2496 break;
2498 default:
2499 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2500 return WINED3DERR_INVALIDCALL;
2503 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2505 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2506 if(object->OriginalIndex == Index) break;
2507 object = NULL;
2510 if(!object) {
2511 TRACE("Adding new light\n");
2512 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2513 if(!object) {
2514 ERR("Out of memory error when allocating a light\n");
2515 return E_OUTOFMEMORY;
2517 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2518 object->glIndex = -1;
2519 object->OriginalIndex = Index;
2522 /* Initialize the object */
2523 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,
2524 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2525 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2526 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2527 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2528 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2529 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2531 /* Save away the information */
2532 object->OriginalParms = *pLight;
2534 switch (pLight->Type) {
2535 case WINED3DLIGHT_POINT:
2536 /* Position */
2537 object->lightPosn[0] = pLight->Position.x;
2538 object->lightPosn[1] = pLight->Position.y;
2539 object->lightPosn[2] = pLight->Position.z;
2540 object->lightPosn[3] = 1.0f;
2541 object->cutoff = 180.0f;
2542 /* FIXME: Range */
2543 break;
2545 case WINED3DLIGHT_DIRECTIONAL:
2546 /* Direction */
2547 object->lightPosn[0] = -pLight->Direction.x;
2548 object->lightPosn[1] = -pLight->Direction.y;
2549 object->lightPosn[2] = -pLight->Direction.z;
2550 object->lightPosn[3] = 0.0f;
2551 object->exponent = 0.0f;
2552 object->cutoff = 180.0f;
2553 break;
2555 case WINED3DLIGHT_SPOT:
2556 /* Position */
2557 object->lightPosn[0] = pLight->Position.x;
2558 object->lightPosn[1] = pLight->Position.y;
2559 object->lightPosn[2] = pLight->Position.z;
2560 object->lightPosn[3] = 1.0f;
2562 /* Direction */
2563 object->lightDirn[0] = pLight->Direction.x;
2564 object->lightDirn[1] = pLight->Direction.y;
2565 object->lightDirn[2] = pLight->Direction.z;
2566 object->lightDirn[3] = 1.0f;
2569 * opengl-ish and d3d-ish spot lights use too different models for the
2570 * light "intensity" as a function of the angle towards the main light direction,
2571 * so we only can approximate very roughly.
2572 * however spot lights are rather rarely used in games (if ever used at all).
2573 * furthermore if still used, probably nobody pays attention to such details.
2575 if (pLight->Falloff == 0) {
2576 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2577 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2578 * will always be 1.0 for both of them, and we don't have to care for the
2579 * rest of the rather complex calculation
2581 object->exponent = 0.0f;
2582 } else {
2583 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2584 if (rho < 0.0001f) rho = 0.0001f;
2585 object->exponent = -0.3f/logf(cosf(rho/2));
2587 if (object->exponent > 128.0f)
2589 object->exponent = 128.0f;
2591 object->cutoff = pLight->Phi*90/M_PI;
2593 /* FIXME: Range */
2594 break;
2596 default:
2597 FIXME("Unrecognized light type %d\n", pLight->Type);
2600 /* Update the live definitions if the light is currently assigned a glIndex */
2601 if (object->glIndex != -1 && !This->isRecordingState) {
2602 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2604 return WINED3D_OK;
2607 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2609 struct wined3d_light_info *lightInfo = NULL;
2610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2611 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2612 struct list *e;
2613 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2615 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2617 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2618 if(lightInfo->OriginalIndex == Index) break;
2619 lightInfo = NULL;
2622 if (lightInfo == NULL) {
2623 TRACE("Light information requested but light not defined\n");
2624 return WINED3DERR_INVALIDCALL;
2627 *pLight = lightInfo->OriginalParms;
2628 return WINED3D_OK;
2631 /*****
2632 * Get / Set Light Enable
2633 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2634 *****/
2635 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2637 struct wined3d_light_info *lightInfo = NULL;
2638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2639 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2640 struct list *e;
2641 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2643 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2645 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2646 if(lightInfo->OriginalIndex == Index) break;
2647 lightInfo = NULL;
2649 TRACE("Found light: %p\n", lightInfo);
2651 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2652 if (lightInfo == NULL) {
2654 TRACE("Light enabled requested but light not defined, so defining one!\n");
2655 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2657 /* Search for it again! Should be fairly quick as near head of list */
2658 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2660 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2661 if(lightInfo->OriginalIndex == Index) break;
2662 lightInfo = NULL;
2664 if (lightInfo == NULL) {
2665 FIXME("Adding default lights has failed dismally\n");
2666 return WINED3DERR_INVALIDCALL;
2670 if(!Enable) {
2671 if(lightInfo->glIndex != -1) {
2672 if(!This->isRecordingState) {
2673 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2676 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2677 lightInfo->glIndex = -1;
2678 } else {
2679 TRACE("Light already disabled, nothing to do\n");
2681 lightInfo->enabled = FALSE;
2682 } else {
2683 lightInfo->enabled = TRUE;
2684 if (lightInfo->glIndex != -1) {
2685 /* nop */
2686 TRACE("Nothing to do as light was enabled\n");
2687 } else {
2688 int i;
2689 /* Find a free gl light */
2690 for(i = 0; i < This->maxConcurrentLights; i++) {
2691 if(This->updateStateBlock->activeLights[i] == NULL) {
2692 This->updateStateBlock->activeLights[i] = lightInfo;
2693 lightInfo->glIndex = i;
2694 break;
2697 if(lightInfo->glIndex == -1) {
2698 /* Our tests show that Windows returns D3D_OK in this situation, even with
2699 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2700 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2701 * as well for those lights.
2703 * TODO: Test how this affects rendering
2705 WARN("Too many concurrently active lights\n");
2706 return WINED3D_OK;
2709 /* i == lightInfo->glIndex */
2710 if(!This->isRecordingState) {
2711 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2716 return WINED3D_OK;
2719 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2721 struct wined3d_light_info *lightInfo = NULL;
2722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2723 struct list *e;
2724 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2725 TRACE("(%p) : for idx(%d)\n", This, Index);
2727 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2729 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2730 if(lightInfo->OriginalIndex == Index) break;
2731 lightInfo = NULL;
2734 if (lightInfo == NULL) {
2735 TRACE("Light enabled state requested but light not defined\n");
2736 return WINED3DERR_INVALIDCALL;
2738 /* true is 128 according to SetLightEnable */
2739 *pEnable = lightInfo->enabled ? 128 : 0;
2740 return WINED3D_OK;
2743 /*****
2744 * Get / Set Clip Planes
2745 *****/
2746 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2748 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2750 /* Validate Index */
2751 if (Index >= This->adapter->gl_info.limits.clipplanes)
2753 TRACE("Application has requested clipplane this device doesn't support\n");
2754 return WINED3DERR_INVALIDCALL;
2757 This->updateStateBlock->changed.clipplane |= 1 << Index;
2759 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2760 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2761 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2762 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2763 TRACE("Application is setting old values over, nothing to do\n");
2764 return WINED3D_OK;
2767 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2768 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2769 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2770 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2772 /* Handle recording of state blocks */
2773 if (This->isRecordingState) {
2774 TRACE("Recording... not performing anything\n");
2775 return WINED3D_OK;
2778 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2780 return WINED3D_OK;
2783 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2785 TRACE("(%p) : for idx %d\n", This, Index);
2787 /* Validate Index */
2788 if (Index >= This->adapter->gl_info.limits.clipplanes)
2790 TRACE("Application has requested clipplane this device doesn't support\n");
2791 return WINED3DERR_INVALIDCALL;
2794 pPlane[0] = This->stateBlock->clipplane[Index][0];
2795 pPlane[1] = This->stateBlock->clipplane[Index][1];
2796 pPlane[2] = This->stateBlock->clipplane[Index][2];
2797 pPlane[3] = This->stateBlock->clipplane[Index][3];
2798 return WINED3D_OK;
2801 /*****
2802 * Get / Set Clip Plane Status
2803 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2804 *****/
2805 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2807 FIXME("(%p) : stub\n", This);
2808 if (NULL == pClipStatus) {
2809 return WINED3DERR_INVALIDCALL;
2811 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2812 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2813 return WINED3D_OK;
2816 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2818 FIXME("(%p) : stub\n", This);
2819 if (NULL == pClipStatus) {
2820 return WINED3DERR_INVALIDCALL;
2822 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2823 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2824 return WINED3D_OK;
2827 /*****
2828 * Get / Set Material
2829 *****/
2830 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2833 This->updateStateBlock->changed.material = TRUE;
2834 This->updateStateBlock->material = *pMaterial;
2836 /* Handle recording of state blocks */
2837 if (This->isRecordingState) {
2838 TRACE("Recording... not performing anything\n");
2839 return WINED3D_OK;
2842 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2843 return WINED3D_OK;
2846 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2848 *pMaterial = This->updateStateBlock->material;
2849 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2850 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2851 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2852 pMaterial->Ambient.b, pMaterial->Ambient.a);
2853 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2854 pMaterial->Specular.b, pMaterial->Specular.a);
2855 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2856 pMaterial->Emissive.b, pMaterial->Emissive.a);
2857 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2859 return WINED3D_OK;
2862 /*****
2863 * Get / Set Indices
2864 *****/
2865 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2866 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2869 IWineD3DBuffer *oldIdxs;
2871 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2872 oldIdxs = This->updateStateBlock->pIndexData;
2874 This->updateStateBlock->changed.indices = TRUE;
2875 This->updateStateBlock->pIndexData = pIndexData;
2876 This->updateStateBlock->IndexFmt = fmt;
2878 /* Handle recording of state blocks */
2879 if (This->isRecordingState) {
2880 TRACE("Recording... not performing anything\n");
2881 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2882 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2883 return WINED3D_OK;
2886 if(oldIdxs != pIndexData) {
2887 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2888 if(pIndexData) {
2889 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2890 IWineD3DBuffer_AddRef(pIndexData);
2892 if(oldIdxs) {
2893 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2894 IWineD3DBuffer_Release(oldIdxs);
2898 return WINED3D_OK;
2901 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2905 *ppIndexData = This->stateBlock->pIndexData;
2907 /* up ref count on ppindexdata */
2908 if (*ppIndexData) {
2909 IWineD3DBuffer_AddRef(*ppIndexData);
2910 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2911 }else{
2912 TRACE("(%p) No index data set\n", This);
2914 TRACE("Returning %p\n", *ppIndexData);
2916 return WINED3D_OK;
2919 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2920 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2922 TRACE("(%p)->(%d)\n", This, BaseIndex);
2924 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2925 TRACE("Application is setting the old value over, nothing to do\n");
2926 return WINED3D_OK;
2929 This->updateStateBlock->baseVertexIndex = BaseIndex;
2931 if (This->isRecordingState) {
2932 TRACE("Recording... not performing anything\n");
2933 return WINED3D_OK;
2935 /* The base vertex index affects the stream sources */
2936 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2937 return WINED3D_OK;
2940 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2942 TRACE("(%p) : base_index %p\n", This, base_index);
2944 *base_index = This->stateBlock->baseVertexIndex;
2946 TRACE("Returning %u\n", *base_index);
2948 return WINED3D_OK;
2951 /*****
2952 * Get / Set Viewports
2953 *****/
2954 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2957 TRACE("(%p)\n", This);
2958 This->updateStateBlock->changed.viewport = TRUE;
2959 This->updateStateBlock->viewport = *pViewport;
2961 /* Handle recording of state blocks */
2962 if (This->isRecordingState) {
2963 TRACE("Recording... not performing anything\n");
2964 return WINED3D_OK;
2967 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2968 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2970 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2971 return WINED3D_OK;
2975 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2977 TRACE("(%p)\n", This);
2978 *pViewport = This->stateBlock->viewport;
2979 return WINED3D_OK;
2982 /*****
2983 * Get / Set Render States
2984 * TODO: Verify against dx9 definitions
2985 *****/
2986 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2989 DWORD oldValue = This->stateBlock->renderState[State];
2991 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2993 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2994 This->updateStateBlock->renderState[State] = Value;
2996 /* Handle recording of state blocks */
2997 if (This->isRecordingState) {
2998 TRACE("Recording... not performing anything\n");
2999 return WINED3D_OK;
3002 /* Compared here and not before the assignment to allow proper stateblock recording */
3003 if(Value == oldValue) {
3004 TRACE("Application is setting the old value over, nothing to do\n");
3005 } else {
3006 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3009 return WINED3D_OK;
3012 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3014 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3015 *pValue = This->stateBlock->renderState[State];
3016 return WINED3D_OK;
3019 /*****
3020 * Get / Set Sampler States
3021 * TODO: Verify against dx9 definitions
3022 *****/
3024 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3026 DWORD oldValue;
3028 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3029 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3031 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3032 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3035 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3036 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3037 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3040 * SetSampler is designed to allow for more than the standard up to 8 textures
3041 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3042 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3044 * http://developer.nvidia.com/object/General_FAQ.html#t6
3046 * There are two new settings for GForce
3047 * the sampler one:
3048 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3049 * and the texture one:
3050 * GL_MAX_TEXTURE_COORDS_ARB.
3051 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3052 ******************/
3054 oldValue = This->stateBlock->samplerState[Sampler][Type];
3055 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3056 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3058 /* Handle recording of state blocks */
3059 if (This->isRecordingState) {
3060 TRACE("Recording... not performing anything\n");
3061 return WINED3D_OK;
3064 if(oldValue == Value) {
3065 TRACE("Application is setting the old value over, nothing to do\n");
3066 return WINED3D_OK;
3069 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3071 return WINED3D_OK;
3074 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3077 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3078 This, Sampler, debug_d3dsamplerstate(Type), Type);
3080 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3081 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3084 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3085 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3086 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3088 *Value = This->stateBlock->samplerState[Sampler][Type];
3089 TRACE("(%p) : Returning %#x\n", This, *Value);
3091 return WINED3D_OK;
3094 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3097 This->updateStateBlock->changed.scissorRect = TRUE;
3098 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3099 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3100 return WINED3D_OK;
3102 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3104 if(This->isRecordingState) {
3105 TRACE("Recording... not performing anything\n");
3106 return WINED3D_OK;
3109 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3111 return WINED3D_OK;
3114 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3117 *pRect = This->updateStateBlock->scissorRect;
3118 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3119 return WINED3D_OK;
3122 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3124 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3126 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3128 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3129 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3131 This->updateStateBlock->vertexDecl = pDecl;
3132 This->updateStateBlock->changed.vertexDecl = TRUE;
3134 if (This->isRecordingState) {
3135 TRACE("Recording... not performing anything\n");
3136 return WINED3D_OK;
3137 } else if(pDecl == oldDecl) {
3138 /* Checked after the assignment to allow proper stateblock recording */
3139 TRACE("Application is setting the old declaration over, nothing to do\n");
3140 return WINED3D_OK;
3143 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3144 return WINED3D_OK;
3147 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3150 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3152 *ppDecl = This->stateBlock->vertexDecl;
3153 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3154 return WINED3D_OK;
3157 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3159 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3161 This->updateStateBlock->vertexShader = pShader;
3162 This->updateStateBlock->changed.vertexShader = TRUE;
3164 if (This->isRecordingState) {
3165 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3166 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3167 TRACE("Recording... not performing anything\n");
3168 return WINED3D_OK;
3169 } else if(oldShader == pShader) {
3170 /* Checked here to allow proper stateblock recording */
3171 TRACE("App is setting the old shader over, nothing to do\n");
3172 return WINED3D_OK;
3175 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3176 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3177 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3179 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3181 return WINED3D_OK;
3184 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3187 if (NULL == ppShader) {
3188 return WINED3DERR_INVALIDCALL;
3190 *ppShader = This->stateBlock->vertexShader;
3191 if( NULL != *ppShader)
3192 IWineD3DVertexShader_AddRef(*ppShader);
3194 TRACE("(%p) : returning %p\n", This, *ppShader);
3195 return WINED3D_OK;
3198 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3199 IWineD3DDevice *iface,
3200 UINT start,
3201 CONST BOOL *srcData,
3202 UINT count) {
3204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3205 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3207 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3208 iface, srcData, start, count);
3210 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3212 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3213 for (i = 0; i < cnt; i++)
3214 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3216 for (i = start; i < cnt + start; ++i) {
3217 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3220 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3222 return WINED3D_OK;
3225 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3226 IWineD3DDevice *iface,
3227 UINT start,
3228 BOOL *dstData,
3229 UINT count) {
3231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3232 int cnt = min(count, MAX_CONST_B - start);
3234 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3235 iface, dstData, start, count);
3237 if (dstData == NULL || cnt < 0)
3238 return WINED3DERR_INVALIDCALL;
3240 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3241 return WINED3D_OK;
3244 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3245 IWineD3DDevice *iface,
3246 UINT start,
3247 CONST int *srcData,
3248 UINT count) {
3250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3251 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3253 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3254 iface, srcData, start, count);
3256 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3258 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3259 for (i = 0; i < cnt; i++)
3260 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3261 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3263 for (i = start; i < cnt + start; ++i) {
3264 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3267 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3269 return WINED3D_OK;
3272 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3273 IWineD3DDevice *iface,
3274 UINT start,
3275 int *dstData,
3276 UINT count) {
3278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3279 int cnt = min(count, MAX_CONST_I - start);
3281 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3282 iface, dstData, start, count);
3284 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3285 return WINED3DERR_INVALIDCALL;
3287 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3288 return WINED3D_OK;
3291 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3292 IWineD3DDevice *iface,
3293 UINT start,
3294 CONST float *srcData,
3295 UINT count) {
3297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3298 UINT i;
3300 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3301 iface, srcData, start, count);
3303 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3304 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3305 return WINED3DERR_INVALIDCALL;
3307 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3308 if(TRACE_ON(d3d)) {
3309 for (i = 0; i < count; i++)
3310 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3311 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3314 if (!This->isRecordingState)
3316 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3317 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3320 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3321 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3323 return WINED3D_OK;
3326 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3327 IWineD3DDevice *iface,
3328 UINT start,
3329 float *dstData,
3330 UINT count) {
3332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3333 int cnt = min(count, This->d3d_vshader_constantF - start);
3335 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3336 iface, dstData, start, count);
3338 if (dstData == NULL || cnt < 0)
3339 return WINED3DERR_INVALIDCALL;
3341 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3342 return WINED3D_OK;
3345 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3346 DWORD i;
3347 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3349 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3353 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3355 DWORD i = This->rev_tex_unit_map[unit];
3356 DWORD j = This->texUnitMap[stage];
3358 This->texUnitMap[stage] = unit;
3359 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3361 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3364 This->rev_tex_unit_map[unit] = stage;
3365 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3367 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3371 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3372 int i;
3374 This->fixed_function_usage_map = 0;
3375 for (i = 0; i < MAX_TEXTURES; ++i) {
3376 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3377 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3378 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3379 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3380 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3381 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3382 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3383 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3385 if (color_op == WINED3DTOP_DISABLE) {
3386 /* Not used, and disable higher stages */
3387 break;
3390 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3391 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3392 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3393 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3394 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3395 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3396 This->fixed_function_usage_map |= (1 << i);
3399 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3400 This->fixed_function_usage_map |= (1 << (i + 1));
3405 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3406 unsigned int i, tex;
3407 WORD ffu_map;
3409 device_update_fixed_function_usage_map(This);
3410 ffu_map = This->fixed_function_usage_map;
3412 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3413 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3414 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3416 if (!(ffu_map & 1)) continue;
3418 if (This->texUnitMap[i] != i) {
3419 device_map_stage(This, i, i);
3420 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3421 markTextureStagesDirty(This, i);
3424 return;
3427 /* Now work out the mapping */
3428 tex = 0;
3429 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3431 if (!(ffu_map & 1)) continue;
3433 if (This->texUnitMap[i] != tex) {
3434 device_map_stage(This, i, tex);
3435 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3436 markTextureStagesDirty(This, i);
3439 ++tex;
3443 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3444 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3445 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3446 unsigned int i;
3448 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3449 if (sampler_type[i] && This->texUnitMap[i] != i)
3451 device_map_stage(This, i, i);
3452 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3453 if (i < MAX_TEXTURES) {
3454 markTextureStagesDirty(This, i);
3460 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3461 const DWORD *vshader_sampler_tokens, DWORD unit)
3463 DWORD current_mapping = This->rev_tex_unit_map[unit];
3465 /* Not currently used */
3466 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3468 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3469 /* Used by a fragment sampler */
3471 if (!pshader_sampler_tokens) {
3472 /* No pixel shader, check fixed function */
3473 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3476 /* Pixel shader, check the shader's sampler map */
3477 return !pshader_sampler_tokens[current_mapping];
3480 /* Used by a vertex sampler */
3481 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3484 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3485 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3486 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3487 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3488 int start = min(MAX_COMBINED_SAMPLERS, This->adapter->gl_info.limits.combined_samplers) - 1;
3489 int i;
3491 if (ps) {
3492 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3494 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3495 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3496 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3499 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3500 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3501 if (vshader_sampler_type[i])
3503 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3505 /* Already mapped somewhere */
3506 continue;
3509 while (start >= 0) {
3510 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3512 device_map_stage(This, vsampler_idx, start);
3513 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3515 --start;
3516 break;
3519 --start;
3525 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3526 BOOL vs = use_vs(This->stateBlock);
3527 BOOL ps = use_ps(This->stateBlock);
3529 * Rules are:
3530 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3531 * that would be really messy and require shader recompilation
3532 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3533 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3535 if (ps) {
3536 device_map_psamplers(This);
3537 } else {
3538 device_map_fixed_function_samplers(This);
3541 if (vs) {
3542 device_map_vsamplers(This, ps);
3546 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3548 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3549 This->updateStateBlock->pixelShader = pShader;
3550 This->updateStateBlock->changed.pixelShader = TRUE;
3552 /* Handle recording of state blocks */
3553 if (This->isRecordingState) {
3554 TRACE("Recording... not performing anything\n");
3557 if (This->isRecordingState) {
3558 TRACE("Recording... not performing anything\n");
3559 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3560 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3561 return WINED3D_OK;
3564 if(pShader == oldShader) {
3565 TRACE("App is setting the old pixel shader over, nothing to do\n");
3566 return WINED3D_OK;
3569 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3570 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3572 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3573 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3575 return WINED3D_OK;
3578 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3581 if (NULL == ppShader) {
3582 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3583 return WINED3DERR_INVALIDCALL;
3586 *ppShader = This->stateBlock->pixelShader;
3587 if (NULL != *ppShader) {
3588 IWineD3DPixelShader_AddRef(*ppShader);
3590 TRACE("(%p) : returning %p\n", This, *ppShader);
3591 return WINED3D_OK;
3594 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3595 IWineD3DDevice *iface,
3596 UINT start,
3597 CONST BOOL *srcData,
3598 UINT count) {
3600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3601 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3603 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3604 iface, srcData, start, count);
3606 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3608 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3609 for (i = 0; i < cnt; i++)
3610 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3612 for (i = start; i < cnt + start; ++i) {
3613 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3616 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3618 return WINED3D_OK;
3621 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3622 IWineD3DDevice *iface,
3623 UINT start,
3624 BOOL *dstData,
3625 UINT count) {
3627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3628 int cnt = min(count, MAX_CONST_B - start);
3630 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3631 iface, dstData, start, count);
3633 if (dstData == NULL || cnt < 0)
3634 return WINED3DERR_INVALIDCALL;
3636 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3637 return WINED3D_OK;
3640 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3641 IWineD3DDevice *iface,
3642 UINT start,
3643 CONST int *srcData,
3644 UINT count) {
3646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3647 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3649 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3650 iface, srcData, start, count);
3652 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3654 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3655 for (i = 0; i < cnt; i++)
3656 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3657 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3659 for (i = start; i < cnt + start; ++i) {
3660 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3663 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3665 return WINED3D_OK;
3668 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3669 IWineD3DDevice *iface,
3670 UINT start,
3671 int *dstData,
3672 UINT count) {
3674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3675 int cnt = min(count, MAX_CONST_I - start);
3677 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3678 iface, dstData, start, count);
3680 if (dstData == NULL || cnt < 0)
3681 return WINED3DERR_INVALIDCALL;
3683 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3684 return WINED3D_OK;
3687 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3688 IWineD3DDevice *iface,
3689 UINT start,
3690 CONST float *srcData,
3691 UINT count) {
3693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3694 UINT i;
3696 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3697 iface, srcData, start, count);
3699 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3700 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3701 return WINED3DERR_INVALIDCALL;
3703 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3704 if(TRACE_ON(d3d)) {
3705 for (i = 0; i < count; i++)
3706 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3707 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3710 if (!This->isRecordingState)
3712 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3713 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3716 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3717 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3719 return WINED3D_OK;
3722 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3723 IWineD3DDevice *iface,
3724 UINT start,
3725 float *dstData,
3726 UINT count) {
3728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3729 int cnt = min(count, This->d3d_pshader_constantF - start);
3731 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3732 iface, dstData, start, count);
3734 if (dstData == NULL || cnt < 0)
3735 return WINED3DERR_INVALIDCALL;
3737 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3738 return WINED3D_OK;
3741 /* Context activation is done by the caller. */
3742 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3743 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3744 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3745 DWORD DestFVF)
3747 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3748 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3749 unsigned int i;
3750 WINED3DVIEWPORT vp;
3751 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3752 BOOL doClip;
3753 DWORD numTextures;
3755 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3757 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3760 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3762 ERR("Source has no position mask\n");
3763 return WINED3DERR_INVALIDCALL;
3766 /* We might access VBOs from this code, so hold the lock */
3767 ENTER_GL();
3769 if (dest->resource.allocatedMemory == NULL) {
3770 buffer_get_sysmem(dest);
3773 /* Get a pointer into the destination vbo(create one if none exists) and
3774 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3776 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3778 dest->flags |= WINED3D_BUFFER_CREATEBO;
3779 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3782 if (dest->buffer_object)
3784 unsigned char extrabytes = 0;
3785 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3786 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3787 * this may write 4 extra bytes beyond the area that should be written
3789 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3790 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3791 if(!dest_conv_addr) {
3792 ERR("Out of memory\n");
3793 /* Continue without storing converted vertices */
3795 dest_conv = dest_conv_addr;
3798 /* Should I clip?
3799 * a) WINED3DRS_CLIPPING is enabled
3800 * b) WINED3DVOP_CLIP is passed
3802 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3803 static BOOL warned = FALSE;
3805 * The clipping code is not quite correct. Some things need
3806 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3807 * so disable clipping for now.
3808 * (The graphics in Half-Life are broken, and my processvertices
3809 * test crashes with IDirect3DDevice3)
3810 doClip = TRUE;
3812 doClip = FALSE;
3813 if(!warned) {
3814 warned = TRUE;
3815 FIXME("Clipping is broken and disabled for now\n");
3817 } else doClip = FALSE;
3818 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3820 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3821 WINED3DTS_VIEW,
3822 &view_mat);
3823 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3824 WINED3DTS_PROJECTION,
3825 &proj_mat);
3826 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3827 WINED3DTS_WORLDMATRIX(0),
3828 &world_mat);
3830 TRACE("View mat:\n");
3831 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);
3832 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);
3833 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);
3834 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);
3836 TRACE("Proj mat:\n");
3837 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);
3838 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);
3839 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);
3840 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);
3842 TRACE("World mat:\n");
3843 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);
3844 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);
3845 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);
3846 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);
3848 /* Get the viewport */
3849 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3850 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3851 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3853 multiply_matrix(&mat,&view_mat,&world_mat);
3854 multiply_matrix(&mat,&proj_mat,&mat);
3856 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3858 for (i = 0; i < dwCount; i+= 1) {
3859 unsigned int tex_index;
3861 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3862 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3863 /* The position first */
3864 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3865 const float *p = (const float *)(element->data + i * element->stride);
3866 float x, y, z, rhw;
3867 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3869 /* Multiplication with world, view and projection matrix */
3870 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);
3871 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);
3872 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);
3873 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);
3875 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3877 /* WARNING: The following things are taken from d3d7 and were not yet checked
3878 * against d3d8 or d3d9!
3881 /* Clipping conditions: From msdn
3883 * A vertex is clipped if it does not match the following requirements
3884 * -rhw < x <= rhw
3885 * -rhw < y <= rhw
3886 * 0 < z <= rhw
3887 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3889 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3890 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3894 if( !doClip ||
3895 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3896 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3897 ( rhw > eps ) ) ) {
3899 /* "Normal" viewport transformation (not clipped)
3900 * 1) The values are divided by rhw
3901 * 2) The y axis is negative, so multiply it with -1
3902 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3903 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3904 * 4) Multiply x with Width/2 and add Width/2
3905 * 5) The same for the height
3906 * 6) Add the viewpoint X and Y to the 2D coordinates and
3907 * The minimum Z value to z
3908 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3910 * Well, basically it's simply a linear transformation into viewport
3911 * coordinates
3914 x /= rhw;
3915 y /= rhw;
3916 z /= rhw;
3918 y *= -1;
3920 x *= vp.Width / 2;
3921 y *= vp.Height / 2;
3922 z *= vp.MaxZ - vp.MinZ;
3924 x += vp.Width / 2 + vp.X;
3925 y += vp.Height / 2 + vp.Y;
3926 z += vp.MinZ;
3928 rhw = 1 / rhw;
3929 } else {
3930 /* That vertex got clipped
3931 * Contrary to OpenGL it is not dropped completely, it just
3932 * undergoes a different calculation.
3934 TRACE("Vertex got clipped\n");
3935 x += rhw;
3936 y += rhw;
3938 x /= 2;
3939 y /= 2;
3941 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3942 * outside of the main vertex buffer memory. That needs some more
3943 * investigation...
3947 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3950 ( (float *) dest_ptr)[0] = x;
3951 ( (float *) dest_ptr)[1] = y;
3952 ( (float *) dest_ptr)[2] = z;
3953 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3955 dest_ptr += 3 * sizeof(float);
3957 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3958 dest_ptr += sizeof(float);
3961 if(dest_conv) {
3962 float w = 1 / rhw;
3963 ( (float *) dest_conv)[0] = x * w;
3964 ( (float *) dest_conv)[1] = y * w;
3965 ( (float *) dest_conv)[2] = z * w;
3966 ( (float *) dest_conv)[3] = w;
3968 dest_conv += 3 * sizeof(float);
3970 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3971 dest_conv += sizeof(float);
3975 if (DestFVF & WINED3DFVF_PSIZE) {
3976 dest_ptr += sizeof(DWORD);
3977 if(dest_conv) dest_conv += sizeof(DWORD);
3979 if (DestFVF & WINED3DFVF_NORMAL) {
3980 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3981 const float *normal = (const float *)(element->data + i * element->stride);
3982 /* AFAIK this should go into the lighting information */
3983 FIXME("Didn't expect the destination to have a normal\n");
3984 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3985 if(dest_conv) {
3986 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3990 if (DestFVF & WINED3DFVF_DIFFUSE) {
3991 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3992 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3993 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3995 static BOOL warned = FALSE;
3997 if(!warned) {
3998 ERR("No diffuse color in source, but destination has one\n");
3999 warned = TRUE;
4002 *( (DWORD *) dest_ptr) = 0xffffffff;
4003 dest_ptr += sizeof(DWORD);
4005 if(dest_conv) {
4006 *( (DWORD *) dest_conv) = 0xffffffff;
4007 dest_conv += sizeof(DWORD);
4010 else {
4011 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4012 if(dest_conv) {
4013 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4014 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4015 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4016 dest_conv += sizeof(DWORD);
4021 if (DestFVF & WINED3DFVF_SPECULAR)
4023 /* What's the color value in the feedback buffer? */
4024 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4025 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4026 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4028 static BOOL warned = FALSE;
4030 if(!warned) {
4031 ERR("No specular color in source, but destination has one\n");
4032 warned = TRUE;
4035 *( (DWORD *) dest_ptr) = 0xFF000000;
4036 dest_ptr += sizeof(DWORD);
4038 if(dest_conv) {
4039 *( (DWORD *) dest_conv) = 0xFF000000;
4040 dest_conv += sizeof(DWORD);
4043 else {
4044 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4045 if(dest_conv) {
4046 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4047 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4048 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4049 dest_conv += sizeof(DWORD);
4054 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4055 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4056 const float *tex_coord = (const float *)(element->data + i * element->stride);
4057 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4059 ERR("No source texture, but destination requests one\n");
4060 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4061 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4063 else {
4064 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4065 if(dest_conv) {
4066 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4072 if(dest_conv) {
4073 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4074 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4075 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4076 dwCount * get_flexible_vertex_size(DestFVF),
4077 dest_conv_addr));
4078 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4079 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4082 LEAVE_GL();
4084 return WINED3D_OK;
4086 #undef copy_and_next
4088 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4089 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4090 DWORD DestFVF)
4092 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4093 struct wined3d_stream_info stream_info;
4094 struct wined3d_context *context;
4095 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4096 HRESULT hr;
4098 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4100 if(pVertexDecl) {
4101 ERR("Output vertex declaration not implemented yet\n");
4104 /* Need any context to write to the vbo. */
4105 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4107 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4108 * control the streamIsUP flag, thus restore it afterwards.
4110 This->stateBlock->streamIsUP = FALSE;
4111 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4112 This->stateBlock->streamIsUP = streamWasUP;
4114 if(vbo || SrcStartIndex) {
4115 unsigned int i;
4116 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4117 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4119 * Also get the start index in, but only loop over all elements if there's something to add at all.
4121 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4123 struct wined3d_stream_info_element *e;
4125 if (!(stream_info.use_map & (1 << i))) continue;
4127 e = &stream_info.elements[i];
4128 if (e->buffer_object)
4130 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4131 e->buffer_object = 0;
4132 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4133 ENTER_GL();
4134 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4135 vb->buffer_object = 0;
4136 LEAVE_GL();
4138 if (e->data) e->data += e->stride * SrcStartIndex;
4142 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4143 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4145 context_release(context);
4147 return hr;
4150 /*****
4151 * Get / Set Texture Stage States
4152 * TODO: Verify against dx9 definitions
4153 *****/
4154 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4156 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4158 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4160 if (Stage >= MAX_TEXTURES) {
4161 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4162 return WINED3D_OK;
4165 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4166 This->updateStateBlock->textureState[Stage][Type] = Value;
4168 if (This->isRecordingState) {
4169 TRACE("Recording... not performing anything\n");
4170 return WINED3D_OK;
4173 /* Checked after the assignments to allow proper stateblock recording */
4174 if(oldValue == Value) {
4175 TRACE("App is setting the old value over, nothing to do\n");
4176 return WINED3D_OK;
4179 if(Stage > This->stateBlock->lowest_disabled_stage &&
4180 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4181 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4182 * Changes in other states are important on disabled stages too
4184 return WINED3D_OK;
4187 if(Type == WINED3DTSS_COLOROP) {
4188 unsigned int i;
4190 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4191 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4192 * they have to be disabled
4194 * The current stage is dirtified below.
4196 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4197 TRACE("Additionally dirtifying stage %u\n", i);
4198 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4200 This->stateBlock->lowest_disabled_stage = Stage;
4201 TRACE("New lowest disabled: %u\n", Stage);
4202 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4203 /* Previously disabled stage enabled. Stages above it may need enabling
4204 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4205 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4207 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4210 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4212 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4213 break;
4215 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4216 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4218 This->stateBlock->lowest_disabled_stage = i;
4219 TRACE("New lowest disabled: %u\n", i);
4223 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4225 return WINED3D_OK;
4228 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4230 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4231 *pValue = This->updateStateBlock->textureState[Stage][Type];
4232 return WINED3D_OK;
4235 /*****
4236 * Get / Set Texture
4237 *****/
4238 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4239 DWORD stage, IWineD3DBaseTexture *texture)
4241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4242 IWineD3DBaseTexture *prev;
4244 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4246 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4247 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4249 /* Windows accepts overflowing this array... we do not. */
4250 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4252 WARN("Ignoring invalid stage %u.\n", stage);
4253 return WINED3D_OK;
4256 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4257 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4259 WARN("Rejecting attempt to set scratch texture.\n");
4260 return WINED3DERR_INVALIDCALL;
4263 This->updateStateBlock->changed.textures |= 1 << stage;
4265 prev = This->updateStateBlock->textures[stage];
4266 TRACE("Previous texture %p.\n", prev);
4268 if (texture == prev)
4270 TRACE("App is setting the same texture again, nothing to do.\n");
4271 return WINED3D_OK;
4274 TRACE("Setting new texture to %p.\n", texture);
4275 This->updateStateBlock->textures[stage] = texture;
4277 if (This->isRecordingState)
4279 TRACE("Recording... not performing anything\n");
4281 if (texture) IWineD3DBaseTexture_AddRef(texture);
4282 if (prev) IWineD3DBaseTexture_Release(prev);
4284 return WINED3D_OK;
4287 if (texture)
4289 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4290 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4291 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4293 IWineD3DBaseTexture_AddRef(texture);
4295 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4297 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4300 if (!prev && stage < MAX_TEXTURES)
4302 /* The source arguments for color and alpha ops have different
4303 * meanings when a NULL texture is bound, so the COLOROP and
4304 * ALPHAOP have to be dirtified. */
4305 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4306 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4309 if (bind_count == 1) t->baseTexture.sampler = stage;
4312 if (prev)
4314 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4315 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4317 IWineD3DBaseTexture_Release(prev);
4319 if (!texture && stage < MAX_TEXTURES)
4321 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4322 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4325 if (bind_count && t->baseTexture.sampler == stage)
4327 unsigned int i;
4329 /* Search for other stages the texture is bound to. Shouldn't
4330 * happen if applications bind textures to a single stage only. */
4331 TRACE("Searching for other stages the texture is bound to.\n");
4332 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4334 if (This->updateStateBlock->textures[i] == prev)
4336 TRACE("Texture is also bound to stage %u.\n", i);
4337 t->baseTexture.sampler = i;
4338 break;
4344 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4346 return WINED3D_OK;
4349 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4352 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4354 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4355 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4358 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4359 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4360 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4363 *ppTexture=This->stateBlock->textures[Stage];
4364 if (*ppTexture)
4365 IWineD3DBaseTexture_AddRef(*ppTexture);
4367 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4369 return WINED3D_OK;
4372 /*****
4373 * Get Back Buffer
4374 *****/
4375 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4376 IWineD3DSurface **ppBackBuffer) {
4377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4378 IWineD3DSwapChain *swapChain;
4379 HRESULT hr;
4381 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4383 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4384 if (hr == WINED3D_OK) {
4385 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4386 IWineD3DSwapChain_Release(swapChain);
4387 } else {
4388 *ppBackBuffer = NULL;
4390 return hr;
4393 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4395 WARN("(%p) : stub, calling idirect3d for now\n", This);
4396 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4399 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4401 IWineD3DSwapChain *swapChain;
4402 HRESULT hr;
4404 if(iSwapChain > 0) {
4405 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4406 if (hr == WINED3D_OK) {
4407 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4408 IWineD3DSwapChain_Release(swapChain);
4409 } else {
4410 FIXME("(%p) Error getting display mode\n", This);
4412 } else {
4413 /* Don't read the real display mode,
4414 but return the stored mode instead. X11 can't change the color
4415 depth, and some apps are pretty angry if they SetDisplayMode from
4416 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4418 Also don't relay to the swapchain because with ddraw it's possible
4419 that there isn't a swapchain at all */
4420 pMode->Width = This->ddraw_width;
4421 pMode->Height = This->ddraw_height;
4422 pMode->Format = This->ddraw_format;
4423 pMode->RefreshRate = 0;
4424 hr = WINED3D_OK;
4427 return hr;
4430 /*****
4431 * Stateblock related functions
4432 *****/
4434 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4436 IWineD3DStateBlock *stateblock;
4437 HRESULT hr;
4439 TRACE("(%p)\n", This);
4441 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4443 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4444 if (FAILED(hr)) return hr;
4446 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4447 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4448 This->isRecordingState = TRUE;
4450 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4452 return WINED3D_OK;
4455 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4457 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4459 if (!This->isRecordingState) {
4460 WARN("(%p) not recording! returning error\n", This);
4461 *ppStateBlock = NULL;
4462 return WINED3DERR_INVALIDCALL;
4465 stateblock_init_contained_states(object);
4467 *ppStateBlock = (IWineD3DStateBlock*) object;
4468 This->isRecordingState = FALSE;
4469 This->updateStateBlock = This->stateBlock;
4470 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4471 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4472 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4473 return WINED3D_OK;
4476 /*****
4477 * Scene related functions
4478 *****/
4479 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4480 /* At the moment we have no need for any functionality at the beginning
4481 of a scene */
4482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4483 TRACE("(%p)\n", This);
4485 if(This->inScene) {
4486 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4487 return WINED3DERR_INVALIDCALL;
4489 This->inScene = TRUE;
4490 return WINED3D_OK;
4493 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4496 struct wined3d_context *context;
4498 TRACE("(%p)\n", This);
4500 if(!This->inScene) {
4501 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4502 return WINED3DERR_INVALIDCALL;
4505 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4506 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4507 wglFlush();
4508 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4509 * fails. */
4510 context_release(context);
4512 This->inScene = FALSE;
4513 return WINED3D_OK;
4516 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4517 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4518 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4520 IWineD3DSwapChain *swapChain = NULL;
4521 int i;
4522 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4524 TRACE("(%p) Presenting the frame\n", This);
4526 for(i = 0 ; i < swapchains ; i ++) {
4528 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4529 TRACE("presentinng chain %d, %p\n", i, swapChain);
4530 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4531 IWineD3DSwapChain_Release(swapChain);
4534 return WINED3D_OK;
4537 /* Not called from the VTable (internal subroutine) */
4538 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4539 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4540 float Z, DWORD Stencil) {
4541 GLbitfield glMask = 0;
4542 unsigned int i;
4543 WINED3DRECT curRect;
4544 RECT vp_rect;
4545 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4546 UINT drawable_width, drawable_height;
4547 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4548 IWineD3DSwapChainImpl *swapchain = NULL;
4549 struct wined3d_context *context;
4551 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4552 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4553 * for the cleared parts, and the untouched parts.
4555 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4556 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4557 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4558 * checking all this if the dest surface is in the drawable anyway.
4560 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4561 while(1) {
4562 if(vp->X != 0 || vp->Y != 0 ||
4563 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4564 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4565 break;
4567 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4568 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4569 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4570 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4571 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4572 break;
4574 if(Count > 0 && pRects && (
4575 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4576 pRects[0].x2 < target->currentDesc.Width ||
4577 pRects[0].y2 < target->currentDesc.Height)) {
4578 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4579 break;
4581 break;
4585 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4587 target->get_drawable_size(context, &drawable_width, &drawable_height);
4589 ENTER_GL();
4591 /* Only set the values up once, as they are not changing */
4592 if (Flags & WINED3DCLEAR_STENCIL) {
4593 glClearStencil(Stencil);
4594 checkGLcall("glClearStencil");
4595 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4596 glStencilMask(0xFFFFFFFF);
4599 if (Flags & WINED3DCLEAR_ZBUFFER) {
4600 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4601 glDepthMask(GL_TRUE);
4602 glClearDepth(Z);
4603 checkGLcall("glClearDepth");
4604 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4605 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4607 if (vp->X != 0 || vp->Y != 0 ||
4608 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4609 surface_load_ds_location(This->stencilBufferTarget, context, location);
4611 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4612 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4613 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4614 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4615 surface_load_ds_location(This->stencilBufferTarget, context, location);
4617 else if (Count > 0 && pRects && (
4618 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4619 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4620 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4621 surface_load_ds_location(This->stencilBufferTarget, context, location);
4625 if (Flags & WINED3DCLEAR_TARGET) {
4626 TRACE("Clearing screen with glClear to color %x\n", Color);
4627 glClearColor(D3DCOLOR_R(Color),
4628 D3DCOLOR_G(Color),
4629 D3DCOLOR_B(Color),
4630 D3DCOLOR_A(Color));
4631 checkGLcall("glClearColor");
4633 /* Clear ALL colors! */
4634 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4635 glMask = glMask | GL_COLOR_BUFFER_BIT;
4638 vp_rect.left = vp->X;
4639 vp_rect.top = vp->Y;
4640 vp_rect.right = vp->X + vp->Width;
4641 vp_rect.bottom = vp->Y + vp->Height;
4642 if (!(Count > 0 && pRects)) {
4643 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4644 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4646 if (context->render_offscreen)
4648 glScissor(vp_rect.left, vp_rect.top,
4649 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4650 } else {
4651 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4652 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4654 checkGLcall("glScissor");
4655 glClear(glMask);
4656 checkGLcall("glClear");
4657 } else {
4658 /* Now process each rect in turn */
4659 for (i = 0; i < Count; i++) {
4660 /* Note gl uses lower left, width/height */
4661 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4662 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4663 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4665 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4666 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4667 curRect.x1, (target->currentDesc.Height - curRect.y2),
4668 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4670 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4671 * The rectangle is not cleared, no error is returned, but further rectanlges are
4672 * still cleared if they are valid
4674 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4675 TRACE("Rectangle with negative dimensions, ignoring\n");
4676 continue;
4679 if (context->render_offscreen)
4681 glScissor(curRect.x1, curRect.y1,
4682 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4683 } else {
4684 glScissor(curRect.x1, drawable_height - curRect.y2,
4685 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4687 checkGLcall("glScissor");
4689 glClear(glMask);
4690 checkGLcall("glClear");
4694 /* Restore the old values (why..?) */
4695 if (Flags & WINED3DCLEAR_STENCIL) {
4696 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4698 if (Flags & WINED3DCLEAR_TARGET) {
4699 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4700 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4701 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4702 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4703 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4705 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4706 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4708 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4710 if (Flags & WINED3DCLEAR_ZBUFFER) {
4711 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4712 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4713 surface_modify_ds_location(This->stencilBufferTarget, location);
4716 LEAVE_GL();
4718 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
4719 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
4720 wglFlush();
4722 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
4725 context_release(context);
4727 return WINED3D_OK;
4730 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4731 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4733 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4735 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4736 Count, pRects, Flags, Color, Z, Stencil);
4738 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4739 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4740 /* TODO: What about depth stencil buffers without stencil bits? */
4741 return WINED3DERR_INVALIDCALL;
4744 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4747 /*****
4748 * Drawing functions
4749 *****/
4751 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4752 WINED3DPRIMITIVETYPE primitive_type)
4754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4756 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4758 This->updateStateBlock->changed.primitive_type = TRUE;
4759 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4762 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4763 WINED3DPRIMITIVETYPE *primitive_type)
4765 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4767 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4769 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4771 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4774 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4778 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4780 if(!This->stateBlock->vertexDecl) {
4781 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4782 return WINED3DERR_INVALIDCALL;
4785 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4786 if(This->stateBlock->streamIsUP) {
4787 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4788 This->stateBlock->streamIsUP = FALSE;
4791 if(This->stateBlock->loadBaseVertexIndex != 0) {
4792 This->stateBlock->loadBaseVertexIndex = 0;
4793 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4795 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4796 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4797 return WINED3D_OK;
4800 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4803 UINT idxStride = 2;
4804 IWineD3DBuffer *pIB;
4805 GLuint vbo;
4807 pIB = This->stateBlock->pIndexData;
4808 if (!pIB) {
4809 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4810 * without an index buffer set. (The first time at least...)
4811 * D3D8 simply dies, but I doubt it can do much harm to return
4812 * D3DERR_INVALIDCALL there as well. */
4813 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4814 return WINED3DERR_INVALIDCALL;
4817 if(!This->stateBlock->vertexDecl) {
4818 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4819 return WINED3DERR_INVALIDCALL;
4822 if(This->stateBlock->streamIsUP) {
4823 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4824 This->stateBlock->streamIsUP = FALSE;
4826 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4828 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4830 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4831 idxStride = 2;
4832 } else {
4833 idxStride = 4;
4836 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4837 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4838 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4841 drawPrimitive(iface, index_count, startIndex, idxStride,
4842 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4844 return WINED3D_OK;
4847 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4848 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4851 IWineD3DBuffer *vb;
4853 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4854 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4856 if(!This->stateBlock->vertexDecl) {
4857 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4858 return WINED3DERR_INVALIDCALL;
4861 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4862 vb = This->stateBlock->streamSource[0];
4863 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4864 if (vb) IWineD3DBuffer_Release(vb);
4865 This->stateBlock->streamOffset[0] = 0;
4866 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4867 This->stateBlock->streamIsUP = TRUE;
4868 This->stateBlock->loadBaseVertexIndex = 0;
4870 /* TODO: Only mark dirty if drawing from a different UP address */
4871 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4873 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4875 /* MSDN specifies stream zero settings must be set to NULL */
4876 This->stateBlock->streamStride[0] = 0;
4877 This->stateBlock->streamSource[0] = NULL;
4879 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4880 * the new stream sources or use UP drawing again
4882 return WINED3D_OK;
4885 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4886 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4887 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4889 int idxStride;
4890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4891 IWineD3DBuffer *vb;
4892 IWineD3DBuffer *ib;
4894 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4895 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4897 if(!This->stateBlock->vertexDecl) {
4898 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4899 return WINED3DERR_INVALIDCALL;
4902 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4903 idxStride = 2;
4904 } else {
4905 idxStride = 4;
4908 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4909 vb = This->stateBlock->streamSource[0];
4910 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4911 if (vb) IWineD3DBuffer_Release(vb);
4912 This->stateBlock->streamIsUP = TRUE;
4913 This->stateBlock->streamOffset[0] = 0;
4914 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4916 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4917 This->stateBlock->baseVertexIndex = 0;
4918 This->stateBlock->loadBaseVertexIndex = 0;
4919 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4920 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4921 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4923 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4925 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4926 This->stateBlock->streamSource[0] = NULL;
4927 This->stateBlock->streamStride[0] = 0;
4928 ib = This->stateBlock->pIndexData;
4929 if(ib) {
4930 IWineD3DBuffer_Release(ib);
4931 This->stateBlock->pIndexData = NULL;
4933 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4934 * SetStreamSource to specify a vertex buffer
4937 return WINED3D_OK;
4940 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4941 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4945 /* Mark the state dirty until we have nicer tracking
4946 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4947 * that value.
4949 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4950 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4951 This->stateBlock->baseVertexIndex = 0;
4952 This->up_strided = DrawPrimStrideData;
4953 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4954 This->up_strided = NULL;
4955 return WINED3D_OK;
4958 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4959 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4960 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4963 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4965 /* Mark the state dirty until we have nicer tracking
4966 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4967 * that value.
4969 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4970 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4971 This->stateBlock->streamIsUP = TRUE;
4972 This->stateBlock->baseVertexIndex = 0;
4973 This->up_strided = DrawPrimStrideData;
4974 drawPrimitive(iface, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData);
4975 This->up_strided = NULL;
4976 return WINED3D_OK;
4979 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
4980 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
4981 * not callable by the app directly no parameter validation checks are needed here.
4983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4984 WINED3DLOCKED_BOX src;
4985 WINED3DLOCKED_BOX dst;
4986 HRESULT hr;
4987 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
4989 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4990 * dirtification to improve loading performance.
4992 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4993 if(FAILED(hr)) return hr;
4994 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4995 if(FAILED(hr)) {
4996 IWineD3DVolume_UnlockBox(pSourceVolume);
4997 return hr;
5000 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5002 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5003 if(FAILED(hr)) {
5004 IWineD3DVolume_UnlockBox(pSourceVolume);
5005 } else {
5006 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5008 return hr;
5011 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
5012 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
5014 unsigned int level_count, i;
5015 WINED3DRESOURCETYPE type;
5016 HRESULT hr;
5018 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
5020 /* Verify that the source and destination textures are non-NULL. */
5021 if (!src_texture || !dst_texture)
5023 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5024 return WINED3DERR_INVALIDCALL;
5027 if (src_texture == dst_texture)
5029 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5030 return WINED3DERR_INVALIDCALL;
5033 /* Verify that the source and destination textures are the same type. */
5034 type = IWineD3DBaseTexture_GetType(src_texture);
5035 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
5037 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5038 return WINED3DERR_INVALIDCALL;
5041 /* Check that both textures have the identical numbers of levels. */
5042 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
5043 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
5045 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5046 return WINED3DERR_INVALIDCALL;
5049 /* Make sure that the destination texture is loaded. */
5050 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
5052 /* Update every surface level of the texture. */
5053 switch (type)
5055 case WINED3DRTYPE_TEXTURE:
5057 IWineD3DSurface *src_surface;
5058 IWineD3DSurface *dst_surface;
5060 for (i = 0; i < level_count; ++i)
5062 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
5063 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
5064 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5065 IWineD3DSurface_Release(dst_surface);
5066 IWineD3DSurface_Release(src_surface);
5067 if (FAILED(hr))
5069 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5070 return hr;
5073 break;
5076 case WINED3DRTYPE_CUBETEXTURE:
5078 IWineD3DSurface *src_surface;
5079 IWineD3DSurface *dst_surface;
5080 WINED3DCUBEMAP_FACES face;
5082 for (i = 0; i < level_count; ++i)
5084 /* Update each cube face. */
5085 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
5087 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
5088 face, i, &src_surface);
5089 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5090 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
5091 face, i, &dst_surface);
5092 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5093 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5094 IWineD3DSurface_Release(dst_surface);
5095 IWineD3DSurface_Release(src_surface);
5096 if (FAILED(hr))
5098 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5099 return hr;
5103 break;
5106 case WINED3DRTYPE_VOLUMETEXTURE:
5108 IWineD3DVolume *src_volume;
5109 IWineD3DVolume *dst_volume;
5111 for (i = 0; i < level_count; ++i)
5113 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5114 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5115 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5116 IWineD3DVolume_Release(dst_volume);
5117 IWineD3DVolume_Release(src_volume);
5118 if (FAILED(hr))
5120 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5121 return hr;
5124 break;
5127 default:
5128 FIXME("Unsupported texture type %#x.\n", type);
5129 return WINED3DERR_INVALIDCALL;
5132 return WINED3D_OK;
5135 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5136 IWineD3DSwapChain *swapChain;
5137 HRESULT hr;
5138 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5139 if(hr == WINED3D_OK) {
5140 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5141 IWineD3DSwapChain_Release(swapChain);
5143 return hr;
5146 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5148 IWineD3DBaseTextureImpl *texture;
5149 DWORD i;
5151 TRACE("(%p) : %p\n", This, pNumPasses);
5153 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5154 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5155 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5156 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5158 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5159 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5160 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5163 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5164 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5166 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5167 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5168 return E_FAIL;
5170 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5171 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5172 return E_FAIL;
5174 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5175 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5176 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5177 return E_FAIL;
5181 /* return a sensible default */
5182 *pNumPasses = 1;
5184 TRACE("returning D3D_OK\n");
5185 return WINED3D_OK;
5188 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5190 int i;
5192 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5194 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5195 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
5196 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
5198 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5203 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5205 int j;
5206 UINT NewSize;
5207 PALETTEENTRY **palettes;
5209 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5211 if (PaletteNumber >= MAX_PALETTES) {
5212 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5213 return WINED3DERR_INVALIDCALL;
5216 if (PaletteNumber >= This->NumberOfPalettes) {
5217 NewSize = This->NumberOfPalettes;
5218 do {
5219 NewSize *= 2;
5220 } while(PaletteNumber >= NewSize);
5221 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5222 if (!palettes) {
5223 ERR("Out of memory!\n");
5224 return E_OUTOFMEMORY;
5226 This->palettes = palettes;
5227 This->NumberOfPalettes = NewSize;
5230 if (!This->palettes[PaletteNumber]) {
5231 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5232 if (!This->palettes[PaletteNumber]) {
5233 ERR("Out of memory!\n");
5234 return E_OUTOFMEMORY;
5238 for (j = 0; j < 256; ++j) {
5239 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5240 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5241 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5242 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5244 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5245 TRACE("(%p) : returning\n", This);
5246 return WINED3D_OK;
5249 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5251 int j;
5252 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5253 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5254 /* What happens in such situation isn't documented; Native seems to silently abort
5255 on such conditions. Return Invalid Call. */
5256 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5257 return WINED3DERR_INVALIDCALL;
5259 for (j = 0; j < 256; ++j) {
5260 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5261 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5262 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5263 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5265 TRACE("(%p) : returning\n", This);
5266 return WINED3D_OK;
5269 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5271 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5272 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5273 (tested with reference rasterizer). Return Invalid Call. */
5274 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5275 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5276 return WINED3DERR_INVALIDCALL;
5278 /*TODO: stateblocks */
5279 if (This->currentPalette != PaletteNumber) {
5280 This->currentPalette = PaletteNumber;
5281 dirtify_p8_texture_samplers(This);
5283 TRACE("(%p) : returning\n", This);
5284 return WINED3D_OK;
5287 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5289 if (PaletteNumber == NULL) {
5290 WARN("(%p) : returning Invalid Call\n", This);
5291 return WINED3DERR_INVALIDCALL;
5293 /*TODO: stateblocks */
5294 *PaletteNumber = This->currentPalette;
5295 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5296 return WINED3D_OK;
5299 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5301 static BOOL warned;
5302 if (!warned)
5304 FIXME("(%p) : stub\n", This);
5305 warned = TRUE;
5308 This->softwareVertexProcessing = bSoftware;
5309 return WINED3D_OK;
5313 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5315 static BOOL warned;
5316 if (!warned)
5318 FIXME("(%p) : stub\n", This);
5319 warned = TRUE;
5321 return This->softwareVertexProcessing;
5325 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5327 IWineD3DSwapChain *swapChain;
5328 HRESULT hr;
5330 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5332 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5333 if(hr == WINED3D_OK){
5334 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5335 IWineD3DSwapChain_Release(swapChain);
5336 }else{
5337 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5339 return hr;
5343 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5345 static BOOL warned;
5346 if(nSegments != 0.0f) {
5347 if (!warned)
5349 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5350 warned = TRUE;
5353 return WINED3D_OK;
5356 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5358 static BOOL warned;
5359 if (!warned)
5361 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5362 warned = TRUE;
5364 return 0.0f;
5367 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5368 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5369 /** TODO: remove casts to IWineD3DSurfaceImpl
5370 * NOTE: move code to surface to accomplish this
5371 ****************************************/
5372 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5373 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5374 int srcWidth, srcHeight;
5375 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5376 WINED3DFORMAT destFormat, srcFormat;
5377 UINT destSize;
5378 int srcLeft, destLeft, destTop;
5379 WINED3DPOOL srcPool, destPool;
5380 int offset = 0;
5381 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5382 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5383 GLenum dummy;
5384 DWORD sampler;
5385 int bpp;
5386 CONVERT_TYPES convert = NO_CONVERSION;
5387 struct wined3d_context *context;
5389 WINED3DSURFACE_DESC winedesc;
5391 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5393 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5394 srcSurfaceWidth = winedesc.width;
5395 srcSurfaceHeight = winedesc.height;
5396 srcPool = winedesc.pool;
5397 srcFormat = winedesc.format;
5399 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5400 destSurfaceWidth = winedesc.width;
5401 destSurfaceHeight = winedesc.height;
5402 destPool = winedesc.pool;
5403 destFormat = winedesc.format;
5404 destSize = winedesc.size;
5406 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5407 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5408 return WINED3DERR_INVALIDCALL;
5411 /* This call loads the opengl surface directly, instead of copying the surface to the
5412 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5413 * copy in sysmem and use regular surface loading.
5415 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5416 if(convert != NO_CONVERSION) {
5417 return IWineD3DSurface_BltFast(pDestinationSurface,
5418 pDestPoint ? pDestPoint->x : 0,
5419 pDestPoint ? pDestPoint->y : 0,
5420 pSourceSurface, pSourceRect, 0);
5423 if (destFormat == WINED3DFMT_UNKNOWN) {
5424 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5425 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5427 /* Get the update surface description */
5428 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5431 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5433 ENTER_GL();
5434 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5435 checkGLcall("glActiveTextureARB");
5436 LEAVE_GL();
5438 /* Make sure the surface is loaded and up to date */
5439 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5440 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5442 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5443 dst_format_desc = dst_impl->resource.format_desc;
5445 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5446 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5447 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5448 srcLeft = pSourceRect ? pSourceRect->left : 0;
5449 destLeft = pDestPoint ? pDestPoint->x : 0;
5450 destTop = pDestPoint ? pDestPoint->y : 0;
5453 /* This function doesn't support compressed textures
5454 the pitch is just bytesPerPixel * width */
5455 if(srcWidth != srcSurfaceWidth || srcLeft ){
5456 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5457 offset += srcLeft * src_format_desc->byte_count;
5458 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5460 /* TODO DXT formats */
5462 if(pSourceRect != NULL && pSourceRect->top != 0){
5463 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5465 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5466 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5467 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5469 /* Sanity check */
5470 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5472 /* need to lock the surface to get the data */
5473 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5476 ENTER_GL();
5478 /* TODO: Cube and volume support */
5479 if(rowoffset != 0){
5480 /* not a whole row so we have to do it a line at a time */
5481 int j;
5483 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5484 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5486 for (j = destTop; j < (srcHeight + destTop); ++j)
5488 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5489 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5490 data += rowoffset;
5493 } else { /* Full width, so just write out the whole texture */
5494 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5496 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5498 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5500 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5501 FIXME("Updating part of a compressed texture is not supported.\n");
5503 if (destFormat != srcFormat)
5505 FIXME("Updating mixed format compressed textures is not supported.\n");
5507 else
5509 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5510 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5513 else
5515 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5516 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5519 checkGLcall("glTexSubImage2D");
5521 LEAVE_GL();
5522 context_release(context);
5524 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5525 sampler = This->rev_tex_unit_map[0];
5526 if (sampler != WINED3D_UNMAPPED_STAGE)
5528 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5531 return WINED3D_OK;
5534 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5536 struct WineD3DRectPatch *patch;
5537 GLenum old_primitive_type;
5538 unsigned int i;
5539 struct list *e;
5540 BOOL found;
5541 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5543 if(!(Handle || pRectPatchInfo)) {
5544 /* TODO: Write a test for the return value, thus the FIXME */
5545 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5546 return WINED3DERR_INVALIDCALL;
5549 if(Handle) {
5550 i = PATCHMAP_HASHFUNC(Handle);
5551 found = FALSE;
5552 LIST_FOR_EACH(e, &This->patches[i]) {
5553 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5554 if(patch->Handle == Handle) {
5555 found = TRUE;
5556 break;
5560 if(!found) {
5561 TRACE("Patch does not exist. Creating a new one\n");
5562 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5563 patch->Handle = Handle;
5564 list_add_head(&This->patches[i], &patch->entry);
5565 } else {
5566 TRACE("Found existing patch %p\n", patch);
5568 } else {
5569 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5570 * attributes we have to tesselate, read back, and draw. This needs a patch
5571 * management structure instance. Create one.
5573 * A possible improvement is to check if a vertex shader is used, and if not directly
5574 * draw the patch.
5576 FIXME("Drawing an uncached patch. This is slow\n");
5577 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5580 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5581 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5582 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5583 HRESULT hr;
5584 TRACE("Tesselation density or patch info changed, retesselating\n");
5586 if(pRectPatchInfo) {
5587 patch->RectPatchInfo = *pRectPatchInfo;
5589 patch->numSegs[0] = pNumSegs[0];
5590 patch->numSegs[1] = pNumSegs[1];
5591 patch->numSegs[2] = pNumSegs[2];
5592 patch->numSegs[3] = pNumSegs[3];
5594 hr = tesselate_rectpatch(This, patch);
5595 if(FAILED(hr)) {
5596 WARN("Patch tesselation failed\n");
5598 /* Do not release the handle to store the params of the patch */
5599 if(!Handle) {
5600 HeapFree(GetProcessHeap(), 0, patch);
5602 return hr;
5606 This->currentPatch = patch;
5607 old_primitive_type = This->stateBlock->gl_primitive_type;
5608 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5609 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5610 This->stateBlock->gl_primitive_type = old_primitive_type;
5611 This->currentPatch = NULL;
5613 /* Destroy uncached patches */
5614 if(!Handle) {
5615 HeapFree(GetProcessHeap(), 0, patch->mem);
5616 HeapFree(GetProcessHeap(), 0, patch);
5618 return WINED3D_OK;
5621 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5623 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5624 FIXME("(%p) : Stub\n", This);
5625 return WINED3D_OK;
5628 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5630 int i;
5631 struct WineD3DRectPatch *patch;
5632 struct list *e;
5633 TRACE("(%p) Handle(%d)\n", This, Handle);
5635 i = PATCHMAP_HASHFUNC(Handle);
5636 LIST_FOR_EACH(e, &This->patches[i]) {
5637 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5638 if(patch->Handle == Handle) {
5639 TRACE("Deleting patch %p\n", patch);
5640 list_remove(&patch->entry);
5641 HeapFree(GetProcessHeap(), 0, patch->mem);
5642 HeapFree(GetProcessHeap(), 0, patch);
5643 return WINED3D_OK;
5647 /* TODO: Write a test for the return value */
5648 FIXME("Attempt to destroy nonexistent patch\n");
5649 return WINED3DERR_INVALIDCALL;
5652 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5653 HRESULT hr;
5654 IWineD3DSwapChain *swapchain;
5656 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5657 if (SUCCEEDED(hr)) {
5658 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5659 return swapchain;
5662 return NULL;
5665 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5666 const WINED3DRECT *rect, const float color[4])
5668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5669 struct wined3d_context *context;
5670 IWineD3DSwapChain *swapchain;
5672 swapchain = get_swapchain(surface);
5673 if (swapchain) {
5674 GLenum buffer;
5676 TRACE("Surface %p is onscreen\n", surface);
5678 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5679 ENTER_GL();
5680 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5681 buffer = surface_get_gl_buffer(surface, swapchain);
5682 glDrawBuffer(buffer);
5683 checkGLcall("glDrawBuffer()");
5684 } else {
5685 TRACE("Surface %p is offscreen\n", surface);
5687 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5688 ENTER_GL();
5689 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5690 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5691 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5694 if (rect) {
5695 glEnable(GL_SCISSOR_TEST);
5696 if(!swapchain) {
5697 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5698 } else {
5699 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5700 rect->x2 - rect->x1, rect->y2 - rect->y1);
5702 checkGLcall("glScissor");
5703 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5704 } else {
5705 glDisable(GL_SCISSOR_TEST);
5707 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5709 glDisable(GL_BLEND);
5710 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5712 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5713 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5715 glClearColor(color[0], color[1], color[2], color[3]);
5716 glClear(GL_COLOR_BUFFER_BIT);
5717 checkGLcall("glClear");
5719 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5720 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5721 glDrawBuffer(GL_BACK);
5722 checkGLcall("glDrawBuffer()");
5725 LEAVE_GL();
5726 context_release(context);
5729 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5730 unsigned int r, g, b, a;
5731 DWORD ret;
5733 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5734 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5735 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5736 return color;
5738 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5740 a = (color & 0xff000000) >> 24;
5741 r = (color & 0x00ff0000) >> 16;
5742 g = (color & 0x0000ff00) >> 8;
5743 b = (color & 0x000000ff) >> 0;
5745 switch(destfmt)
5747 case WINED3DFMT_B5G6R5_UNORM:
5748 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5749 r = (r * 32) / 256;
5750 g = (g * 64) / 256;
5751 b = (b * 32) / 256;
5752 ret = r << 11;
5753 ret |= g << 5;
5754 ret |= b;
5755 TRACE("Returning %08x\n", ret);
5756 return ret;
5758 case WINED3DFMT_B5G5R5X1_UNORM:
5759 case WINED3DFMT_B5G5R5A1_UNORM:
5760 a = (a * 2) / 256;
5761 r = (r * 32) / 256;
5762 g = (g * 32) / 256;
5763 b = (b * 32) / 256;
5764 ret = a << 15;
5765 ret |= r << 10;
5766 ret |= g << 5;
5767 ret |= b << 0;
5768 TRACE("Returning %08x\n", ret);
5769 return ret;
5771 case WINED3DFMT_A8_UNORM:
5772 TRACE("Returning %08x\n", a);
5773 return a;
5775 case WINED3DFMT_B4G4R4X4_UNORM:
5776 case WINED3DFMT_B4G4R4A4_UNORM:
5777 a = (a * 16) / 256;
5778 r = (r * 16) / 256;
5779 g = (g * 16) / 256;
5780 b = (b * 16) / 256;
5781 ret = a << 12;
5782 ret |= r << 8;
5783 ret |= g << 4;
5784 ret |= b << 0;
5785 TRACE("Returning %08x\n", ret);
5786 return ret;
5788 case WINED3DFMT_B2G3R3_UNORM:
5789 r = (r * 8) / 256;
5790 g = (g * 8) / 256;
5791 b = (b * 4) / 256;
5792 ret = r << 5;
5793 ret |= g << 2;
5794 ret |= b << 0;
5795 TRACE("Returning %08x\n", ret);
5796 return ret;
5798 case WINED3DFMT_R8G8B8X8_UNORM:
5799 case WINED3DFMT_R8G8B8A8_UNORM:
5800 ret = a << 24;
5801 ret |= b << 16;
5802 ret |= g << 8;
5803 ret |= r << 0;
5804 TRACE("Returning %08x\n", ret);
5805 return ret;
5807 case WINED3DFMT_B10G10R10A2_UNORM:
5808 a = (a * 4) / 256;
5809 r = (r * 1024) / 256;
5810 g = (g * 1024) / 256;
5811 b = (b * 1024) / 256;
5812 ret = a << 30;
5813 ret |= r << 20;
5814 ret |= g << 10;
5815 ret |= b << 0;
5816 TRACE("Returning %08x\n", ret);
5817 return ret;
5819 case WINED3DFMT_R10G10B10A2_UNORM:
5820 a = (a * 4) / 256;
5821 r = (r * 1024) / 256;
5822 g = (g * 1024) / 256;
5823 b = (b * 1024) / 256;
5824 ret = a << 30;
5825 ret |= b << 20;
5826 ret |= g << 10;
5827 ret |= r << 0;
5828 TRACE("Returning %08x\n", ret);
5829 return ret;
5831 default:
5832 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5833 return 0;
5837 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5839 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5840 WINEDDBLTFX BltFx;
5841 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5843 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5844 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5845 return WINED3DERR_INVALIDCALL;
5848 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5849 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5850 color_fill_fbo(iface, pSurface, pRect, c);
5851 return WINED3D_OK;
5852 } else {
5853 /* Just forward this to the DirectDraw blitting engine */
5854 memset(&BltFx, 0, sizeof(BltFx));
5855 BltFx.dwSize = sizeof(BltFx);
5856 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5857 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5858 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5862 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5863 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5865 IWineD3DResource *resource;
5866 IWineD3DSurface *surface;
5867 HRESULT hr;
5869 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5870 if (FAILED(hr))
5872 ERR("Failed to get resource, hr %#x\n", hr);
5873 return;
5876 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5878 FIXME("Only supported on surface resources\n");
5879 IWineD3DResource_Release(resource);
5880 return;
5883 surface = (IWineD3DSurface *)resource;
5885 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5887 color_fill_fbo(iface, surface, NULL, color);
5889 else
5891 WINEDDBLTFX BltFx;
5892 WINED3DCOLOR c;
5894 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5896 c = ((DWORD)(color[2] * 255.0f));
5897 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5898 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5899 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5901 /* Just forward this to the DirectDraw blitting engine */
5902 memset(&BltFx, 0, sizeof(BltFx));
5903 BltFx.dwSize = sizeof(BltFx);
5904 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5905 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5906 if (FAILED(hr))
5908 ERR("Blt failed, hr %#x\n", hr);
5912 IWineD3DResource_Release(resource);
5915 /* rendertarget and depth stencil functions */
5916 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5919 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5921 ERR("(%p) : Only %d render targets are supported.\n",
5922 This, This->adapter->gl_info.limits.buffers);
5923 return WINED3DERR_INVALIDCALL;
5926 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5927 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5928 /* Note inc ref on returned surface */
5929 if(*ppRenderTarget != NULL)
5930 IWineD3DSurface_AddRef(*ppRenderTarget);
5931 return WINED3D_OK;
5934 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5936 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5937 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5938 IWineD3DSwapChainImpl *Swapchain;
5939 HRESULT hr;
5941 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5943 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5944 if(hr != WINED3D_OK) {
5945 ERR("Can't get the swapchain\n");
5946 return hr;
5949 /* Make sure to release the swapchain */
5950 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5952 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5953 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5954 return WINED3DERR_INVALIDCALL;
5956 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5957 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5958 return WINED3DERR_INVALIDCALL;
5961 if(Swapchain->frontBuffer != Front) {
5962 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5964 if(Swapchain->frontBuffer)
5966 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5967 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5969 Swapchain->frontBuffer = Front;
5971 if(Swapchain->frontBuffer) {
5972 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5973 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5977 if(Back && !Swapchain->backBuffer) {
5978 /* We need memory for the back buffer array - only one back buffer this way */
5979 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5980 if(!Swapchain->backBuffer) {
5981 ERR("Out of memory\n");
5982 return E_OUTOFMEMORY;
5986 if(Swapchain->backBuffer[0] != Back) {
5987 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5989 /* What to do about the context here in the case of multithreading? Not sure.
5990 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5992 WARN("No active context?\n");
5994 ENTER_GL();
5995 if(!Swapchain->backBuffer[0]) {
5996 /* GL was told to draw to the front buffer at creation,
5997 * undo that
5999 glDrawBuffer(GL_BACK);
6000 checkGLcall("glDrawBuffer(GL_BACK)");
6001 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6002 Swapchain->presentParms.BackBufferCount = 1;
6003 } else if (!Back) {
6004 /* That makes problems - disable for now */
6005 /* glDrawBuffer(GL_FRONT); */
6006 checkGLcall("glDrawBuffer(GL_FRONT)");
6007 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6008 Swapchain->presentParms.BackBufferCount = 0;
6010 LEAVE_GL();
6012 if(Swapchain->backBuffer[0])
6014 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6015 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6017 Swapchain->backBuffer[0] = Back;
6019 if(Swapchain->backBuffer[0]) {
6020 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6021 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6022 } else {
6023 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6024 Swapchain->backBuffer = NULL;
6029 return WINED3D_OK;
6032 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6034 *ppZStencilSurface = This->stencilBufferTarget;
6035 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6037 if(*ppZStencilSurface != NULL) {
6038 /* Note inc ref on returned surface */
6039 IWineD3DSurface_AddRef(*ppZStencilSurface);
6040 return WINED3D_OK;
6041 } else {
6042 return WINED3DERR_NOTFOUND;
6046 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6047 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6050 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6051 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6052 const struct wined3d_gl_info *gl_info;
6053 struct wined3d_context *context;
6054 GLenum gl_filter;
6055 POINT offset = {0, 0};
6057 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6058 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6059 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6060 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6062 switch (filter) {
6063 case WINED3DTEXF_LINEAR:
6064 gl_filter = GL_LINEAR;
6065 break;
6067 default:
6068 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6069 case WINED3DTEXF_NONE:
6070 case WINED3DTEXF_POINT:
6071 gl_filter = GL_NEAREST;
6072 break;
6075 /* Attach src surface to src fbo */
6076 src_swapchain = get_swapchain(src_surface);
6077 dst_swapchain = get_swapchain(dst_surface);
6079 if (src_swapchain) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
6080 else if (dst_swapchain) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6081 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6083 gl_info = context->gl_info;
6085 if (src_swapchain) {
6086 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6088 TRACE("Source surface %p is onscreen\n", src_surface);
6089 /* Make sure the drawable is up to date. In the offscreen case
6090 * attach_surface_fbo() implicitly takes care of this. */
6091 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6093 if(buffer == GL_FRONT) {
6094 RECT windowsize;
6095 UINT h;
6096 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6097 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6098 h = windowsize.bottom - windowsize.top;
6099 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6100 src_rect->y1 = offset.y + h - src_rect->y1;
6101 src_rect->y2 = offset.y + h - src_rect->y2;
6102 } else {
6103 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6104 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6107 ENTER_GL();
6108 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
6109 glReadBuffer(buffer);
6110 checkGLcall("glReadBuffer()");
6111 } else {
6112 TRACE("Source surface %p is offscreen\n", src_surface);
6113 ENTER_GL();
6114 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
6115 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
6116 glReadBuffer(GL_COLOR_ATTACHMENT0);
6117 checkGLcall("glReadBuffer()");
6118 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
6120 LEAVE_GL();
6122 /* Attach dst surface to dst fbo */
6123 if (dst_swapchain) {
6124 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6126 TRACE("Destination surface %p is onscreen\n", dst_surface);
6127 /* Make sure the drawable is up to date. In the offscreen case
6128 * attach_surface_fbo() implicitly takes care of this. */
6129 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6131 if(buffer == GL_FRONT) {
6132 RECT windowsize;
6133 UINT h;
6134 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6135 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6136 h = windowsize.bottom - windowsize.top;
6137 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6138 dst_rect->y1 = offset.y + h - dst_rect->y1;
6139 dst_rect->y2 = offset.y + h - dst_rect->y2;
6140 } else {
6141 /* Screen coords = window coords, surface height = window height */
6142 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6143 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6146 ENTER_GL();
6147 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
6148 glDrawBuffer(buffer);
6149 checkGLcall("glDrawBuffer()");
6150 } else {
6151 TRACE("Destination surface %p is offscreen\n", dst_surface);
6153 ENTER_GL();
6154 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
6155 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
6156 glDrawBuffer(GL_COLOR_ATTACHMENT0);
6157 checkGLcall("glDrawBuffer()");
6158 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
6160 glDisable(GL_SCISSOR_TEST);
6161 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6163 if (flip) {
6164 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6165 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
6166 checkGLcall("glBlitFramebuffer()");
6167 } else {
6168 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6169 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
6170 checkGLcall("glBlitFramebuffer()");
6173 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6175 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6176 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6177 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6178 glDrawBuffer(GL_BACK);
6179 checkGLcall("glDrawBuffer()");
6181 LEAVE_GL();
6183 context_release(context);
6186 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
6187 BOOL set_viewport) {
6188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6190 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6192 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
6194 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6195 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
6196 return WINED3DERR_INVALIDCALL;
6199 /* MSDN says that null disables the render target
6200 but a device must always be associated with a render target
6201 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6203 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6204 FIXME("Trying to set render target 0 to NULL\n");
6205 return WINED3DERR_INVALIDCALL;
6207 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6208 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);
6209 return WINED3DERR_INVALIDCALL;
6212 /* If we are trying to set what we already have, don't bother */
6213 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6214 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6215 return WINED3D_OK;
6217 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6218 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6219 This->render_targets[RenderTargetIndex] = pRenderTarget;
6221 /* Render target 0 is special */
6222 if(RenderTargetIndex == 0 && set_viewport) {
6223 /* Finally, reset the viewport and scissor rect as the MSDN states.
6224 * Tests show that stateblock recording is ignored, the change goes
6225 * directly into the primary stateblock.
6227 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6228 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6229 This->stateBlock->viewport.X = 0;
6230 This->stateBlock->viewport.Y = 0;
6231 This->stateBlock->viewport.MaxZ = 1.0f;
6232 This->stateBlock->viewport.MinZ = 0.0f;
6233 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6235 This->stateBlock->scissorRect.top = 0;
6236 This->stateBlock->scissorRect.left = 0;
6237 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
6238 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
6239 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6241 return WINED3D_OK;
6244 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6246 HRESULT hr = WINED3D_OK;
6247 IWineD3DSurface *tmp;
6249 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6251 if (pNewZStencil == This->stencilBufferTarget) {
6252 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6253 } else {
6254 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6255 * depending on the renter target implementation being used.
6256 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6257 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6258 * stencil buffer and incur an extra memory overhead
6259 ******************************************************/
6261 if (This->stencilBufferTarget) {
6262 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6263 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6264 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6265 } else {
6266 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6267 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
6268 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6269 context_release(context);
6273 tmp = This->stencilBufferTarget;
6274 This->stencilBufferTarget = pNewZStencil;
6275 /* should we be calling the parent or the wined3d surface? */
6276 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6277 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6278 hr = WINED3D_OK;
6280 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6281 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6282 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6283 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6284 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6288 return hr;
6291 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6292 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6294 /* TODO: the use of Impl is deprecated. */
6295 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6296 WINED3DLOCKED_RECT lockedRect;
6298 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6300 /* some basic validation checks */
6301 if(This->cursorTexture) {
6302 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6303 ENTER_GL();
6304 glDeleteTextures(1, &This->cursorTexture);
6305 LEAVE_GL();
6306 context_release(context);
6307 This->cursorTexture = 0;
6310 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6311 This->haveHardwareCursor = TRUE;
6312 else
6313 This->haveHardwareCursor = FALSE;
6315 if(pCursorBitmap) {
6316 WINED3DLOCKED_RECT rect;
6318 /* MSDN: Cursor must be A8R8G8B8 */
6319 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6321 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6322 return WINED3DERR_INVALIDCALL;
6325 /* MSDN: Cursor must be smaller than the display mode */
6326 if(pSur->currentDesc.Width > This->ddraw_width ||
6327 pSur->currentDesc.Height > This->ddraw_height) {
6328 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);
6329 return WINED3DERR_INVALIDCALL;
6332 if (!This->haveHardwareCursor) {
6333 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6335 /* Do not store the surface's pointer because the application may
6336 * release it after setting the cursor image. Windows doesn't
6337 * addref the set surface, so we can't do this either without
6338 * creating circular refcount dependencies. Copy out the gl texture
6339 * instead.
6341 This->cursorWidth = pSur->currentDesc.Width;
6342 This->cursorHeight = pSur->currentDesc.Height;
6343 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6345 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6346 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6347 struct wined3d_context *context;
6348 char *mem, *bits = rect.pBits;
6349 GLint intfmt = glDesc->glInternal;
6350 GLint format = glDesc->glFormat;
6351 GLint type = glDesc->glType;
6352 INT height = This->cursorHeight;
6353 INT width = This->cursorWidth;
6354 INT bpp = glDesc->byte_count;
6355 DWORD sampler;
6356 INT i;
6358 /* Reformat the texture memory (pitch and width can be
6359 * different) */
6360 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6361 for(i = 0; i < height; i++)
6362 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6363 IWineD3DSurface_UnlockRect(pCursorBitmap);
6365 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6367 ENTER_GL();
6369 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6371 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6372 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6375 /* Make sure that a proper texture unit is selected */
6376 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6377 checkGLcall("glActiveTextureARB");
6378 sampler = This->rev_tex_unit_map[0];
6379 if (sampler != WINED3D_UNMAPPED_STAGE)
6381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6383 /* Create a new cursor texture */
6384 glGenTextures(1, &This->cursorTexture);
6385 checkGLcall("glGenTextures");
6386 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6387 checkGLcall("glBindTexture");
6388 /* Copy the bitmap memory into the cursor texture */
6389 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6390 HeapFree(GetProcessHeap(), 0, mem);
6391 checkGLcall("glTexImage2D");
6393 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6395 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6396 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6399 LEAVE_GL();
6401 context_release(context);
6403 else
6405 FIXME("A cursor texture was not returned.\n");
6406 This->cursorTexture = 0;
6409 else
6411 /* Draw a hardware cursor */
6412 ICONINFO cursorInfo;
6413 HCURSOR cursor;
6414 /* Create and clear maskBits because it is not needed for
6415 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6416 * chunks. */
6417 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6418 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6419 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6420 WINED3DLOCK_NO_DIRTY_UPDATE |
6421 WINED3DLOCK_READONLY
6423 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6424 pSur->currentDesc.Height);
6426 cursorInfo.fIcon = FALSE;
6427 cursorInfo.xHotspot = XHotSpot;
6428 cursorInfo.yHotspot = YHotSpot;
6429 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6430 1, 1, maskBits);
6431 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6432 1, 32, lockedRect.pBits);
6433 IWineD3DSurface_UnlockRect(pCursorBitmap);
6434 /* Create our cursor and clean up. */
6435 cursor = CreateIconIndirect(&cursorInfo);
6436 SetCursor(cursor);
6437 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6438 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6439 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6440 This->hardwareCursor = cursor;
6441 HeapFree(GetProcessHeap(), 0, maskBits);
6445 This->xHotSpot = XHotSpot;
6446 This->yHotSpot = YHotSpot;
6447 return WINED3D_OK;
6450 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6452 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6454 This->xScreenSpace = XScreenSpace;
6455 This->yScreenSpace = YScreenSpace;
6457 return;
6461 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6463 BOOL oldVisible = This->bCursorVisible;
6464 POINT pt;
6466 TRACE("(%p) : visible(%d)\n", This, bShow);
6469 * When ShowCursor is first called it should make the cursor appear at the OS's last
6470 * known cursor position. Because of this, some applications just repetitively call
6471 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6473 GetCursorPos(&pt);
6474 This->xScreenSpace = pt.x;
6475 This->yScreenSpace = pt.y;
6477 if (This->haveHardwareCursor) {
6478 This->bCursorVisible = bShow;
6479 if (bShow)
6480 SetCursor(This->hardwareCursor);
6481 else
6482 SetCursor(NULL);
6484 else
6486 if (This->cursorTexture)
6487 This->bCursorVisible = bShow;
6490 return oldVisible;
6493 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6494 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6495 IWineD3DResourceImpl *resource;
6496 TRACE("(%p) : state (%u)\n", This, This->state);
6498 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6499 switch (This->state) {
6500 case WINED3D_OK:
6501 return WINED3D_OK;
6502 case WINED3DERR_DEVICELOST:
6504 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6505 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6506 return WINED3DERR_DEVICENOTRESET;
6508 return WINED3DERR_DEVICELOST;
6510 case WINED3DERR_DRIVERINTERNALERROR:
6511 return WINED3DERR_DRIVERINTERNALERROR;
6514 /* Unknown state */
6515 return WINED3DERR_DRIVERINTERNALERROR;
6518 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6519 TRACE("checking resource %p for eviction\n", resource);
6520 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6521 TRACE("Evicting %p\n", resource);
6522 IWineD3DResource_UnLoad(resource);
6524 IWineD3DResource_Release(resource);
6525 return S_OK;
6528 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6530 TRACE("(%p)\n", This);
6532 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6533 return WINED3D_OK;
6536 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6538 IWineD3DDeviceImpl *device = surface->resource.wineD3DDevice;
6539 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6541 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6542 if(surface->Flags & SFLAG_DIBSECTION) {
6543 /* Release the DC */
6544 SelectObject(surface->hDC, surface->dib.holdbitmap);
6545 DeleteDC(surface->hDC);
6546 /* Release the DIB section */
6547 DeleteObject(surface->dib.DIBsection);
6548 surface->dib.bitmap_data = NULL;
6549 surface->resource.allocatedMemory = NULL;
6550 surface->Flags &= ~SFLAG_DIBSECTION;
6552 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6553 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6554 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6555 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6557 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6558 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6559 } else {
6560 surface->pow2Width = surface->pow2Height = 1;
6561 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6562 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6564 surface->glRect.left = 0;
6565 surface->glRect.top = 0;
6566 surface->glRect.right = surface->pow2Width;
6567 surface->glRect.bottom = surface->pow2Height;
6569 if (surface->texture_name)
6571 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6572 ENTER_GL();
6573 glDeleteTextures(1, &surface->texture_name);
6574 LEAVE_GL();
6575 context_release(context);
6576 surface->texture_name = 0;
6577 surface->Flags &= ~SFLAG_CLIENT;
6579 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6580 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6581 surface->Flags |= SFLAG_NONPOW2;
6582 } else {
6583 surface->Flags &= ~SFLAG_NONPOW2;
6585 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6586 surface->resource.allocatedMemory = NULL;
6587 surface->resource.heapMemory = NULL;
6588 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6589 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6590 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6591 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6592 } else {
6593 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6597 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6598 TRACE("Unloading resource %p\n", resource);
6599 IWineD3DResource_UnLoad(resource);
6600 IWineD3DResource_Release(resource);
6601 return S_OK;
6604 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6606 UINT i, count;
6607 WINED3DDISPLAYMODE m;
6608 HRESULT hr;
6610 /* All Windowed modes are supported, as is leaving the current mode */
6611 if(pp->Windowed) return TRUE;
6612 if(!pp->BackBufferWidth) return TRUE;
6613 if(!pp->BackBufferHeight) return TRUE;
6615 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6616 for(i = 0; i < count; i++) {
6617 memset(&m, 0, sizeof(m));
6618 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6619 if(FAILED(hr)) {
6620 ERR("EnumAdapterModes failed\n");
6622 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6623 /* Mode found, it is supported */
6624 return TRUE;
6627 /* Mode not found -> not supported */
6628 return FALSE;
6631 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6633 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6634 const struct wined3d_gl_info *gl_info;
6635 struct wined3d_context *context;
6636 UINT i;
6637 IWineD3DBaseShaderImpl *shader;
6639 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6640 gl_info = context->gl_info;
6642 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6643 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6644 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6647 ENTER_GL();
6648 if(This->depth_blt_texture) {
6649 glDeleteTextures(1, &This->depth_blt_texture);
6650 This->depth_blt_texture = 0;
6652 if (This->depth_blt_rb) {
6653 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6654 This->depth_blt_rb = 0;
6655 This->depth_blt_rb_w = 0;
6656 This->depth_blt_rb_h = 0;
6658 LEAVE_GL();
6660 This->blitter->free_private(iface);
6661 This->frag_pipe->free_private(iface);
6662 This->shader_backend->shader_free_private(iface);
6664 ENTER_GL();
6665 for (i = 0; i < This->adapter->gl_info.limits.textures; ++i)
6667 /* Textures are recreated below */
6668 glDeleteTextures(1, &This->dummyTextureName[i]);
6669 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6670 This->dummyTextureName[i] = 0;
6672 LEAVE_GL();
6674 context_release(context);
6676 while (This->numContexts)
6678 context_destroy(This, This->contexts[0]);
6680 HeapFree(GetProcessHeap(), 0, swapchain->context);
6681 swapchain->context = NULL;
6682 swapchain->num_contexts = 0;
6685 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6687 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6688 HRESULT hr;
6689 IWineD3DSurfaceImpl *target;
6691 /* Recreate the primary swapchain's context */
6692 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6693 if(swapchain->backBuffer) {
6694 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6695 } else {
6696 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6698 swapchain->context[0] = context_create(This, target, swapchain->win_handle, FALSE, &swapchain->presentParms);
6699 swapchain->num_contexts = 1;
6701 create_dummy_textures(This);
6703 context_release(swapchain->context[0]);
6705 hr = This->shader_backend->shader_alloc_private(iface);
6706 if(FAILED(hr)) {
6707 ERR("Failed to recreate shader private data\n");
6708 goto err_out;
6710 hr = This->frag_pipe->alloc_private(iface);
6711 if(FAILED(hr)) {
6712 TRACE("Fragment pipeline private data couldn't be allocated\n");
6713 goto err_out;
6715 hr = This->blitter->alloc_private(iface);
6716 if(FAILED(hr)) {
6717 TRACE("Blitter private data couldn't be allocated\n");
6718 goto err_out;
6721 return WINED3D_OK;
6723 err_out:
6724 This->blitter->free_private(iface);
6725 This->frag_pipe->free_private(iface);
6726 This->shader_backend->shader_free_private(iface);
6727 return hr;
6730 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6732 IWineD3DSwapChainImpl *swapchain;
6733 HRESULT hr;
6734 BOOL DisplayModeChanged = FALSE;
6735 WINED3DDISPLAYMODE mode;
6736 TRACE("(%p)\n", This);
6738 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6739 if(FAILED(hr)) {
6740 ERR("Failed to get the first implicit swapchain\n");
6741 return hr;
6744 if(!is_display_mode_supported(This, pPresentationParameters)) {
6745 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6746 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6747 pPresentationParameters->BackBufferHeight);
6748 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6749 return WINED3DERR_INVALIDCALL;
6752 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6753 * on an existing gl context, so there's no real need for recreation.
6755 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6757 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6759 TRACE("New params:\n");
6760 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6761 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6762 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6763 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6764 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6765 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6766 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6767 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6768 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6769 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6770 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6771 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6772 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6774 /* No special treatment of these parameters. Just store them */
6775 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6776 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6777 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6778 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6780 /* What to do about these? */
6781 if(pPresentationParameters->BackBufferCount != 0 &&
6782 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6783 ERR("Cannot change the back buffer count yet\n");
6785 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6786 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6787 ERR("Cannot change the back buffer format yet\n");
6789 if(pPresentationParameters->hDeviceWindow != NULL &&
6790 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6791 ERR("Cannot change the device window yet\n");
6793 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6794 HRESULT hrc;
6796 TRACE("Creating the depth stencil buffer\n");
6798 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6799 This->parent,
6800 pPresentationParameters->BackBufferWidth,
6801 pPresentationParameters->BackBufferHeight,
6802 pPresentationParameters->AutoDepthStencilFormat,
6803 pPresentationParameters->MultiSampleType,
6804 pPresentationParameters->MultiSampleQuality,
6805 FALSE,
6806 &This->auto_depth_stencil_buffer);
6808 if (FAILED(hrc)) {
6809 ERR("Failed to create the depth stencil buffer\n");
6810 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6811 return WINED3DERR_INVALIDCALL;
6815 /* Reset the depth stencil */
6816 if (pPresentationParameters->EnableAutoDepthStencil)
6817 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6818 else
6819 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6821 TRACE("Resetting stateblock\n");
6822 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6823 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6825 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6827 if(pPresentationParameters->Windowed) {
6828 mode.Width = swapchain->orig_width;
6829 mode.Height = swapchain->orig_height;
6830 mode.RefreshRate = 0;
6831 mode.Format = swapchain->presentParms.BackBufferFormat;
6832 } else {
6833 mode.Width = pPresentationParameters->BackBufferWidth;
6834 mode.Height = pPresentationParameters->BackBufferHeight;
6835 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6836 mode.Format = swapchain->presentParms.BackBufferFormat;
6839 /* Should Width == 800 && Height == 0 set 800x600? */
6840 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6841 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6842 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6844 UINT i;
6846 if(!pPresentationParameters->Windowed) {
6847 DisplayModeChanged = TRUE;
6849 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6850 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6852 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6853 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6854 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6856 if(This->auto_depth_stencil_buffer) {
6857 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6861 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6862 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6863 DisplayModeChanged) {
6865 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6867 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
6868 if(swapchain->presentParms.Windowed) {
6869 /* switch from windowed to fs */
6870 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
6871 pPresentationParameters->BackBufferWidth,
6872 pPresentationParameters->BackBufferHeight);
6873 } else {
6874 /* Fullscreen -> fullscreen mode change */
6875 MoveWindow(swapchain->win_handle, 0, 0,
6876 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6877 TRUE);
6879 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
6880 /* Fullscreen -> windowed switch */
6881 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
6883 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6884 } else if(!pPresentationParameters->Windowed) {
6885 DWORD style = This->style, exStyle = This->exStyle;
6886 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6887 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6888 * Reset to clear up their mess. Guild Wars also loses the device during that.
6890 This->style = 0;
6891 This->exStyle = 0;
6892 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
6893 pPresentationParameters->BackBufferWidth,
6894 pPresentationParameters->BackBufferHeight);
6895 This->style = style;
6896 This->exStyle = exStyle;
6899 /* Note: No parent needed for initial internal stateblock */
6900 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6901 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6902 else TRACE("Created stateblock %p\n", This->stateBlock);
6903 This->updateStateBlock = This->stateBlock;
6904 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6906 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6907 if(FAILED(hr)) {
6908 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6911 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6912 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6914 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6915 * first use
6917 return hr;
6920 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6922 /** FIXME: always true at the moment **/
6923 if(!bEnableDialogs) {
6924 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6926 return WINED3D_OK;
6930 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6932 TRACE("(%p) : pParameters %p\n", This, pParameters);
6934 *pParameters = This->createParms;
6935 return WINED3D_OK;
6938 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6939 IWineD3DSwapChain *swapchain;
6941 TRACE("Relaying to swapchain\n");
6943 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6944 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6945 IWineD3DSwapChain_Release(swapchain);
6947 return;
6950 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6951 IWineD3DSwapChain *swapchain;
6953 TRACE("Relaying to swapchain\n");
6955 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6956 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6957 IWineD3DSwapChain_Release(swapchain);
6959 return;
6963 /** ********************************************************
6964 * Notification functions
6965 ** ********************************************************/
6966 /** This function must be called in the release of a resource when ref == 0,
6967 * the contents of resource must still be correct,
6968 * any handles to other resource held by the caller must be closed
6969 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6970 *****************************************************/
6971 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6973 TRACE("(%p) : Adding resource %p\n", This, resource);
6975 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6978 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6980 TRACE("(%p) : Removing resource %p\n", This, resource);
6982 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6985 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6987 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6988 int counter;
6990 TRACE("(%p) : resource %p\n", This, resource);
6992 context_resource_released((IWineD3DDevice *)This, resource, type);
6994 switch (type) {
6995 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6996 case WINED3DRTYPE_SURFACE: {
6997 unsigned int i;
6999 if (This->d3d_initialized)
7001 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
7003 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7004 This->render_targets[i] = NULL;
7007 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7008 This->stencilBufferTarget = NULL;
7012 break;
7014 case WINED3DRTYPE_TEXTURE:
7015 case WINED3DRTYPE_CUBETEXTURE:
7016 case WINED3DRTYPE_VOLUMETEXTURE:
7017 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7018 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7019 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7020 This->stateBlock->textures[counter] = NULL;
7022 if (This->updateStateBlock != This->stateBlock ){
7023 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7024 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7025 This->updateStateBlock->textures[counter] = NULL;
7029 break;
7030 case WINED3DRTYPE_VOLUME:
7031 /* TODO: nothing really? */
7032 break;
7033 case WINED3DRTYPE_BUFFER:
7035 int streamNumber;
7036 TRACE("Cleaning up stream pointers\n");
7038 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7039 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7040 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7042 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7043 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7044 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7045 This->updateStateBlock->streamSource[streamNumber] = 0;
7046 /* Set changed flag? */
7049 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) */
7050 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7051 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7052 This->stateBlock->streamSource[streamNumber] = 0;
7057 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7058 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7059 This->updateStateBlock->pIndexData = NULL;
7062 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7063 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7064 This->stateBlock->pIndexData = NULL;
7068 break;
7070 default:
7071 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7072 break;
7076 /* Remove the resource from the resourceStore */
7077 device_resource_remove(This, resource);
7079 TRACE("Resource released\n");
7083 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7085 IWineD3DResourceImpl *resource, *cursor;
7086 HRESULT ret;
7087 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7089 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7090 TRACE("enumerating resource %p\n", resource);
7091 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7092 ret = pCallback((IWineD3DResource *) resource, pData);
7093 if(ret == S_FALSE) {
7094 TRACE("Canceling enumeration\n");
7095 break;
7098 return WINED3D_OK;
7101 /**********************************************************
7102 * IWineD3DDevice VTbl follows
7103 **********************************************************/
7105 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7107 /*** IUnknown methods ***/
7108 IWineD3DDeviceImpl_QueryInterface,
7109 IWineD3DDeviceImpl_AddRef,
7110 IWineD3DDeviceImpl_Release,
7111 /*** IWineD3DDevice methods ***/
7112 IWineD3DDeviceImpl_GetParent,
7113 /*** Creation methods**/
7114 IWineD3DDeviceImpl_CreateBuffer,
7115 IWineD3DDeviceImpl_CreateVertexBuffer,
7116 IWineD3DDeviceImpl_CreateIndexBuffer,
7117 IWineD3DDeviceImpl_CreateStateBlock,
7118 IWineD3DDeviceImpl_CreateSurface,
7119 IWineD3DDeviceImpl_CreateRendertargetView,
7120 IWineD3DDeviceImpl_CreateTexture,
7121 IWineD3DDeviceImpl_CreateVolumeTexture,
7122 IWineD3DDeviceImpl_CreateVolume,
7123 IWineD3DDeviceImpl_CreateCubeTexture,
7124 IWineD3DDeviceImpl_CreateQuery,
7125 IWineD3DDeviceImpl_CreateSwapChain,
7126 IWineD3DDeviceImpl_CreateVertexDeclaration,
7127 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7128 IWineD3DDeviceImpl_CreateVertexShader,
7129 IWineD3DDeviceImpl_CreatePixelShader,
7130 IWineD3DDeviceImpl_CreatePalette,
7131 /*** Odd functions **/
7132 IWineD3DDeviceImpl_Init3D,
7133 IWineD3DDeviceImpl_InitGDI,
7134 IWineD3DDeviceImpl_Uninit3D,
7135 IWineD3DDeviceImpl_UninitGDI,
7136 IWineD3DDeviceImpl_SetMultithreaded,
7137 IWineD3DDeviceImpl_EvictManagedResources,
7138 IWineD3DDeviceImpl_GetAvailableTextureMem,
7139 IWineD3DDeviceImpl_GetBackBuffer,
7140 IWineD3DDeviceImpl_GetCreationParameters,
7141 IWineD3DDeviceImpl_GetDeviceCaps,
7142 IWineD3DDeviceImpl_GetDirect3D,
7143 IWineD3DDeviceImpl_GetDisplayMode,
7144 IWineD3DDeviceImpl_SetDisplayMode,
7145 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7146 IWineD3DDeviceImpl_GetRasterStatus,
7147 IWineD3DDeviceImpl_GetSwapChain,
7148 IWineD3DDeviceImpl_Reset,
7149 IWineD3DDeviceImpl_SetDialogBoxMode,
7150 IWineD3DDeviceImpl_SetCursorProperties,
7151 IWineD3DDeviceImpl_SetCursorPosition,
7152 IWineD3DDeviceImpl_ShowCursor,
7153 IWineD3DDeviceImpl_TestCooperativeLevel,
7154 /*** Getters and setters **/
7155 IWineD3DDeviceImpl_SetClipPlane,
7156 IWineD3DDeviceImpl_GetClipPlane,
7157 IWineD3DDeviceImpl_SetClipStatus,
7158 IWineD3DDeviceImpl_GetClipStatus,
7159 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7160 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7161 IWineD3DDeviceImpl_SetDepthStencilSurface,
7162 IWineD3DDeviceImpl_GetDepthStencilSurface,
7163 IWineD3DDeviceImpl_SetGammaRamp,
7164 IWineD3DDeviceImpl_GetGammaRamp,
7165 IWineD3DDeviceImpl_SetIndexBuffer,
7166 IWineD3DDeviceImpl_GetIndexBuffer,
7167 IWineD3DDeviceImpl_SetBaseVertexIndex,
7168 IWineD3DDeviceImpl_GetBaseVertexIndex,
7169 IWineD3DDeviceImpl_SetLight,
7170 IWineD3DDeviceImpl_GetLight,
7171 IWineD3DDeviceImpl_SetLightEnable,
7172 IWineD3DDeviceImpl_GetLightEnable,
7173 IWineD3DDeviceImpl_SetMaterial,
7174 IWineD3DDeviceImpl_GetMaterial,
7175 IWineD3DDeviceImpl_SetNPatchMode,
7176 IWineD3DDeviceImpl_GetNPatchMode,
7177 IWineD3DDeviceImpl_SetPaletteEntries,
7178 IWineD3DDeviceImpl_GetPaletteEntries,
7179 IWineD3DDeviceImpl_SetPixelShader,
7180 IWineD3DDeviceImpl_GetPixelShader,
7181 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7182 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7183 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7184 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7185 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7186 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7187 IWineD3DDeviceImpl_SetRenderState,
7188 IWineD3DDeviceImpl_GetRenderState,
7189 IWineD3DDeviceImpl_SetRenderTarget,
7190 IWineD3DDeviceImpl_GetRenderTarget,
7191 IWineD3DDeviceImpl_SetFrontBackBuffers,
7192 IWineD3DDeviceImpl_SetSamplerState,
7193 IWineD3DDeviceImpl_GetSamplerState,
7194 IWineD3DDeviceImpl_SetScissorRect,
7195 IWineD3DDeviceImpl_GetScissorRect,
7196 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7197 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7198 IWineD3DDeviceImpl_SetStreamSource,
7199 IWineD3DDeviceImpl_GetStreamSource,
7200 IWineD3DDeviceImpl_SetStreamSourceFreq,
7201 IWineD3DDeviceImpl_GetStreamSourceFreq,
7202 IWineD3DDeviceImpl_SetTexture,
7203 IWineD3DDeviceImpl_GetTexture,
7204 IWineD3DDeviceImpl_SetTextureStageState,
7205 IWineD3DDeviceImpl_GetTextureStageState,
7206 IWineD3DDeviceImpl_SetTransform,
7207 IWineD3DDeviceImpl_GetTransform,
7208 IWineD3DDeviceImpl_SetVertexDeclaration,
7209 IWineD3DDeviceImpl_GetVertexDeclaration,
7210 IWineD3DDeviceImpl_SetVertexShader,
7211 IWineD3DDeviceImpl_GetVertexShader,
7212 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7213 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7214 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7215 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7216 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7217 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7218 IWineD3DDeviceImpl_SetViewport,
7219 IWineD3DDeviceImpl_GetViewport,
7220 IWineD3DDeviceImpl_MultiplyTransform,
7221 IWineD3DDeviceImpl_ValidateDevice,
7222 IWineD3DDeviceImpl_ProcessVertices,
7223 /*** State block ***/
7224 IWineD3DDeviceImpl_BeginStateBlock,
7225 IWineD3DDeviceImpl_EndStateBlock,
7226 /*** Scene management ***/
7227 IWineD3DDeviceImpl_BeginScene,
7228 IWineD3DDeviceImpl_EndScene,
7229 IWineD3DDeviceImpl_Present,
7230 IWineD3DDeviceImpl_Clear,
7231 IWineD3DDeviceImpl_ClearRendertargetView,
7232 /*** Drawing ***/
7233 IWineD3DDeviceImpl_SetPrimitiveType,
7234 IWineD3DDeviceImpl_GetPrimitiveType,
7235 IWineD3DDeviceImpl_DrawPrimitive,
7236 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7237 IWineD3DDeviceImpl_DrawPrimitiveUP,
7238 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7239 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7240 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7241 IWineD3DDeviceImpl_DrawRectPatch,
7242 IWineD3DDeviceImpl_DrawTriPatch,
7243 IWineD3DDeviceImpl_DeletePatch,
7244 IWineD3DDeviceImpl_ColorFill,
7245 IWineD3DDeviceImpl_UpdateTexture,
7246 IWineD3DDeviceImpl_UpdateSurface,
7247 IWineD3DDeviceImpl_GetFrontBufferData,
7248 /*** object tracking ***/
7249 IWineD3DDeviceImpl_EnumResources
7252 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7253 DWORD rep = This->StateTable[state].representative;
7254 struct wined3d_context *context;
7255 DWORD idx;
7256 BYTE shift;
7257 UINT i;
7259 for(i = 0; i < This->numContexts; i++) {
7260 context = This->contexts[i];
7261 if(isStateDirty(context, rep)) continue;
7263 context->dirtyArray[context->numDirtyEntries++] = rep;
7264 idx = rep >> 5;
7265 shift = rep & 0x1f;
7266 context->isStateDirty[idx] |= (1 << shift);
7270 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7272 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.wineD3DDevice;
7273 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7274 *width = device->pbufferWidth;
7275 *height = device->pbufferHeight;
7278 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7280 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7281 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7282 *width = surface->pow2Width;
7283 *height = surface->pow2Height;
7286 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7288 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7289 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7290 * current context's drawable, which is the size of the back buffer of the swapchain
7291 * the active context belongs to. The back buffer of the swapchain is stored as the
7292 * surface the context belongs to. */
7293 *width = surface->currentDesc.Width;
7294 *height = surface->currentDesc.Height;