push 8b07bf1f08b23b9893a622b47d2be359556765b1
[wine/hacks.git] / dlls / wined3d / device.c
blob33c15ec9aed4b2b80f32fa0f96d10158ca2d4705
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 (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
303 stream_info->swizzle_map |= 1 << idx;
305 stream_info->use_map |= 1 << idx;
309 /* Now call PreLoad on all the vertex buffers. In the very rare case
310 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
311 * The vertex buffer can now use the strided structure in the device instead of finding its
312 * own again.
314 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
315 * once in there. */
316 for (i = 0; i < stream_count; ++i)
318 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
319 if (vb) IWineD3DBuffer_PreLoad(vb);
323 static void stream_info_element_from_strided(IWineD3DDeviceImpl *This,
324 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
326 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, &This->adapter->gl_info);
327 e->format_desc = format_desc;
328 e->stride = strided->dwStride;
329 e->data = strided->lpData;
330 e->stream_idx = 0;
331 e->buffer_object = 0;
334 void device_stream_info_from_strided(IWineD3DDeviceImpl *This,
335 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
337 unsigned int i;
339 memset(stream_info, 0, sizeof(*stream_info));
341 if (strided->position.lpData)
342 stream_info_element_from_strided(This, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
343 if (strided->normal.lpData)
344 stream_info_element_from_strided(This, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
345 if (strided->diffuse.lpData)
346 stream_info_element_from_strided(This, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
347 if (strided->specular.lpData)
348 stream_info_element_from_strided(This, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
350 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
352 if (strided->texCoords[i].lpData)
353 stream_info_element_from_strided(This, &strided->texCoords[i],
354 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
357 stream_info->position_transformed = strided->position_transformed;
359 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
361 if (!stream_info->elements[i].format_desc) continue;
363 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA)
364 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
366 stream_info->swizzle_map |= 1 << i;
368 stream_info->use_map |= 1 << i;
372 /**********************************************************
373 * IUnknown parts follows
374 **********************************************************/
376 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
380 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
381 if (IsEqualGUID(riid, &IID_IUnknown)
382 || IsEqualGUID(riid, &IID_IWineD3DBase)
383 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
384 IUnknown_AddRef(iface);
385 *ppobj = This;
386 return S_OK;
388 *ppobj = NULL;
389 return E_NOINTERFACE;
392 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
394 ULONG refCount = InterlockedIncrement(&This->ref);
396 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
397 return refCount;
400 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
402 ULONG refCount = InterlockedDecrement(&This->ref);
404 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
406 if (!refCount) {
407 UINT i;
409 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
410 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
411 This->multistate_funcs[i] = NULL;
414 /* TODO: Clean up all the surfaces and textures! */
415 /* NOTE: You must release the parent if the object was created via a callback
416 ** ***************************/
418 if (!list_empty(&This->resources)) {
419 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
420 dumpResources(&This->resources);
423 if(This->contexts) ERR("Context array not freed!\n");
424 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
425 This->haveHardwareCursor = FALSE;
427 IWineD3D_Release(This->wineD3D);
428 This->wineD3D = NULL;
429 HeapFree(GetProcessHeap(), 0, This);
430 TRACE("Freed device %p\n", This);
431 This = NULL;
433 return refCount;
436 /**********************************************************
437 * IWineD3DDevice implementation follows
438 **********************************************************/
439 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
441 *pParent = This->parent;
442 IUnknown_AddRef(This->parent);
443 return WINED3D_OK;
446 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
447 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
449 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
450 struct wined3d_buffer *object;
451 HRESULT hr;
453 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
455 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
456 if (!object)
458 ERR("Failed to allocate memory\n");
459 return E_OUTOFMEMORY;
462 FIXME("Ignoring access flags (pool)\n");
464 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
465 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
466 if (FAILED(hr))
468 WARN("Failed to initialize buffer, hr %#x.\n", hr);
469 HeapFree(GetProcessHeap(), 0, object);
470 return hr;
472 object->desc = *desc;
474 TRACE("Created buffer %p.\n", object);
476 *buffer = (IWineD3DBuffer *)object;
478 return WINED3D_OK;
481 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size,
482 DWORD Usage, DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
483 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
486 struct wined3d_buffer *object;
487 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
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(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
539 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
540 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
541 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
542 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
543 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
544 } else if(dxVersion <= 7 && conv) {
545 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
546 } else {
547 object->flags |= WINED3D_BUFFER_CREATEBO;
549 return WINED3D_OK;
552 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
553 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
554 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
557 struct wined3d_buffer *object;
558 HRESULT hr;
560 TRACE("(%p) Creating index buffer\n", This);
562 /* Allocate the storage for the device */
563 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
564 if (!object)
566 ERR("Out of memory\n");
567 *ppIndexBuffer = NULL;
568 return WINED3DERR_OUTOFVIDEOMEMORY;
571 hr = buffer_init(object, This, Length, Usage, WINED3DFMT_UNKNOWN,
572 Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
573 if (FAILED(hr))
575 WARN("Failed to initialize buffer, hr %#x\n", hr);
576 HeapFree(GetProcessHeap(), 0, object);
577 return hr;
580 TRACE("Created buffer %p.\n", object);
582 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
583 object->flags |= WINED3D_BUFFER_CREATEBO;
586 *ppIndexBuffer = (IWineD3DBuffer *) object;
588 return WINED3D_OK;
591 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
592 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
595 IWineD3DStateBlockImpl *object;
596 HRESULT hr;
598 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
599 if(!object)
601 ERR("Failed to allocate stateblock memory.\n");
602 return E_OUTOFMEMORY;
605 hr = stateblock_init(object, This, type, parent);
606 if (FAILED(hr))
608 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
609 HeapFree(GetProcessHeap(), 0, object);
610 return hr;
613 TRACE("Created stateblock %p.\n", object);
614 *stateblock = (IWineD3DStateBlock *)object;
616 return WINED3D_OK;
619 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
620 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
621 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
622 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
625 IWineD3DSurfaceImpl *object;
626 HRESULT hr;
628 TRACE("(%p) Create surface\n",This);
630 if (Impl == SURFACE_OPENGL && !This->adapter)
632 ERR("OpenGL surfaces are not available without OpenGL.\n");
633 return WINED3DERR_NOTAVAILABLE;
636 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
637 if (!object)
639 ERR("Failed to allocate surface memory.\n");
640 *ppSurface = NULL;
641 return WINED3DERR_OUTOFVIDEOMEMORY;
644 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
645 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
646 if (FAILED(hr))
648 WARN("Failed to initialize surface, returning %#x.\n", hr);
649 HeapFree(GetProcessHeap(), 0, object);
650 *ppSurface = NULL;
651 return hr;
654 TRACE("(%p) : Created surface %p\n", This, object);
656 *ppSurface = (IWineD3DSurface *)object;
658 return hr;
661 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
662 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
664 struct wined3d_rendertarget_view *object;
666 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
667 if (!object)
669 ERR("Failed to allocate memory\n");
670 return E_OUTOFMEMORY;
673 object->vtbl = &wined3d_rendertarget_view_vtbl;
674 object->refcount = 1;
675 IWineD3DResource_AddRef(resource);
676 object->resource = resource;
677 object->parent = parent;
679 *rendertarget_view = (IWineD3DRendertargetView *)object;
681 return WINED3D_OK;
684 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
685 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
686 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
689 IWineD3DTextureImpl *object;
690 HRESULT hr;
692 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
693 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
694 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
696 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
697 if (!object)
699 ERR("Out of memory\n");
700 *ppTexture = NULL;
701 return WINED3DERR_OUTOFVIDEOMEMORY;
704 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
705 if (FAILED(hr))
707 WARN("Failed to initialize texture, returning %#x\n", hr);
708 HeapFree(GetProcessHeap(), 0, object);
709 *ppTexture = NULL;
710 return hr;
713 *ppTexture = (IWineD3DTexture *)object;
715 TRACE("(%p) : Created texture %p\n", This, object);
717 return WINED3D_OK;
720 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
721 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
722 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
725 IWineD3DVolumeTextureImpl *object;
726 HRESULT hr;
728 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
729 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
731 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
732 if (!object)
734 ERR("Out of memory\n");
735 *ppVolumeTexture = NULL;
736 return WINED3DERR_OUTOFVIDEOMEMORY;
739 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
740 if (FAILED(hr))
742 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
743 HeapFree(GetProcessHeap(), 0, object);
744 *ppVolumeTexture = NULL;
745 return hr;
748 TRACE("(%p) : Created volume texture %p.\n", This, object);
749 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
751 return WINED3D_OK;
754 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
755 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
756 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
759 IWineD3DVolumeImpl *object;
760 HRESULT hr;
762 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
763 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
765 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
766 if (!object)
768 ERR("Out of memory\n");
769 *ppVolume = NULL;
770 return WINED3DERR_OUTOFVIDEOMEMORY;
773 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
774 if (FAILED(hr))
776 WARN("Failed to initialize volume, returning %#x.\n", hr);
777 HeapFree(GetProcessHeap(), 0, object);
778 return hr;
781 TRACE("(%p) : Created volume %p.\n", This, object);
782 *ppVolume = (IWineD3DVolume *)object;
784 return WINED3D_OK;
787 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
788 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
789 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
792 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
793 HRESULT hr;
795 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
796 if (!object)
798 ERR("Out of memory\n");
799 *ppCubeTexture = NULL;
800 return WINED3DERR_OUTOFVIDEOMEMORY;
803 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
804 if (FAILED(hr))
806 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
807 HeapFree(GetProcessHeap(), 0, object);
808 *ppCubeTexture = NULL;
809 return hr;
812 TRACE("(%p) : Created Cube Texture %p\n", This, object);
813 *ppCubeTexture = (IWineD3DCubeTexture *)object;
815 return WINED3D_OK;
818 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
820 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
821 HRESULT hr = WINED3DERR_NOTAVAILABLE;
822 const IWineD3DQueryVtbl *vtable;
824 /* Just a check to see if we support this type of query */
825 switch(Type) {
826 case WINED3DQUERYTYPE_OCCLUSION:
827 TRACE("(%p) occlusion query\n", This);
828 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
829 hr = WINED3D_OK;
830 else
831 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
833 vtable = &IWineD3DOcclusionQuery_Vtbl;
834 break;
836 case WINED3DQUERYTYPE_EVENT:
837 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
838 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
839 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
841 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
843 vtable = &IWineD3DEventQuery_Vtbl;
844 hr = WINED3D_OK;
845 break;
847 case WINED3DQUERYTYPE_VCACHE:
848 case WINED3DQUERYTYPE_RESOURCEMANAGER:
849 case WINED3DQUERYTYPE_VERTEXSTATS:
850 case WINED3DQUERYTYPE_TIMESTAMP:
851 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
852 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
853 case WINED3DQUERYTYPE_PIPELINETIMINGS:
854 case WINED3DQUERYTYPE_INTERFACETIMINGS:
855 case WINED3DQUERYTYPE_VERTEXTIMINGS:
856 case WINED3DQUERYTYPE_PIXELTIMINGS:
857 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
858 case WINED3DQUERYTYPE_CACHEUTILIZATION:
859 default:
860 /* Use the base Query vtable until we have a special one for each query */
861 vtable = &IWineD3DQuery_Vtbl;
862 FIXME("(%p) Unhandled query type %d\n", This, Type);
864 if(NULL == ppQuery || hr != WINED3D_OK) {
865 return hr;
868 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
869 if(!object)
871 ERR("Out of memory\n");
872 *ppQuery = NULL;
873 return WINED3DERR_OUTOFVIDEOMEMORY;
876 object->lpVtbl = vtable;
877 object->type = Type;
878 object->state = QUERY_CREATED;
879 object->wineD3DDevice = This;
880 object->parent = parent;
881 object->ref = 1;
883 *ppQuery = (IWineD3DQuery *)object;
885 /* allocated the 'extended' data based on the type of query requested */
886 switch(Type){
887 case WINED3DQUERYTYPE_OCCLUSION:
888 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
889 ((struct wined3d_occlusion_query *)object->extendedData)->context = NULL;
890 break;
892 case WINED3DQUERYTYPE_EVENT:
893 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query));
894 ((struct wined3d_event_query *)object->extendedData)->context = NULL;
895 break;
897 case WINED3DQUERYTYPE_VCACHE:
898 case WINED3DQUERYTYPE_RESOURCEMANAGER:
899 case WINED3DQUERYTYPE_VERTEXSTATS:
900 case WINED3DQUERYTYPE_TIMESTAMP:
901 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
902 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
903 case WINED3DQUERYTYPE_PIPELINETIMINGS:
904 case WINED3DQUERYTYPE_INTERFACETIMINGS:
905 case WINED3DQUERYTYPE_VERTEXTIMINGS:
906 case WINED3DQUERYTYPE_PIXELTIMINGS:
907 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
908 case WINED3DQUERYTYPE_CACHEUTILIZATION:
909 default:
910 object->extendedData = 0;
911 FIXME("(%p) Unhandled query type %d\n",This , Type);
913 TRACE("(%p) : Created Query %p\n", This, object);
914 return WINED3D_OK;
917 /*****************************************************************************
918 * IWineD3DDeviceImpl_SetupFullscreenWindow
920 * Helper function that modifies a HWND's Style and ExStyle for proper
921 * fullscreen use.
923 * Params:
924 * iface: Pointer to the IWineD3DDevice interface
925 * window: Window to setup
927 *****************************************************************************/
928 static LONG fullscreen_style(LONG orig_style) {
929 LONG style = orig_style;
930 style &= ~WS_CAPTION;
931 style &= ~WS_THICKFRAME;
933 /* Make sure the window is managed, otherwise we won't get keyboard input */
934 style |= WS_POPUP | WS_SYSMENU;
936 return style;
939 static LONG fullscreen_exStyle(LONG orig_exStyle) {
940 LONG exStyle = orig_exStyle;
942 /* Filter out window decorations */
943 exStyle &= ~WS_EX_WINDOWEDGE;
944 exStyle &= ~WS_EX_CLIENTEDGE;
946 return exStyle;
949 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
952 LONG style, exStyle;
953 /* Don't do anything if an original style is stored.
954 * That shouldn't happen
956 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
957 if (This->style || This->exStyle) {
958 ERR("(%p): Want to change the window parameters of HWND %p, but "
959 "another style is stored for restoration afterwards\n", This, window);
962 /* Get the parameters and save them */
963 style = GetWindowLongW(window, GWL_STYLE);
964 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
965 This->style = style;
966 This->exStyle = exStyle;
968 style = fullscreen_style(style);
969 exStyle = fullscreen_exStyle(exStyle);
971 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
972 This->style, This->exStyle, style, exStyle);
974 SetWindowLongW(window, GWL_STYLE, style);
975 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
977 /* Inform the window about the update. */
978 SetWindowPos(window, HWND_TOP, 0, 0,
979 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
982 /*****************************************************************************
983 * IWineD3DDeviceImpl_RestoreWindow
985 * Helper function that restores a windows' properties when taking it out
986 * of fullscreen mode
988 * Params:
989 * iface: Pointer to the IWineD3DDevice interface
990 * window: Window to setup
992 *****************************************************************************/
993 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
995 LONG style, exStyle;
997 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
998 * switch, do nothing
1000 if (!This->style && !This->exStyle) return;
1002 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1003 This, window, This->style, This->exStyle);
1005 style = GetWindowLongW(window, GWL_STYLE);
1006 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1008 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1009 * Some applications change it before calling Reset() when switching between windowed and
1010 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1012 if(style == fullscreen_style(This->style) &&
1013 exStyle == fullscreen_style(This->exStyle)) {
1014 SetWindowLongW(window, GWL_STYLE, This->style);
1015 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1018 /* Delete the old values */
1019 This->style = 0;
1020 This->exStyle = 0;
1022 /* Inform the window about the update */
1023 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1024 0, 0, 0, 0, /* Pos, Size, ignored */
1025 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1028 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1029 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1030 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1031 IUnknown *parent, WINED3DSURFTYPE surface_type)
1033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1035 HDC hDc;
1036 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1037 HRESULT hr;
1038 BOOL displaymode_set = FALSE;
1039 WINED3DDISPLAYMODE Mode;
1040 const struct GlPixelFormatDesc *format_desc;
1042 TRACE("(%p) : Created Additional Swap Chain\n", This);
1044 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1045 * does a device hold a reference to a swap chain giving them a lifetime of the device
1046 * or does the swap chain notify the device of its destruction.
1047 *******************************/
1049 /* Check the params */
1050 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1051 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1052 return WINED3DERR_INVALIDCALL;
1053 } else if (pPresentationParameters->BackBufferCount > 1) {
1054 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");
1057 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1058 if(!object)
1060 ERR("Out of memory\n");
1061 *ppSwapChain = NULL;
1062 return WINED3DERR_OUTOFVIDEOMEMORY;
1065 switch(surface_type) {
1066 case SURFACE_GDI:
1067 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1068 break;
1069 case SURFACE_OPENGL:
1070 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1071 break;
1072 case SURFACE_UNKNOWN:
1073 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1074 HeapFree(GetProcessHeap(), 0, object);
1075 return WINED3DERR_INVALIDCALL;
1077 object->wineD3DDevice = This;
1078 object->parent = parent;
1079 object->ref = 1;
1081 *ppSwapChain = (IWineD3DSwapChain *)object;
1083 /*********************
1084 * Lookup the window Handle and the relating X window handle
1085 ********************/
1087 /* Setup hwnd we are using, plus which display this equates to */
1088 object->win_handle = pPresentationParameters->hDeviceWindow;
1089 if (!object->win_handle) {
1090 object->win_handle = This->createParms.hFocusWindow;
1092 if(!pPresentationParameters->Windowed && object->win_handle) {
1093 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1094 pPresentationParameters->BackBufferWidth,
1095 pPresentationParameters->BackBufferHeight);
1098 hDc = GetDC(object->win_handle);
1099 TRACE("Using hDc %p\n", hDc);
1101 if (NULL == hDc) {
1102 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1103 return WINED3DERR_NOTAVAILABLE;
1106 /* Get info on the current display setup */
1107 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1108 object->orig_width = Mode.Width;
1109 object->orig_height = Mode.Height;
1110 object->orig_fmt = Mode.Format;
1111 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1113 if (pPresentationParameters->Windowed &&
1114 ((pPresentationParameters->BackBufferWidth == 0) ||
1115 (pPresentationParameters->BackBufferHeight == 0) ||
1116 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1118 RECT Rect;
1119 GetClientRect(object->win_handle, &Rect);
1121 if (pPresentationParameters->BackBufferWidth == 0) {
1122 pPresentationParameters->BackBufferWidth = Rect.right;
1123 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1125 if (pPresentationParameters->BackBufferHeight == 0) {
1126 pPresentationParameters->BackBufferHeight = Rect.bottom;
1127 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1129 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1130 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1131 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1135 /* Put the correct figures in the presentation parameters */
1136 TRACE("Copying across presentation parameters\n");
1137 object->presentParms = *pPresentationParameters;
1139 TRACE("calling rendertarget CB\n");
1140 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1141 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1142 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1143 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1144 if (SUCCEEDED(hr)) {
1145 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1146 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1147 if(surface_type == SURFACE_OPENGL) {
1148 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1150 } else {
1151 ERR("Failed to create the front buffer\n");
1152 goto error;
1155 /*********************
1156 * Windowed / Fullscreen
1157 *******************/
1160 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1161 * so we should really check to see if there is a fullscreen swapchain already
1162 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1163 **************************************/
1165 if (!pPresentationParameters->Windowed) {
1166 WINED3DDISPLAYMODE mode;
1169 /* Change the display settings */
1170 mode.Width = pPresentationParameters->BackBufferWidth;
1171 mode.Height = pPresentationParameters->BackBufferHeight;
1172 mode.Format = pPresentationParameters->BackBufferFormat;
1173 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1175 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1176 displaymode_set = TRUE;
1180 * Create an opengl context for the display visual
1181 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1182 * use different properties after that point in time. FIXME: How to handle when requested format
1183 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1184 * it chooses is identical to the one already being used!
1185 **********************************/
1186 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1188 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1189 if(!object->context) {
1190 ERR("Failed to create the context array\n");
1191 hr = E_OUTOFMEMORY;
1192 goto error;
1194 object->num_contexts = 1;
1196 if(surface_type == SURFACE_OPENGL) {
1197 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1198 if (!object->context[0]) {
1199 ERR("Failed to create a new context\n");
1200 hr = WINED3DERR_NOTAVAILABLE;
1201 goto error;
1202 } else {
1203 TRACE("Context created (HWND=%p, glContext=%p)\n",
1204 object->win_handle, object->context[0]->glCtx);
1208 /*********************
1209 * Create the back, front and stencil buffers
1210 *******************/
1211 if(object->presentParms.BackBufferCount > 0) {
1212 UINT i;
1214 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1215 if(!object->backBuffer) {
1216 ERR("Out of memory\n");
1217 hr = E_OUTOFMEMORY;
1218 goto error;
1221 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1222 TRACE("calling rendertarget CB\n");
1223 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1224 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1225 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1226 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1227 if(SUCCEEDED(hr)) {
1228 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1229 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1230 } else {
1231 ERR("Cannot create new back buffer\n");
1232 goto error;
1234 if(surface_type == SURFACE_OPENGL) {
1235 ENTER_GL();
1236 glDrawBuffer(GL_BACK);
1237 checkGLcall("glDrawBuffer(GL_BACK)");
1238 LEAVE_GL();
1241 } else {
1242 object->backBuffer = NULL;
1244 /* Single buffering - draw to front buffer */
1245 if(surface_type == SURFACE_OPENGL) {
1246 ENTER_GL();
1247 glDrawBuffer(GL_FRONT);
1248 checkGLcall("glDrawBuffer(GL_FRONT)");
1249 LEAVE_GL();
1253 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1254 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1255 TRACE("Creating depth stencil buffer\n");
1256 if (This->auto_depth_stencil_buffer == NULL ) {
1257 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1258 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1259 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1260 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1261 &This->auto_depth_stencil_buffer);
1262 if (SUCCEEDED(hr)) {
1263 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1264 } else {
1265 ERR("Failed to create the auto depth stencil\n");
1266 goto error;
1271 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1273 TRACE("Created swapchain %p\n", object);
1274 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1275 return WINED3D_OK;
1277 error:
1278 if (displaymode_set) {
1279 DEVMODEW devmode;
1280 RECT clip_rc;
1282 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1283 ClipCursor(NULL);
1285 /* Change the display settings */
1286 memset(&devmode, 0, sizeof(devmode));
1287 devmode.dmSize = sizeof(devmode);
1288 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1289 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1290 devmode.dmPelsWidth = object->orig_width;
1291 devmode.dmPelsHeight = object->orig_height;
1292 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1295 if (object->backBuffer) {
1296 UINT i;
1297 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1298 if (object->backBuffer[i]) IWineD3DSurface_Release(object->backBuffer[i]);
1300 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1301 object->backBuffer = NULL;
1303 if(object->context && object->context[0])
1304 DestroyContext(This, object->context[0]);
1305 if (object->frontBuffer) IWineD3DSurface_Release(object->frontBuffer);
1306 HeapFree(GetProcessHeap(), 0, object);
1307 return hr;
1310 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1311 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1313 TRACE("(%p)\n", This);
1315 return This->NumberOfSwapChains;
1318 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1320 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1322 if(iSwapChain < This->NumberOfSwapChains) {
1323 *pSwapChain = This->swapchains[iSwapChain];
1324 IWineD3DSwapChain_AddRef(*pSwapChain);
1325 TRACE("(%p) returning %p\n", This, *pSwapChain);
1326 return WINED3D_OK;
1327 } else {
1328 TRACE("Swapchain out of range\n");
1329 *pSwapChain = NULL;
1330 return WINED3DERR_INVALIDCALL;
1334 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1335 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1336 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1339 IWineD3DVertexDeclarationImpl *object = NULL;
1340 HRESULT hr;
1342 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1343 iface, declaration, parent, elements, element_count);
1345 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1346 if(!object)
1348 ERR("Failed to allocate vertex declaration memory.\n");
1349 return E_OUTOFMEMORY;
1352 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1353 if (FAILED(hr))
1355 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1356 HeapFree(GetProcessHeap(), 0, object);
1357 return hr;
1360 TRACE("Created verrtex declaration %p.\n", object);
1361 *declaration = (IWineD3DVertexDeclaration *)object;
1363 return WINED3D_OK;
1366 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1367 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1369 unsigned int idx, idx2;
1370 unsigned int offset;
1371 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1372 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1373 BOOL has_blend_idx = has_blend &&
1374 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1375 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1376 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1377 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1378 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1379 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1380 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1382 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1383 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1384 WINED3DVERTEXELEMENT *elements = NULL;
1386 unsigned int size;
1387 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1388 if (has_blend_idx) num_blends--;
1390 /* Compute declaration size */
1391 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1392 has_psize + has_diffuse + has_specular + num_textures;
1394 /* convert the declaration */
1395 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1396 if (!elements) return ~0U;
1398 idx = 0;
1399 if (has_pos) {
1400 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1401 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1402 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1404 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1405 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1406 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1408 else {
1409 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1410 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1412 elements[idx].usage_idx = 0;
1413 idx++;
1415 if (has_blend && (num_blends > 0)) {
1416 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1417 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1418 else {
1419 switch(num_blends) {
1420 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1421 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1422 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1423 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1424 default:
1425 ERR("Unexpected amount of blend values: %u\n", num_blends);
1428 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1429 elements[idx].usage_idx = 0;
1430 idx++;
1432 if (has_blend_idx) {
1433 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1434 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1435 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1436 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1437 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1438 else
1439 elements[idx].format = WINED3DFMT_R32_FLOAT;
1440 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1441 elements[idx].usage_idx = 0;
1442 idx++;
1444 if (has_normal) {
1445 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1446 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1447 elements[idx].usage_idx = 0;
1448 idx++;
1450 if (has_psize) {
1451 elements[idx].format = WINED3DFMT_R32_FLOAT;
1452 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1453 elements[idx].usage_idx = 0;
1454 idx++;
1456 if (has_diffuse) {
1457 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1458 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1459 elements[idx].usage_idx = 0;
1460 idx++;
1462 if (has_specular) {
1463 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1464 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1465 elements[idx].usage_idx = 1;
1466 idx++;
1468 for (idx2 = 0; idx2 < num_textures; idx2++) {
1469 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1470 switch (numcoords) {
1471 case WINED3DFVF_TEXTUREFORMAT1:
1472 elements[idx].format = WINED3DFMT_R32_FLOAT;
1473 break;
1474 case WINED3DFVF_TEXTUREFORMAT2:
1475 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1476 break;
1477 case WINED3DFVF_TEXTUREFORMAT3:
1478 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1479 break;
1480 case WINED3DFVF_TEXTUREFORMAT4:
1481 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1482 break;
1484 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1485 elements[idx].usage_idx = idx2;
1486 idx++;
1489 /* Now compute offsets, and initialize the rest of the fields */
1490 for (idx = 0, offset = 0; idx < size; ++idx)
1492 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1493 elements[idx].input_slot = 0;
1494 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1495 elements[idx].offset = offset;
1496 offset += format_desc->component_count * format_desc->component_size;
1499 *ppVertexElements = elements;
1500 return size;
1503 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1504 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1505 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1507 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1508 WINED3DVERTEXELEMENT *elements;
1509 unsigned int size;
1510 DWORD hr;
1512 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1514 size = ConvertFvfToDeclaration(This, fvf, &elements);
1515 if (size == ~0U) return E_OUTOFMEMORY;
1517 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1518 HeapFree(GetProcessHeap(), 0, elements);
1519 return hr;
1522 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1523 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1524 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1525 const struct wined3d_parent_ops *parent_ops)
1527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1528 IWineD3DVertexShaderImpl *object;
1529 HRESULT hr;
1531 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1532 if (!object)
1534 ERR("Failed to allocate shader memory.\n");
1535 return E_OUTOFMEMORY;
1538 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1539 if (FAILED(hr))
1541 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1542 HeapFree(GetProcessHeap(), 0, object);
1543 return hr;
1546 TRACE("Created vertex shader %p.\n", object);
1547 *ppVertexShader = (IWineD3DVertexShader *)object;
1549 return WINED3D_OK;
1552 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1553 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1554 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1555 const struct wined3d_parent_ops *parent_ops)
1557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1558 IWineD3DPixelShaderImpl *object;
1559 HRESULT hr;
1561 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1562 if (!object)
1564 ERR("Failed to allocate shader memory.\n");
1565 return E_OUTOFMEMORY;
1568 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1569 if (FAILED(hr))
1571 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1572 HeapFree(GetProcessHeap(), 0, object);
1573 return hr;
1576 TRACE("Created pixel shader %p.\n", object);
1577 *ppPixelShader = (IWineD3DPixelShader *)object;
1579 return WINED3D_OK;
1582 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1583 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1586 IWineD3DPaletteImpl *object;
1587 HRESULT hr;
1588 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1590 /* Create the new object */
1591 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1592 if(!object) {
1593 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1594 return E_OUTOFMEMORY;
1597 object->lpVtbl = &IWineD3DPalette_Vtbl;
1598 object->ref = 1;
1599 object->Flags = Flags;
1600 object->parent = Parent;
1601 object->wineD3DDevice = This;
1602 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1603 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1605 if(!object->hpal) {
1606 HeapFree( GetProcessHeap(), 0, object);
1607 return E_OUTOFMEMORY;
1610 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1611 if(FAILED(hr)) {
1612 IWineD3DPalette_Release((IWineD3DPalette *) object);
1613 return hr;
1616 *Palette = (IWineD3DPalette *) object;
1618 return WINED3D_OK;
1621 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1622 HBITMAP hbm;
1623 BITMAP bm;
1624 HRESULT hr;
1625 HDC dcb = NULL, dcs = NULL;
1626 WINEDDCOLORKEY colorkey;
1628 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1629 if(hbm)
1631 GetObjectA(hbm, sizeof(BITMAP), &bm);
1632 dcb = CreateCompatibleDC(NULL);
1633 if(!dcb) goto out;
1634 SelectObject(dcb, hbm);
1636 else
1638 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1639 * couldn't be loaded
1641 memset(&bm, 0, sizeof(bm));
1642 bm.bmWidth = 32;
1643 bm.bmHeight = 32;
1646 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1647 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1648 NULL, &wined3d_null_parent_ops);
1649 if(FAILED(hr)) {
1650 ERR("Wine logo requested, but failed to create surface\n");
1651 goto out;
1654 if(dcb) {
1655 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1656 if(FAILED(hr)) goto out;
1657 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1658 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1660 colorkey.dwColorSpaceLowValue = 0;
1661 colorkey.dwColorSpaceHighValue = 0;
1662 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1663 } else {
1664 /* Fill the surface with a white color to show that wined3d is there */
1665 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1668 out:
1669 if(dcb) {
1670 DeleteDC(dcb);
1672 if(hbm) {
1673 DeleteObject(hbm);
1675 return;
1678 /* Context activation is done by the caller. */
1679 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1680 unsigned int i;
1681 /* Under DirectX you can have texture stage operations even if no texture is
1682 bound, whereas opengl will only do texture operations when a valid texture is
1683 bound. We emulate this by creating dummy textures and binding them to each
1684 texture stage, but disable all stages by default. Hence if a stage is enabled
1685 then the default texture will kick in until replaced by a SetTexture call */
1686 ENTER_GL();
1688 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1689 /* The dummy texture does not have client storage backing */
1690 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1691 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1693 for (i = 0; i < GL_LIMITS(textures); i++) {
1694 GLubyte white = 255;
1696 /* Make appropriate texture active */
1697 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1698 checkGLcall("glActiveTextureARB");
1700 /* Generate an opengl texture name */
1701 glGenTextures(1, &This->dummyTextureName[i]);
1702 checkGLcall("glGenTextures");
1703 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1705 /* Generate a dummy 2d texture (not using 1d because they cause many
1706 * DRI drivers fall back to sw) */
1707 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1708 checkGLcall("glBindTexture");
1710 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1711 checkGLcall("glTexImage2D");
1713 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1714 /* Reenable because if supported it is enabled by default */
1715 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1716 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1719 LEAVE_GL();
1722 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1723 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1726 IWineD3DSwapChainImpl *swapchain = NULL;
1727 HRESULT hr;
1728 DWORD state;
1729 unsigned int i;
1731 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1733 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1734 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1736 /* TODO: Test if OpenGL is compiled in and loaded */
1738 TRACE("(%p) : Creating stateblock\n", This);
1739 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1740 hr = IWineD3DDevice_CreateStateBlock(iface,
1741 WINED3DSBT_INIT,
1742 (IWineD3DStateBlock **)&This->stateBlock,
1743 NULL);
1744 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1745 WARN("Failed to create stateblock\n");
1746 goto err_out;
1748 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1749 This->updateStateBlock = This->stateBlock;
1750 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1752 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1753 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1755 This->NumberOfPalettes = 1;
1756 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1757 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1758 ERR("Out of memory!\n");
1759 goto err_out;
1761 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1762 if(!This->palettes[0]) {
1763 ERR("Out of memory!\n");
1764 goto err_out;
1766 for (i = 0; i < 256; ++i) {
1767 This->palettes[0][i].peRed = 0xFF;
1768 This->palettes[0][i].peGreen = 0xFF;
1769 This->palettes[0][i].peBlue = 0xFF;
1770 This->palettes[0][i].peFlags = 0xFF;
1772 This->currentPalette = 0;
1774 /* Initialize the texture unit mapping to a 1:1 mapping */
1775 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1776 if (state < GL_LIMITS(fragment_samplers)) {
1777 This->texUnitMap[state] = state;
1778 This->rev_tex_unit_map[state] = state;
1779 } else {
1780 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1781 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1785 /* Setup the implicit swapchain. This also initializes a context. */
1786 TRACE("Creating implicit swapchain\n");
1787 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1788 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1789 if (FAILED(hr))
1791 WARN("Failed to create implicit swapchain\n");
1792 goto err_out;
1795 This->NumberOfSwapChains = 1;
1796 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1797 if(!This->swapchains) {
1798 ERR("Out of memory!\n");
1799 goto err_out;
1801 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1803 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1804 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1805 This->render_targets[0] = swapchain->backBuffer[0];
1807 else {
1808 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1809 This->render_targets[0] = swapchain->frontBuffer;
1811 IWineD3DSurface_AddRef(This->render_targets[0]);
1813 /* Depth Stencil support */
1814 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1815 if (NULL != This->stencilBufferTarget) {
1816 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1819 hr = This->shader_backend->shader_alloc_private(iface);
1820 if(FAILED(hr)) {
1821 TRACE("Shader private data couldn't be allocated\n");
1822 goto err_out;
1824 hr = This->frag_pipe->alloc_private(iface);
1825 if(FAILED(hr)) {
1826 TRACE("Fragment pipeline private data couldn't be allocated\n");
1827 goto err_out;
1829 hr = This->blitter->alloc_private(iface);
1830 if(FAILED(hr)) {
1831 TRACE("Blitter private data couldn't be allocated\n");
1832 goto err_out;
1835 /* Set up some starting GL setup */
1837 /* Setup all the devices defaults */
1838 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1839 create_dummy_textures(This);
1841 ENTER_GL();
1843 /* Initialize the current view state */
1844 This->view_ident = 1;
1845 This->contexts[0]->last_was_rhw = 0;
1846 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1847 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1849 switch(wined3d_settings.offscreen_rendering_mode) {
1850 case ORM_FBO:
1851 case ORM_PBUFFER:
1852 This->offscreenBuffer = GL_BACK;
1853 break;
1855 case ORM_BACKBUFFER:
1857 if (context_get_current()->aux_buffers > 0)
1859 TRACE("Using auxilliary buffer for offscreen rendering\n");
1860 This->offscreenBuffer = GL_AUX0;
1861 } else {
1862 TRACE("Using back buffer for offscreen rendering\n");
1863 This->offscreenBuffer = GL_BACK;
1868 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1869 LEAVE_GL();
1871 /* Clear the screen */
1872 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1873 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1874 0x00, 1.0f, 0);
1876 This->d3d_initialized = TRUE;
1878 if(wined3d_settings.logo) {
1879 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1881 This->highest_dirty_ps_const = 0;
1882 This->highest_dirty_vs_const = 0;
1883 return WINED3D_OK;
1885 err_out:
1886 HeapFree(GetProcessHeap(), 0, This->render_targets);
1887 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1888 HeapFree(GetProcessHeap(), 0, This->swapchains);
1889 This->NumberOfSwapChains = 0;
1890 if(This->palettes) {
1891 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1892 HeapFree(GetProcessHeap(), 0, This->palettes);
1894 This->NumberOfPalettes = 0;
1895 if(swapchain) {
1896 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1898 if(This->stateBlock) {
1899 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1900 This->stateBlock = NULL;
1902 if (This->blit_priv) {
1903 This->blitter->free_private(iface);
1905 if (This->fragment_priv) {
1906 This->frag_pipe->free_private(iface);
1908 if (This->shader_priv) {
1909 This->shader_backend->shader_free_private(iface);
1911 return hr;
1914 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1915 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1918 IWineD3DSwapChainImpl *swapchain = NULL;
1919 HRESULT hr;
1921 /* Setup the implicit swapchain */
1922 TRACE("Creating implicit swapchain\n");
1923 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1924 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1925 if (FAILED(hr))
1927 WARN("Failed to create implicit swapchain\n");
1928 goto err_out;
1931 This->NumberOfSwapChains = 1;
1932 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1933 if(!This->swapchains) {
1934 ERR("Out of memory!\n");
1935 goto err_out;
1937 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1938 return WINED3D_OK;
1940 err_out:
1941 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1942 return hr;
1945 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1947 IWineD3DResource_UnLoad(resource);
1948 IWineD3DResource_Release(resource);
1949 return WINED3D_OK;
1952 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1953 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1956 const struct wined3d_context *context;
1957 const struct wined3d_gl_info *gl_info;
1958 int sampler;
1959 UINT i;
1960 TRACE("(%p)\n", This);
1962 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1964 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1965 * it was created. Thus make sure a context is active for the glDelete* calls
1967 context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
1968 gl_info = context->gl_info;
1970 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1972 /* Unload resources */
1973 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1975 TRACE("Deleting high order patches\n");
1976 for(i = 0; i < PATCHMAP_SIZE; i++) {
1977 struct list *e1, *e2;
1978 struct WineD3DRectPatch *patch;
1979 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1980 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1981 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1985 /* Delete the palette conversion shader if it is around */
1986 if(This->paletteConversionShader) {
1987 ENTER_GL();
1988 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
1989 LEAVE_GL();
1990 This->paletteConversionShader = 0;
1993 /* Delete the pbuffer context if there is any */
1994 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1996 /* Delete the mouse cursor texture */
1997 if(This->cursorTexture) {
1998 ENTER_GL();
1999 glDeleteTextures(1, &This->cursorTexture);
2000 LEAVE_GL();
2001 This->cursorTexture = 0;
2004 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2005 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2007 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2008 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2011 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2012 * private data, it might contain opengl pointers
2014 if(This->depth_blt_texture) {
2015 ENTER_GL();
2016 glDeleteTextures(1, &This->depth_blt_texture);
2017 LEAVE_GL();
2018 This->depth_blt_texture = 0;
2020 if (This->depth_blt_rb) {
2021 ENTER_GL();
2022 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2023 LEAVE_GL();
2024 This->depth_blt_rb = 0;
2025 This->depth_blt_rb_w = 0;
2026 This->depth_blt_rb_h = 0;
2029 /* Release the update stateblock */
2030 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2031 if(This->updateStateBlock != This->stateBlock)
2032 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2034 This->updateStateBlock = NULL;
2036 { /* because were not doing proper internal refcounts releasing the primary state block
2037 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2038 to set this->stateBlock = NULL; first */
2039 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2040 This->stateBlock = NULL;
2042 /* Release the stateblock */
2043 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2044 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2048 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2049 This->blitter->free_private(iface);
2050 This->frag_pipe->free_private(iface);
2051 This->shader_backend->shader_free_private(iface);
2053 /* Release the buffers (with sanity checks)*/
2054 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2055 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2056 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2057 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2059 This->stencilBufferTarget = NULL;
2061 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2062 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2063 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2065 TRACE("Setting rendertarget to NULL\n");
2066 This->render_targets[0] = NULL;
2068 if (This->auto_depth_stencil_buffer) {
2069 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
2071 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2073 This->auto_depth_stencil_buffer = NULL;
2076 for(i=0; i < This->NumberOfSwapChains; i++) {
2077 TRACE("Releasing the implicit swapchain %d\n", i);
2078 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2079 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2083 HeapFree(GetProcessHeap(), 0, This->swapchains);
2084 This->swapchains = NULL;
2085 This->NumberOfSwapChains = 0;
2087 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2088 HeapFree(GetProcessHeap(), 0, This->palettes);
2089 This->palettes = NULL;
2090 This->NumberOfPalettes = 0;
2092 HeapFree(GetProcessHeap(), 0, This->render_targets);
2093 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2094 This->render_targets = NULL;
2095 This->draw_buffers = NULL;
2097 This->d3d_initialized = FALSE;
2098 return WINED3D_OK;
2101 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2103 unsigned int i;
2105 for(i=0; i < This->NumberOfSwapChains; i++) {
2106 TRACE("Releasing the implicit swapchain %d\n", i);
2107 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2108 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2112 HeapFree(GetProcessHeap(), 0, This->swapchains);
2113 This->swapchains = NULL;
2114 This->NumberOfSwapChains = 0;
2115 return WINED3D_OK;
2118 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2119 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2120 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2122 * There is no way to deactivate thread safety once it is enabled.
2124 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2127 /*For now just store the flag(needed in case of ddraw) */
2128 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2130 return;
2133 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2134 const WINED3DDISPLAYMODE* pMode) {
2135 DEVMODEW devmode;
2136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2137 LONG ret;
2138 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2139 RECT clip_rc;
2141 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2143 /* Resize the screen even without a window:
2144 * The app could have unset it with SetCooperativeLevel, but not called
2145 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2146 * but we don't have any hwnd
2149 memset(&devmode, 0, sizeof(devmode));
2150 devmode.dmSize = sizeof(devmode);
2151 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2152 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2153 devmode.dmPelsWidth = pMode->Width;
2154 devmode.dmPelsHeight = pMode->Height;
2156 devmode.dmDisplayFrequency = pMode->RefreshRate;
2157 if (pMode->RefreshRate != 0) {
2158 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2161 /* Only change the mode if necessary */
2162 if( (This->ddraw_width == pMode->Width) &&
2163 (This->ddraw_height == pMode->Height) &&
2164 (This->ddraw_format == pMode->Format) &&
2165 (pMode->RefreshRate == 0) ) {
2166 return WINED3D_OK;
2169 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2170 if (ret != DISP_CHANGE_SUCCESSFUL) {
2171 if(devmode.dmDisplayFrequency != 0) {
2172 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2173 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2174 devmode.dmDisplayFrequency = 0;
2175 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2177 if(ret != DISP_CHANGE_SUCCESSFUL) {
2178 return WINED3DERR_NOTAVAILABLE;
2182 /* Store the new values */
2183 This->ddraw_width = pMode->Width;
2184 This->ddraw_height = pMode->Height;
2185 This->ddraw_format = pMode->Format;
2187 /* And finally clip mouse to our screen */
2188 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2189 ClipCursor(&clip_rc);
2191 return WINED3D_OK;
2194 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2195 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2196 *ppD3D= This->wineD3D;
2197 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2198 IWineD3D_AddRef(*ppD3D);
2199 return WINED3D_OK;
2202 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2205 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2206 (This->adapter->TextureRam/(1024*1024)),
2207 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2208 /* return simulated texture memory left */
2209 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2212 /*****
2213 * Get / Set Stream Source
2214 *****/
2215 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2216 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2218 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2219 IWineD3DBuffer *oldSrc;
2221 if (StreamNumber >= MAX_STREAMS) {
2222 WARN("Stream out of range %d\n", StreamNumber);
2223 return WINED3DERR_INVALIDCALL;
2224 } else if(OffsetInBytes & 0x3) {
2225 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2226 return WINED3DERR_INVALIDCALL;
2229 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2230 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2232 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2234 if(oldSrc == pStreamData &&
2235 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2236 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2237 TRACE("Application is setting the old values over, nothing to do\n");
2238 return WINED3D_OK;
2241 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2242 if (pStreamData) {
2243 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2244 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2247 /* Handle recording of state blocks */
2248 if (This->isRecordingState) {
2249 TRACE("Recording... not performing anything\n");
2250 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2251 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2252 return WINED3D_OK;
2255 if (pStreamData != NULL) {
2256 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2257 IWineD3DBuffer_AddRef(pStreamData);
2259 if (oldSrc != NULL) {
2260 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2261 IWineD3DBuffer_Release(oldSrc);
2264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2266 return WINED3D_OK;
2269 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2270 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2274 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2275 This->stateBlock->streamSource[StreamNumber],
2276 This->stateBlock->streamOffset[StreamNumber],
2277 This->stateBlock->streamStride[StreamNumber]);
2279 if (StreamNumber >= MAX_STREAMS) {
2280 WARN("Stream out of range %d\n", StreamNumber);
2281 return WINED3DERR_INVALIDCALL;
2283 *pStream = This->stateBlock->streamSource[StreamNumber];
2284 *pStride = This->stateBlock->streamStride[StreamNumber];
2285 if (pOffset) {
2286 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2289 if (*pStream != NULL) {
2290 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2292 return WINED3D_OK;
2295 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2297 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2298 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2300 /* Verify input at least in d3d9 this is invalid*/
2301 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2302 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2303 return WINED3DERR_INVALIDCALL;
2305 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2306 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2307 return WINED3DERR_INVALIDCALL;
2309 if( Divider == 0 ){
2310 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2311 return WINED3DERR_INVALIDCALL;
2314 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2315 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2317 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2318 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2320 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2321 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2322 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2325 return WINED3D_OK;
2328 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2331 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2332 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2334 TRACE("(%p) : returning %d\n", This, *Divider);
2336 return WINED3D_OK;
2339 /*****
2340 * Get / Set & Multiply Transform
2341 *****/
2342 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2345 /* Most of this routine, comments included copied from ddraw tree initially: */
2346 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2348 /* Handle recording of state blocks */
2349 if (This->isRecordingState) {
2350 TRACE("Recording... not performing anything\n");
2351 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2352 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2353 return WINED3D_OK;
2357 * If the new matrix is the same as the current one,
2358 * we cut off any further processing. this seems to be a reasonable
2359 * optimization because as was noticed, some apps (warcraft3 for example)
2360 * tend towards setting the same matrix repeatedly for some reason.
2362 * From here on we assume that the new matrix is different, wherever it matters.
2364 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2365 TRACE("The app is setting the same matrix over again\n");
2366 return WINED3D_OK;
2367 } else {
2368 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2372 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2373 where ViewMat = Camera space, WorldMat = world space.
2375 In OpenGL, camera and world space is combined into GL_MODELVIEW
2376 matrix. The Projection matrix stay projection matrix.
2379 /* Capture the times we can just ignore the change for now */
2380 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2381 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2382 /* Handled by the state manager */
2385 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2386 return WINED3D_OK;
2389 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2391 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2392 *pMatrix = This->stateBlock->transforms[State];
2393 return WINED3D_OK;
2396 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2397 const WINED3DMATRIX *mat = NULL;
2398 WINED3DMATRIX temp;
2400 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2401 * below means it will be recorded in a state block change, but it
2402 * works regardless where it is recorded.
2403 * If this is found to be wrong, change to StateBlock.
2405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2406 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2408 if (State <= HIGHEST_TRANSFORMSTATE)
2410 mat = &This->updateStateBlock->transforms[State];
2411 } else {
2412 FIXME("Unhandled transform state!!\n");
2415 multiply_matrix(&temp, mat, pMatrix);
2417 /* Apply change via set transform - will reapply to eg. lights this way */
2418 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2421 /*****
2422 * Get / Set Light
2423 *****/
2424 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2425 you can reference any indexes you want as long as that number max are enabled at any
2426 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2427 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2428 but when recording, just build a chain pretty much of commands to be replayed. */
2430 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2431 float rho;
2432 struct wined3d_light_info *object = NULL;
2433 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2434 struct list *e;
2436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2437 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2439 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2440 * the gl driver.
2442 if(!pLight) {
2443 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2444 return WINED3DERR_INVALIDCALL;
2447 switch(pLight->Type) {
2448 case WINED3DLIGHT_POINT:
2449 case WINED3DLIGHT_SPOT:
2450 case WINED3DLIGHT_PARALLELPOINT:
2451 case WINED3DLIGHT_GLSPOT:
2452 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2453 * most wanted
2455 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2457 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2458 return WINED3DERR_INVALIDCALL;
2460 break;
2462 case WINED3DLIGHT_DIRECTIONAL:
2463 /* Ignores attenuation */
2464 break;
2466 default:
2467 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2468 return WINED3DERR_INVALIDCALL;
2471 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2473 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2474 if(object->OriginalIndex == Index) break;
2475 object = NULL;
2478 if(!object) {
2479 TRACE("Adding new light\n");
2480 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2481 if(!object) {
2482 ERR("Out of memory error when allocating a light\n");
2483 return E_OUTOFMEMORY;
2485 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2486 object->glIndex = -1;
2487 object->OriginalIndex = Index;
2490 /* Initialize the object */
2491 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,
2492 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2493 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2494 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2495 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2496 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2497 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2499 /* Save away the information */
2500 object->OriginalParms = *pLight;
2502 switch (pLight->Type) {
2503 case WINED3DLIGHT_POINT:
2504 /* Position */
2505 object->lightPosn[0] = pLight->Position.x;
2506 object->lightPosn[1] = pLight->Position.y;
2507 object->lightPosn[2] = pLight->Position.z;
2508 object->lightPosn[3] = 1.0f;
2509 object->cutoff = 180.0f;
2510 /* FIXME: Range */
2511 break;
2513 case WINED3DLIGHT_DIRECTIONAL:
2514 /* Direction */
2515 object->lightPosn[0] = -pLight->Direction.x;
2516 object->lightPosn[1] = -pLight->Direction.y;
2517 object->lightPosn[2] = -pLight->Direction.z;
2518 object->lightPosn[3] = 0.0f;
2519 object->exponent = 0.0f;
2520 object->cutoff = 180.0f;
2521 break;
2523 case WINED3DLIGHT_SPOT:
2524 /* Position */
2525 object->lightPosn[0] = pLight->Position.x;
2526 object->lightPosn[1] = pLight->Position.y;
2527 object->lightPosn[2] = pLight->Position.z;
2528 object->lightPosn[3] = 1.0f;
2530 /* Direction */
2531 object->lightDirn[0] = pLight->Direction.x;
2532 object->lightDirn[1] = pLight->Direction.y;
2533 object->lightDirn[2] = pLight->Direction.z;
2534 object->lightDirn[3] = 1.0f;
2537 * opengl-ish and d3d-ish spot lights use too different models for the
2538 * light "intensity" as a function of the angle towards the main light direction,
2539 * so we only can approximate very roughly.
2540 * however spot lights are rather rarely used in games (if ever used at all).
2541 * furthermore if still used, probably nobody pays attention to such details.
2543 if (pLight->Falloff == 0) {
2544 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2545 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2546 * will always be 1.0 for both of them, and we don't have to care for the
2547 * rest of the rather complex calculation
2549 object->exponent = 0.0f;
2550 } else {
2551 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2552 if (rho < 0.0001f) rho = 0.0001f;
2553 object->exponent = -0.3f/logf(cosf(rho/2));
2555 if (object->exponent > 128.0f)
2557 object->exponent = 128.0f;
2559 object->cutoff = pLight->Phi*90/M_PI;
2561 /* FIXME: Range */
2562 break;
2564 default:
2565 FIXME("Unrecognized light type %d\n", pLight->Type);
2568 /* Update the live definitions if the light is currently assigned a glIndex */
2569 if (object->glIndex != -1 && !This->isRecordingState) {
2570 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2572 return WINED3D_OK;
2575 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2577 struct wined3d_light_info *lightInfo = NULL;
2578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2579 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2580 struct list *e;
2581 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2583 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2585 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2586 if(lightInfo->OriginalIndex == Index) break;
2587 lightInfo = NULL;
2590 if (lightInfo == NULL) {
2591 TRACE("Light information requested but light not defined\n");
2592 return WINED3DERR_INVALIDCALL;
2595 *pLight = lightInfo->OriginalParms;
2596 return WINED3D_OK;
2599 /*****
2600 * Get / Set Light Enable
2601 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2602 *****/
2603 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2605 struct wined3d_light_info *lightInfo = NULL;
2606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2607 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2608 struct list *e;
2609 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2611 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2613 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2614 if(lightInfo->OriginalIndex == Index) break;
2615 lightInfo = NULL;
2617 TRACE("Found light: %p\n", lightInfo);
2619 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2620 if (lightInfo == NULL) {
2622 TRACE("Light enabled requested but light not defined, so defining one!\n");
2623 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2625 /* Search for it again! Should be fairly quick as near head of list */
2626 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2628 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2629 if(lightInfo->OriginalIndex == Index) break;
2630 lightInfo = NULL;
2632 if (lightInfo == NULL) {
2633 FIXME("Adding default lights has failed dismally\n");
2634 return WINED3DERR_INVALIDCALL;
2638 if(!Enable) {
2639 if(lightInfo->glIndex != -1) {
2640 if(!This->isRecordingState) {
2641 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2644 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2645 lightInfo->glIndex = -1;
2646 } else {
2647 TRACE("Light already disabled, nothing to do\n");
2649 lightInfo->enabled = FALSE;
2650 } else {
2651 lightInfo->enabled = TRUE;
2652 if (lightInfo->glIndex != -1) {
2653 /* nop */
2654 TRACE("Nothing to do as light was enabled\n");
2655 } else {
2656 int i;
2657 /* Find a free gl light */
2658 for(i = 0; i < This->maxConcurrentLights; i++) {
2659 if(This->updateStateBlock->activeLights[i] == NULL) {
2660 This->updateStateBlock->activeLights[i] = lightInfo;
2661 lightInfo->glIndex = i;
2662 break;
2665 if(lightInfo->glIndex == -1) {
2666 /* Our tests show that Windows returns D3D_OK in this situation, even with
2667 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2668 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2669 * as well for those lights.
2671 * TODO: Test how this affects rendering
2673 WARN("Too many concurrently active lights\n");
2674 return WINED3D_OK;
2677 /* i == lightInfo->glIndex */
2678 if(!This->isRecordingState) {
2679 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2684 return WINED3D_OK;
2687 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2689 struct wined3d_light_info *lightInfo = NULL;
2690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2691 struct list *e;
2692 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2693 TRACE("(%p) : for idx(%d)\n", This, Index);
2695 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2697 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2698 if(lightInfo->OriginalIndex == Index) break;
2699 lightInfo = NULL;
2702 if (lightInfo == NULL) {
2703 TRACE("Light enabled state requested but light not defined\n");
2704 return WINED3DERR_INVALIDCALL;
2706 /* true is 128 according to SetLightEnable */
2707 *pEnable = lightInfo->enabled ? 128 : 0;
2708 return WINED3D_OK;
2711 /*****
2712 * Get / Set Clip Planes
2713 *****/
2714 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2716 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2718 /* Validate Index */
2719 if (Index >= GL_LIMITS(clipplanes)) {
2720 TRACE("Application has requested clipplane this device doesn't support\n");
2721 return WINED3DERR_INVALIDCALL;
2724 This->updateStateBlock->changed.clipplane |= 1 << Index;
2726 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2727 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2728 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2729 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2730 TRACE("Application is setting old values over, nothing to do\n");
2731 return WINED3D_OK;
2734 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2735 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2736 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2737 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2739 /* Handle recording of state blocks */
2740 if (This->isRecordingState) {
2741 TRACE("Recording... not performing anything\n");
2742 return WINED3D_OK;
2745 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2747 return WINED3D_OK;
2750 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2752 TRACE("(%p) : for idx %d\n", This, Index);
2754 /* Validate Index */
2755 if (Index >= GL_LIMITS(clipplanes)) {
2756 TRACE("Application has requested clipplane this device doesn't support\n");
2757 return WINED3DERR_INVALIDCALL;
2760 pPlane[0] = This->stateBlock->clipplane[Index][0];
2761 pPlane[1] = This->stateBlock->clipplane[Index][1];
2762 pPlane[2] = This->stateBlock->clipplane[Index][2];
2763 pPlane[3] = This->stateBlock->clipplane[Index][3];
2764 return WINED3D_OK;
2767 /*****
2768 * Get / Set Clip Plane Status
2769 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2770 *****/
2771 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2773 FIXME("(%p) : stub\n", This);
2774 if (NULL == pClipStatus) {
2775 return WINED3DERR_INVALIDCALL;
2777 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2778 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2779 return WINED3D_OK;
2782 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2784 FIXME("(%p) : stub\n", This);
2785 if (NULL == pClipStatus) {
2786 return WINED3DERR_INVALIDCALL;
2788 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2789 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2790 return WINED3D_OK;
2793 /*****
2794 * Get / Set Material
2795 *****/
2796 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2799 This->updateStateBlock->changed.material = TRUE;
2800 This->updateStateBlock->material = *pMaterial;
2802 /* Handle recording of state blocks */
2803 if (This->isRecordingState) {
2804 TRACE("Recording... not performing anything\n");
2805 return WINED3D_OK;
2808 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2809 return WINED3D_OK;
2812 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2813 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2814 *pMaterial = This->updateStateBlock->material;
2815 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2816 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2817 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2818 pMaterial->Ambient.b, pMaterial->Ambient.a);
2819 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2820 pMaterial->Specular.b, pMaterial->Specular.a);
2821 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2822 pMaterial->Emissive.b, pMaterial->Emissive.a);
2823 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2825 return WINED3D_OK;
2828 /*****
2829 * Get / Set Indices
2830 *****/
2831 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2832 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2835 IWineD3DBuffer *oldIdxs;
2837 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2838 oldIdxs = This->updateStateBlock->pIndexData;
2840 This->updateStateBlock->changed.indices = TRUE;
2841 This->updateStateBlock->pIndexData = pIndexData;
2842 This->updateStateBlock->IndexFmt = fmt;
2844 /* Handle recording of state blocks */
2845 if (This->isRecordingState) {
2846 TRACE("Recording... not performing anything\n");
2847 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2848 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2849 return WINED3D_OK;
2852 if(oldIdxs != pIndexData) {
2853 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2854 if(pIndexData) {
2855 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2856 IWineD3DBuffer_AddRef(pIndexData);
2858 if(oldIdxs) {
2859 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2860 IWineD3DBuffer_Release(oldIdxs);
2864 return WINED3D_OK;
2867 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2871 *ppIndexData = This->stateBlock->pIndexData;
2873 /* up ref count on ppindexdata */
2874 if (*ppIndexData) {
2875 IWineD3DBuffer_AddRef(*ppIndexData);
2876 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2877 }else{
2878 TRACE("(%p) No index data set\n", This);
2880 TRACE("Returning %p\n", *ppIndexData);
2882 return WINED3D_OK;
2885 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2886 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2888 TRACE("(%p)->(%d)\n", This, BaseIndex);
2890 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2891 TRACE("Application is setting the old value over, nothing to do\n");
2892 return WINED3D_OK;
2895 This->updateStateBlock->baseVertexIndex = BaseIndex;
2897 if (This->isRecordingState) {
2898 TRACE("Recording... not performing anything\n");
2899 return WINED3D_OK;
2901 /* The base vertex index affects the stream sources */
2902 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2903 return WINED3D_OK;
2906 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2907 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2908 TRACE("(%p) : base_index %p\n", This, base_index);
2910 *base_index = This->stateBlock->baseVertexIndex;
2912 TRACE("Returning %u\n", *base_index);
2914 return WINED3D_OK;
2917 /*****
2918 * Get / Set Viewports
2919 *****/
2920 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2923 TRACE("(%p)\n", This);
2924 This->updateStateBlock->changed.viewport = TRUE;
2925 This->updateStateBlock->viewport = *pViewport;
2927 /* Handle recording of state blocks */
2928 if (This->isRecordingState) {
2929 TRACE("Recording... not performing anything\n");
2930 return WINED3D_OK;
2933 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2934 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2936 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2937 return WINED3D_OK;
2941 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2943 TRACE("(%p)\n", This);
2944 *pViewport = This->stateBlock->viewport;
2945 return WINED3D_OK;
2948 /*****
2949 * Get / Set Render States
2950 * TODO: Verify against dx9 definitions
2951 *****/
2952 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2954 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2955 DWORD oldValue = This->stateBlock->renderState[State];
2957 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2959 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2960 This->updateStateBlock->renderState[State] = Value;
2962 /* Handle recording of state blocks */
2963 if (This->isRecordingState) {
2964 TRACE("Recording... not performing anything\n");
2965 return WINED3D_OK;
2968 /* Compared here and not before the assignment to allow proper stateblock recording */
2969 if(Value == oldValue) {
2970 TRACE("Application is setting the old value over, nothing to do\n");
2971 } else {
2972 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2975 return WINED3D_OK;
2978 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2980 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2981 *pValue = This->stateBlock->renderState[State];
2982 return WINED3D_OK;
2985 /*****
2986 * Get / Set Sampler States
2987 * TODO: Verify against dx9 definitions
2988 *****/
2990 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2992 DWORD oldValue;
2994 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2995 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2997 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2998 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3001 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3002 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3003 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3006 * SetSampler is designed to allow for more than the standard up to 8 textures
3007 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3008 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3010 * http://developer.nvidia.com/object/General_FAQ.html#t6
3012 * There are two new settings for GForce
3013 * the sampler one:
3014 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3015 * and the texture one:
3016 * GL_MAX_TEXTURE_COORDS_ARB.
3017 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3018 ******************/
3020 oldValue = This->stateBlock->samplerState[Sampler][Type];
3021 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3022 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3024 /* Handle recording of state blocks */
3025 if (This->isRecordingState) {
3026 TRACE("Recording... not performing anything\n");
3027 return WINED3D_OK;
3030 if(oldValue == Value) {
3031 TRACE("Application is setting the old value over, nothing to do\n");
3032 return WINED3D_OK;
3035 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3037 return WINED3D_OK;
3040 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3043 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3044 This, Sampler, debug_d3dsamplerstate(Type), Type);
3046 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3047 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3050 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3051 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3052 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3054 *Value = This->stateBlock->samplerState[Sampler][Type];
3055 TRACE("(%p) : Returning %#x\n", This, *Value);
3057 return WINED3D_OK;
3060 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3063 This->updateStateBlock->changed.scissorRect = TRUE;
3064 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3065 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3066 return WINED3D_OK;
3068 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3070 if(This->isRecordingState) {
3071 TRACE("Recording... not performing anything\n");
3072 return WINED3D_OK;
3075 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3077 return WINED3D_OK;
3080 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3083 *pRect = This->updateStateBlock->scissorRect;
3084 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3085 return WINED3D_OK;
3088 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3090 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3092 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3094 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3095 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3097 This->updateStateBlock->vertexDecl = pDecl;
3098 This->updateStateBlock->changed.vertexDecl = TRUE;
3100 if (This->isRecordingState) {
3101 TRACE("Recording... not performing anything\n");
3102 return WINED3D_OK;
3103 } else if(pDecl == oldDecl) {
3104 /* Checked after the assignment to allow proper stateblock recording */
3105 TRACE("Application is setting the old declaration over, nothing to do\n");
3106 return WINED3D_OK;
3109 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3110 return WINED3D_OK;
3113 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3114 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3116 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3118 *ppDecl = This->stateBlock->vertexDecl;
3119 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3120 return WINED3D_OK;
3123 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3125 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3127 This->updateStateBlock->vertexShader = pShader;
3128 This->updateStateBlock->changed.vertexShader = TRUE;
3130 if (This->isRecordingState) {
3131 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3132 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3133 TRACE("Recording... not performing anything\n");
3134 return WINED3D_OK;
3135 } else if(oldShader == pShader) {
3136 /* Checked here to allow proper stateblock recording */
3137 TRACE("App is setting the old shader over, nothing to do\n");
3138 return WINED3D_OK;
3141 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3142 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3143 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3145 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3147 return WINED3D_OK;
3150 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3153 if (NULL == ppShader) {
3154 return WINED3DERR_INVALIDCALL;
3156 *ppShader = This->stateBlock->vertexShader;
3157 if( NULL != *ppShader)
3158 IWineD3DVertexShader_AddRef(*ppShader);
3160 TRACE("(%p) : returning %p\n", This, *ppShader);
3161 return WINED3D_OK;
3164 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3165 IWineD3DDevice *iface,
3166 UINT start,
3167 CONST BOOL *srcData,
3168 UINT count) {
3170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3171 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3173 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3174 iface, srcData, start, count);
3176 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3178 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3179 for (i = 0; i < cnt; i++)
3180 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3182 for (i = start; i < cnt + start; ++i) {
3183 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3186 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3188 return WINED3D_OK;
3191 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3192 IWineD3DDevice *iface,
3193 UINT start,
3194 BOOL *dstData,
3195 UINT count) {
3197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3198 int cnt = min(count, MAX_CONST_B - start);
3200 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3201 iface, dstData, start, count);
3203 if (dstData == NULL || cnt < 0)
3204 return WINED3DERR_INVALIDCALL;
3206 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3207 return WINED3D_OK;
3210 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3211 IWineD3DDevice *iface,
3212 UINT start,
3213 CONST int *srcData,
3214 UINT count) {
3216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3217 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3219 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3220 iface, srcData, start, count);
3222 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3224 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3225 for (i = 0; i < cnt; i++)
3226 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3227 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3229 for (i = start; i < cnt + start; ++i) {
3230 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3233 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3235 return WINED3D_OK;
3238 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3239 IWineD3DDevice *iface,
3240 UINT start,
3241 int *dstData,
3242 UINT count) {
3244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3245 int cnt = min(count, MAX_CONST_I - start);
3247 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3248 iface, dstData, start, count);
3250 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3251 return WINED3DERR_INVALIDCALL;
3253 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3254 return WINED3D_OK;
3257 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3258 IWineD3DDevice *iface,
3259 UINT start,
3260 CONST float *srcData,
3261 UINT count) {
3263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3264 UINT i;
3266 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3267 iface, srcData, start, count);
3269 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3270 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3271 return WINED3DERR_INVALIDCALL;
3273 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3274 if(TRACE_ON(d3d)) {
3275 for (i = 0; i < count; i++)
3276 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3277 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3280 if (!This->isRecordingState)
3282 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3283 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3286 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3287 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3289 return WINED3D_OK;
3292 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3293 IWineD3DDevice *iface,
3294 UINT start,
3295 float *dstData,
3296 UINT count) {
3298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3299 int cnt = min(count, This->d3d_vshader_constantF - start);
3301 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3302 iface, dstData, start, count);
3304 if (dstData == NULL || cnt < 0)
3305 return WINED3DERR_INVALIDCALL;
3307 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3308 return WINED3D_OK;
3311 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3312 DWORD i;
3313 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3315 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3319 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3321 DWORD i = This->rev_tex_unit_map[unit];
3322 DWORD j = This->texUnitMap[stage];
3324 This->texUnitMap[stage] = unit;
3325 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3327 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3330 This->rev_tex_unit_map[unit] = stage;
3331 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3333 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3337 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3338 int i;
3340 This->fixed_function_usage_map = 0;
3341 for (i = 0; i < MAX_TEXTURES; ++i) {
3342 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3343 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3344 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3345 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3346 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3347 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3348 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3349 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3351 if (color_op == WINED3DTOP_DISABLE) {
3352 /* Not used, and disable higher stages */
3353 break;
3356 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3357 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3358 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3359 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3360 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3361 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3362 This->fixed_function_usage_map |= (1 << i);
3365 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3366 This->fixed_function_usage_map |= (1 << (i + 1));
3371 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3372 unsigned int i, tex;
3373 WORD ffu_map;
3375 device_update_fixed_function_usage_map(This);
3376 ffu_map = This->fixed_function_usage_map;
3378 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3379 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3380 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3382 if (!(ffu_map & 1)) continue;
3384 if (This->texUnitMap[i] != i) {
3385 device_map_stage(This, i, i);
3386 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3387 markTextureStagesDirty(This, i);
3390 return;
3393 /* Now work out the mapping */
3394 tex = 0;
3395 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3397 if (!(ffu_map & 1)) continue;
3399 if (This->texUnitMap[i] != tex) {
3400 device_map_stage(This, i, tex);
3401 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3402 markTextureStagesDirty(This, i);
3405 ++tex;
3409 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3410 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3411 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3412 unsigned int i;
3414 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3415 if (sampler_type[i] && This->texUnitMap[i] != i)
3417 device_map_stage(This, i, i);
3418 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3419 if (i < MAX_TEXTURES) {
3420 markTextureStagesDirty(This, i);
3426 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3427 const DWORD *vshader_sampler_tokens, DWORD unit)
3429 DWORD current_mapping = This->rev_tex_unit_map[unit];
3431 /* Not currently used */
3432 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3434 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3435 /* Used by a fragment sampler */
3437 if (!pshader_sampler_tokens) {
3438 /* No pixel shader, check fixed function */
3439 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3442 /* Pixel shader, check the shader's sampler map */
3443 return !pshader_sampler_tokens[current_mapping];
3446 /* Used by a vertex sampler */
3447 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3450 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3451 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3452 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3453 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3454 int start = min(MAX_COMBINED_SAMPLERS, GL_LIMITS(combined_samplers)) - 1;
3455 int i;
3457 if (ps) {
3458 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3460 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3461 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3462 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3465 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3466 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3467 if (vshader_sampler_type[i])
3469 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3471 /* Already mapped somewhere */
3472 continue;
3475 while (start >= 0) {
3476 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3478 device_map_stage(This, vsampler_idx, start);
3479 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3481 --start;
3482 break;
3485 --start;
3491 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3492 BOOL vs = use_vs(This->stateBlock);
3493 BOOL ps = use_ps(This->stateBlock);
3495 * Rules are:
3496 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3497 * that would be really messy and require shader recompilation
3498 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3499 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3501 if (ps) {
3502 device_map_psamplers(This);
3503 } else {
3504 device_map_fixed_function_samplers(This);
3507 if (vs) {
3508 device_map_vsamplers(This, ps);
3512 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3514 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3515 This->updateStateBlock->pixelShader = pShader;
3516 This->updateStateBlock->changed.pixelShader = TRUE;
3518 /* Handle recording of state blocks */
3519 if (This->isRecordingState) {
3520 TRACE("Recording... not performing anything\n");
3523 if (This->isRecordingState) {
3524 TRACE("Recording... not performing anything\n");
3525 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3526 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3527 return WINED3D_OK;
3530 if(pShader == oldShader) {
3531 TRACE("App is setting the old pixel shader over, nothing to do\n");
3532 return WINED3D_OK;
3535 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3536 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3538 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3539 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3541 return WINED3D_OK;
3544 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3547 if (NULL == ppShader) {
3548 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3549 return WINED3DERR_INVALIDCALL;
3552 *ppShader = This->stateBlock->pixelShader;
3553 if (NULL != *ppShader) {
3554 IWineD3DPixelShader_AddRef(*ppShader);
3556 TRACE("(%p) : returning %p\n", This, *ppShader);
3557 return WINED3D_OK;
3560 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3561 IWineD3DDevice *iface,
3562 UINT start,
3563 CONST BOOL *srcData,
3564 UINT count) {
3566 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3567 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3569 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3570 iface, srcData, start, count);
3572 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3574 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3575 for (i = 0; i < cnt; i++)
3576 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3578 for (i = start; i < cnt + start; ++i) {
3579 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3582 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3584 return WINED3D_OK;
3587 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3588 IWineD3DDevice *iface,
3589 UINT start,
3590 BOOL *dstData,
3591 UINT count) {
3593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3594 int cnt = min(count, MAX_CONST_B - start);
3596 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3597 iface, dstData, start, count);
3599 if (dstData == NULL || cnt < 0)
3600 return WINED3DERR_INVALIDCALL;
3602 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3603 return WINED3D_OK;
3606 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3607 IWineD3DDevice *iface,
3608 UINT start,
3609 CONST int *srcData,
3610 UINT count) {
3612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3613 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3615 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3616 iface, srcData, start, count);
3618 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3620 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3621 for (i = 0; i < cnt; i++)
3622 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3623 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3625 for (i = start; i < cnt + start; ++i) {
3626 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3629 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3631 return WINED3D_OK;
3634 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3635 IWineD3DDevice *iface,
3636 UINT start,
3637 int *dstData,
3638 UINT count) {
3640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3641 int cnt = min(count, MAX_CONST_I - start);
3643 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3644 iface, dstData, start, count);
3646 if (dstData == NULL || cnt < 0)
3647 return WINED3DERR_INVALIDCALL;
3649 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3650 return WINED3D_OK;
3653 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3654 IWineD3DDevice *iface,
3655 UINT start,
3656 CONST float *srcData,
3657 UINT count) {
3659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3660 UINT i;
3662 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3663 iface, srcData, start, count);
3665 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3666 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3667 return WINED3DERR_INVALIDCALL;
3669 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3670 if(TRACE_ON(d3d)) {
3671 for (i = 0; i < count; i++)
3672 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3673 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3676 if (!This->isRecordingState)
3678 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3679 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3682 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3683 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3685 return WINED3D_OK;
3688 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3689 IWineD3DDevice *iface,
3690 UINT start,
3691 float *dstData,
3692 UINT count) {
3694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3695 int cnt = min(count, This->d3d_pshader_constantF - start);
3697 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3698 iface, dstData, start, count);
3700 if (dstData == NULL || cnt < 0)
3701 return WINED3DERR_INVALIDCALL;
3703 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3704 return WINED3D_OK;
3707 /* Context activation is done by the caller. */
3708 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3709 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3710 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3711 DWORD DestFVF)
3713 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3714 unsigned int i;
3715 WINED3DVIEWPORT vp;
3716 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3717 BOOL doClip;
3718 DWORD numTextures;
3720 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3722 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3725 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3727 ERR("Source has no position mask\n");
3728 return WINED3DERR_INVALIDCALL;
3731 /* We might access VBOs from this code, so hold the lock */
3732 ENTER_GL();
3734 if (dest->resource.allocatedMemory == NULL) {
3735 buffer_get_sysmem(dest);
3738 /* Get a pointer into the destination vbo(create one if none exists) and
3739 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3741 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
3743 dest->flags |= WINED3D_BUFFER_CREATEBO;
3744 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3747 if (dest->buffer_object)
3749 unsigned char extrabytes = 0;
3750 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3751 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3752 * this may write 4 extra bytes beyond the area that should be written
3754 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3755 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3756 if(!dest_conv_addr) {
3757 ERR("Out of memory\n");
3758 /* Continue without storing converted vertices */
3760 dest_conv = dest_conv_addr;
3763 /* Should I clip?
3764 * a) WINED3DRS_CLIPPING is enabled
3765 * b) WINED3DVOP_CLIP is passed
3767 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3768 static BOOL warned = FALSE;
3770 * The clipping code is not quite correct. Some things need
3771 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3772 * so disable clipping for now.
3773 * (The graphics in Half-Life are broken, and my processvertices
3774 * test crashes with IDirect3DDevice3)
3775 doClip = TRUE;
3777 doClip = FALSE;
3778 if(!warned) {
3779 warned = TRUE;
3780 FIXME("Clipping is broken and disabled for now\n");
3782 } else doClip = FALSE;
3783 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3785 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3786 WINED3DTS_VIEW,
3787 &view_mat);
3788 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3789 WINED3DTS_PROJECTION,
3790 &proj_mat);
3791 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3792 WINED3DTS_WORLDMATRIX(0),
3793 &world_mat);
3795 TRACE("View mat:\n");
3796 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);
3797 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);
3798 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);
3799 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);
3801 TRACE("Proj mat:\n");
3802 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);
3803 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);
3804 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);
3805 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);
3807 TRACE("World mat:\n");
3808 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);
3809 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);
3810 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);
3811 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);
3813 /* Get the viewport */
3814 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3815 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3816 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3818 multiply_matrix(&mat,&view_mat,&world_mat);
3819 multiply_matrix(&mat,&proj_mat,&mat);
3821 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3823 for (i = 0; i < dwCount; i+= 1) {
3824 unsigned int tex_index;
3826 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3827 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3828 /* The position first */
3829 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3830 const float *p = (const float *)(element->data + i * element->stride);
3831 float x, y, z, rhw;
3832 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3834 /* Multiplication with world, view and projection matrix */
3835 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);
3836 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);
3837 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);
3838 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);
3840 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3842 /* WARNING: The following things are taken from d3d7 and were not yet checked
3843 * against d3d8 or d3d9!
3846 /* Clipping conditions: From msdn
3848 * A vertex is clipped if it does not match the following requirements
3849 * -rhw < x <= rhw
3850 * -rhw < y <= rhw
3851 * 0 < z <= rhw
3852 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3854 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3855 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3859 if( !doClip ||
3860 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3861 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3862 ( rhw > eps ) ) ) {
3864 /* "Normal" viewport transformation (not clipped)
3865 * 1) The values are divided by rhw
3866 * 2) The y axis is negative, so multiply it with -1
3867 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3868 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3869 * 4) Multiply x with Width/2 and add Width/2
3870 * 5) The same for the height
3871 * 6) Add the viewpoint X and Y to the 2D coordinates and
3872 * The minimum Z value to z
3873 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3875 * Well, basically it's simply a linear transformation into viewport
3876 * coordinates
3879 x /= rhw;
3880 y /= rhw;
3881 z /= rhw;
3883 y *= -1;
3885 x *= vp.Width / 2;
3886 y *= vp.Height / 2;
3887 z *= vp.MaxZ - vp.MinZ;
3889 x += vp.Width / 2 + vp.X;
3890 y += vp.Height / 2 + vp.Y;
3891 z += vp.MinZ;
3893 rhw = 1 / rhw;
3894 } else {
3895 /* That vertex got clipped
3896 * Contrary to OpenGL it is not dropped completely, it just
3897 * undergoes a different calculation.
3899 TRACE("Vertex got clipped\n");
3900 x += rhw;
3901 y += rhw;
3903 x /= 2;
3904 y /= 2;
3906 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3907 * outside of the main vertex buffer memory. That needs some more
3908 * investigation...
3912 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3915 ( (float *) dest_ptr)[0] = x;
3916 ( (float *) dest_ptr)[1] = y;
3917 ( (float *) dest_ptr)[2] = z;
3918 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3920 dest_ptr += 3 * sizeof(float);
3922 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3923 dest_ptr += sizeof(float);
3926 if(dest_conv) {
3927 float w = 1 / rhw;
3928 ( (float *) dest_conv)[0] = x * w;
3929 ( (float *) dest_conv)[1] = y * w;
3930 ( (float *) dest_conv)[2] = z * w;
3931 ( (float *) dest_conv)[3] = w;
3933 dest_conv += 3 * sizeof(float);
3935 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3936 dest_conv += sizeof(float);
3940 if (DestFVF & WINED3DFVF_PSIZE) {
3941 dest_ptr += sizeof(DWORD);
3942 if(dest_conv) dest_conv += sizeof(DWORD);
3944 if (DestFVF & WINED3DFVF_NORMAL) {
3945 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3946 const float *normal = (const float *)(element->data + i * element->stride);
3947 /* AFAIK this should go into the lighting information */
3948 FIXME("Didn't expect the destination to have a normal\n");
3949 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3950 if(dest_conv) {
3951 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3955 if (DestFVF & WINED3DFVF_DIFFUSE) {
3956 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3957 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3958 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3960 static BOOL warned = FALSE;
3962 if(!warned) {
3963 ERR("No diffuse color in source, but destination has one\n");
3964 warned = TRUE;
3967 *( (DWORD *) dest_ptr) = 0xffffffff;
3968 dest_ptr += sizeof(DWORD);
3970 if(dest_conv) {
3971 *( (DWORD *) dest_conv) = 0xffffffff;
3972 dest_conv += sizeof(DWORD);
3975 else {
3976 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3977 if(dest_conv) {
3978 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3979 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3980 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3981 dest_conv += sizeof(DWORD);
3986 if (DestFVF & WINED3DFVF_SPECULAR)
3988 /* What's the color value in the feedback buffer? */
3989 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3990 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3991 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3993 static BOOL warned = FALSE;
3995 if(!warned) {
3996 ERR("No specular color in source, but destination has one\n");
3997 warned = TRUE;
4000 *( (DWORD *) dest_ptr) = 0xFF000000;
4001 dest_ptr += sizeof(DWORD);
4003 if(dest_conv) {
4004 *( (DWORD *) dest_conv) = 0xFF000000;
4005 dest_conv += sizeof(DWORD);
4008 else {
4009 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4010 if(dest_conv) {
4011 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4012 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4013 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4014 dest_conv += sizeof(DWORD);
4019 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4020 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4021 const float *tex_coord = (const float *)(element->data + i * element->stride);
4022 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4024 ERR("No source texture, but destination requests one\n");
4025 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4026 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4028 else {
4029 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4030 if(dest_conv) {
4031 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4037 if(dest_conv) {
4038 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4039 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4040 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4041 dwCount * get_flexible_vertex_size(DestFVF),
4042 dest_conv_addr));
4043 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4044 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4047 LEAVE_GL();
4049 return WINED3D_OK;
4051 #undef copy_and_next
4053 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4054 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4055 DWORD DestFVF)
4057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4058 struct wined3d_stream_info stream_info;
4059 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4060 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4062 if(pVertexDecl) {
4063 ERR("Output vertex declaration not implemented yet\n");
4066 /* Need any context to write to the vbo. */
4067 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4069 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4070 * control the streamIsUP flag, thus restore it afterwards.
4072 This->stateBlock->streamIsUP = FALSE;
4073 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4074 This->stateBlock->streamIsUP = streamWasUP;
4076 if(vbo || SrcStartIndex) {
4077 unsigned int i;
4078 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4079 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4081 * Also get the start index in, but only loop over all elements if there's something to add at all.
4083 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4085 struct wined3d_stream_info_element *e;
4087 if (!(stream_info.use_map & (1 << i))) continue;
4089 e = &stream_info.elements[i];
4090 if (e->buffer_object)
4092 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4093 e->buffer_object = 0;
4094 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4095 ENTER_GL();
4096 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4097 vb->buffer_object = 0;
4098 LEAVE_GL();
4100 if (e->data) e->data += e->stride * SrcStartIndex;
4104 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4105 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4108 /*****
4109 * Get / Set Texture Stage States
4110 * TODO: Verify against dx9 definitions
4111 *****/
4112 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4114 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4116 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4118 if (Stage >= MAX_TEXTURES) {
4119 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4120 return WINED3D_OK;
4123 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4124 This->updateStateBlock->textureState[Stage][Type] = Value;
4126 if (This->isRecordingState) {
4127 TRACE("Recording... not performing anything\n");
4128 return WINED3D_OK;
4131 /* Checked after the assignments to allow proper stateblock recording */
4132 if(oldValue == Value) {
4133 TRACE("App is setting the old value over, nothing to do\n");
4134 return WINED3D_OK;
4137 if(Stage > This->stateBlock->lowest_disabled_stage &&
4138 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4139 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4140 * Changes in other states are important on disabled stages too
4142 return WINED3D_OK;
4145 if(Type == WINED3DTSS_COLOROP) {
4146 unsigned int i;
4148 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4149 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4150 * they have to be disabled
4152 * The current stage is dirtified below.
4154 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4155 TRACE("Additionally dirtifying stage %u\n", i);
4156 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4158 This->stateBlock->lowest_disabled_stage = Stage;
4159 TRACE("New lowest disabled: %u\n", Stage);
4160 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4161 /* Previously disabled stage enabled. Stages above it may need enabling
4162 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4163 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4165 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4168 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4169 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4170 break;
4172 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4173 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4175 This->stateBlock->lowest_disabled_stage = i;
4176 TRACE("New lowest disabled: %u\n", i);
4180 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4182 return WINED3D_OK;
4185 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4187 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4188 *pValue = This->updateStateBlock->textureState[Stage][Type];
4189 return WINED3D_OK;
4192 /*****
4193 * Get / Set Texture
4194 *****/
4195 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4196 DWORD stage, IWineD3DBaseTexture *texture)
4198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4199 IWineD3DBaseTexture *prev;
4201 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4203 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4204 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4206 /* Windows accepts overflowing this array... we do not. */
4207 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4209 WARN("Ignoring invalid stage %u.\n", stage);
4210 return WINED3D_OK;
4213 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4214 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4216 WARN("Rejecting attempt to set scratch texture.\n");
4217 return WINED3DERR_INVALIDCALL;
4220 This->updateStateBlock->changed.textures |= 1 << stage;
4222 prev = This->updateStateBlock->textures[stage];
4223 TRACE("Previous texture %p.\n", prev);
4225 if (texture == prev)
4227 TRACE("App is setting the same texture again, nothing to do.\n");
4228 return WINED3D_OK;
4231 TRACE("Setting new texture to %p.\n", texture);
4232 This->updateStateBlock->textures[stage] = texture;
4234 if (This->isRecordingState)
4236 TRACE("Recording... not performing anything\n");
4238 if (texture) IWineD3DBaseTexture_AddRef(texture);
4239 if (prev) IWineD3DBaseTexture_Release(prev);
4241 return WINED3D_OK;
4244 if (texture)
4246 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4247 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4248 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4250 IWineD3DBaseTexture_AddRef(texture);
4252 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4254 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4257 if (!prev && stage < MAX_TEXTURES)
4259 /* The source arguments for color and alpha ops have different
4260 * meanings when a NULL texture is bound, so the COLOROP and
4261 * ALPHAOP have to be dirtified. */
4262 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4263 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4266 if (bind_count == 1) t->baseTexture.sampler = stage;
4269 if (prev)
4271 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4272 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4274 IWineD3DBaseTexture_Release(prev);
4276 if (!texture && stage < MAX_TEXTURES)
4278 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4279 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4282 if (bind_count && t->baseTexture.sampler == stage)
4284 unsigned int i;
4286 /* Search for other stages the texture is bound to. Shouldn't
4287 * happen if applications bind textures to a single stage only. */
4288 TRACE("Searching for other stages the texture is bound to.\n");
4289 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4291 if (This->updateStateBlock->textures[i] == prev)
4293 TRACE("Texture is also bound to stage %u.\n", i);
4294 t->baseTexture.sampler = i;
4295 break;
4301 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4303 return WINED3D_OK;
4306 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4309 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4311 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4312 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4315 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4316 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4317 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4320 *ppTexture=This->stateBlock->textures[Stage];
4321 if (*ppTexture)
4322 IWineD3DBaseTexture_AddRef(*ppTexture);
4324 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4326 return WINED3D_OK;
4329 /*****
4330 * Get Back Buffer
4331 *****/
4332 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4333 IWineD3DSurface **ppBackBuffer) {
4334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4335 IWineD3DSwapChain *swapChain;
4336 HRESULT hr;
4338 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4340 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4341 if (hr == WINED3D_OK) {
4342 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4343 IWineD3DSwapChain_Release(swapChain);
4344 } else {
4345 *ppBackBuffer = NULL;
4347 return hr;
4350 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4352 WARN("(%p) : stub, calling idirect3d for now\n", This);
4353 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4356 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4358 IWineD3DSwapChain *swapChain;
4359 HRESULT hr;
4361 if(iSwapChain > 0) {
4362 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4363 if (hr == WINED3D_OK) {
4364 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4365 IWineD3DSwapChain_Release(swapChain);
4366 } else {
4367 FIXME("(%p) Error getting display mode\n", This);
4369 } else {
4370 /* Don't read the real display mode,
4371 but return the stored mode instead. X11 can't change the color
4372 depth, and some apps are pretty angry if they SetDisplayMode from
4373 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4375 Also don't relay to the swapchain because with ddraw it's possible
4376 that there isn't a swapchain at all */
4377 pMode->Width = This->ddraw_width;
4378 pMode->Height = This->ddraw_height;
4379 pMode->Format = This->ddraw_format;
4380 pMode->RefreshRate = 0;
4381 hr = WINED3D_OK;
4384 return hr;
4387 /*****
4388 * Stateblock related functions
4389 *****/
4391 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4393 IWineD3DStateBlock *stateblock;
4394 HRESULT hr;
4396 TRACE("(%p)\n", This);
4398 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4400 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4401 if (FAILED(hr)) return hr;
4403 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4404 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4405 This->isRecordingState = TRUE;
4407 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4409 return WINED3D_OK;
4412 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4414 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4416 if (!This->isRecordingState) {
4417 WARN("(%p) not recording! returning error\n", This);
4418 *ppStateBlock = NULL;
4419 return WINED3DERR_INVALIDCALL;
4422 stateblock_init_contained_states(object);
4424 *ppStateBlock = (IWineD3DStateBlock*) object;
4425 This->isRecordingState = FALSE;
4426 This->updateStateBlock = This->stateBlock;
4427 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4428 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4429 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4430 return WINED3D_OK;
4433 /*****
4434 * Scene related functions
4435 *****/
4436 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4437 /* At the moment we have no need for any functionality at the beginning
4438 of a scene */
4439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4440 TRACE("(%p)\n", This);
4442 if(This->inScene) {
4443 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4444 return WINED3DERR_INVALIDCALL;
4446 This->inScene = TRUE;
4447 return WINED3D_OK;
4450 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4452 TRACE("(%p)\n", This);
4454 if(!This->inScene) {
4455 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4456 return WINED3DERR_INVALIDCALL;
4459 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4460 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4461 wglFlush();
4462 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4463 * fails
4466 This->inScene = FALSE;
4467 return WINED3D_OK;
4470 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4471 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4472 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4474 IWineD3DSwapChain *swapChain = NULL;
4475 int i;
4476 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4478 TRACE("(%p) Presenting the frame\n", This);
4480 for(i = 0 ; i < swapchains ; i ++) {
4482 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4483 TRACE("presentinng chain %d, %p\n", i, swapChain);
4484 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4485 IWineD3DSwapChain_Release(swapChain);
4488 return WINED3D_OK;
4491 /* Not called from the VTable (internal subroutine) */
4492 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4493 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4494 float Z, DWORD Stencil) {
4495 GLbitfield glMask = 0;
4496 unsigned int i;
4497 WINED3DRECT curRect;
4498 RECT vp_rect;
4499 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4500 UINT drawable_width, drawable_height;
4501 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4502 IWineD3DSwapChainImpl *swapchain = NULL;
4503 struct wined3d_context *context;
4505 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4506 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4507 * for the cleared parts, and the untouched parts.
4509 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4510 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4511 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4512 * checking all this if the dest surface is in the drawable anyway.
4514 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4515 while(1) {
4516 if(vp->X != 0 || vp->Y != 0 ||
4517 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4518 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4519 break;
4521 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4522 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4523 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4524 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4525 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4526 break;
4528 if(Count > 0 && pRects && (
4529 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4530 pRects[0].x2 < target->currentDesc.Width ||
4531 pRects[0].y2 < target->currentDesc.Height)) {
4532 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4533 break;
4535 break;
4539 context = ActivateContext(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4541 target->get_drawable_size(context, &drawable_width, &drawable_height);
4543 ENTER_GL();
4545 /* Only set the values up once, as they are not changing */
4546 if (Flags & WINED3DCLEAR_STENCIL) {
4547 glClearStencil(Stencil);
4548 checkGLcall("glClearStencil");
4549 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4550 glStencilMask(0xFFFFFFFF);
4553 if (Flags & WINED3DCLEAR_ZBUFFER) {
4554 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4555 glDepthMask(GL_TRUE);
4556 glClearDepth(Z);
4557 checkGLcall("glClearDepth");
4558 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4559 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4561 if (vp->X != 0 || vp->Y != 0 ||
4562 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4563 surface_load_ds_location(This->stencilBufferTarget, context, location);
4565 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4566 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4567 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4568 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4569 surface_load_ds_location(This->stencilBufferTarget, context, location);
4571 else if (Count > 0 && pRects && (
4572 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4573 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4574 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4575 surface_load_ds_location(This->stencilBufferTarget, context, location);
4579 if (Flags & WINED3DCLEAR_TARGET) {
4580 TRACE("Clearing screen with glClear to color %x\n", Color);
4581 glClearColor(D3DCOLOR_R(Color),
4582 D3DCOLOR_G(Color),
4583 D3DCOLOR_B(Color),
4584 D3DCOLOR_A(Color));
4585 checkGLcall("glClearColor");
4587 /* Clear ALL colors! */
4588 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4589 glMask = glMask | GL_COLOR_BUFFER_BIT;
4592 vp_rect.left = vp->X;
4593 vp_rect.top = vp->Y;
4594 vp_rect.right = vp->X + vp->Width;
4595 vp_rect.bottom = vp->Y + vp->Height;
4596 if (!(Count > 0 && pRects)) {
4597 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4598 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4600 if (context->render_offscreen)
4602 glScissor(vp_rect.left, vp_rect.top,
4603 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4604 } else {
4605 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4606 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4608 checkGLcall("glScissor");
4609 glClear(glMask);
4610 checkGLcall("glClear");
4611 } else {
4612 /* Now process each rect in turn */
4613 for (i = 0; i < Count; i++) {
4614 /* Note gl uses lower left, width/height */
4615 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4616 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4617 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4619 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4620 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4621 curRect.x1, (target->currentDesc.Height - curRect.y2),
4622 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4624 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4625 * The rectangle is not cleared, no error is returned, but further rectanlges are
4626 * still cleared if they are valid
4628 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4629 TRACE("Rectangle with negative dimensions, ignoring\n");
4630 continue;
4633 if (context->render_offscreen)
4635 glScissor(curRect.x1, curRect.y1,
4636 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4637 } else {
4638 glScissor(curRect.x1, drawable_height - curRect.y2,
4639 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4641 checkGLcall("glScissor");
4643 glClear(glMask);
4644 checkGLcall("glClear");
4648 /* Restore the old values (why..?) */
4649 if (Flags & WINED3DCLEAR_STENCIL) {
4650 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4652 if (Flags & WINED3DCLEAR_TARGET) {
4653 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4654 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4655 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4656 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4657 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4659 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4660 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4662 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4664 if (Flags & WINED3DCLEAR_ZBUFFER) {
4665 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4666 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4667 surface_modify_ds_location(This->stencilBufferTarget, location);
4670 LEAVE_GL();
4672 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
4673 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
4674 wglFlush();
4676 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
4679 return WINED3D_OK;
4682 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4683 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4685 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4687 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4688 Count, pRects, Flags, Color, Z, Stencil);
4690 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4691 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4692 /* TODO: What about depth stencil buffers without stencil bits? */
4693 return WINED3DERR_INVALIDCALL;
4696 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4699 /*****
4700 * Drawing functions
4701 *****/
4703 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4704 WINED3DPRIMITIVETYPE primitive_type)
4706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4708 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4710 This->updateStateBlock->changed.primitive_type = TRUE;
4711 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4714 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4715 WINED3DPRIMITIVETYPE *primitive_type)
4717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4719 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4721 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4723 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4726 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4730 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4732 if(!This->stateBlock->vertexDecl) {
4733 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4734 return WINED3DERR_INVALIDCALL;
4737 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4738 if(This->stateBlock->streamIsUP) {
4739 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4740 This->stateBlock->streamIsUP = FALSE;
4743 if(This->stateBlock->loadBaseVertexIndex != 0) {
4744 This->stateBlock->loadBaseVertexIndex = 0;
4745 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4747 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4748 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4749 return WINED3D_OK;
4752 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4755 UINT idxStride = 2;
4756 IWineD3DBuffer *pIB;
4757 GLuint vbo;
4759 pIB = This->stateBlock->pIndexData;
4760 if (!pIB) {
4761 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4762 * without an index buffer set. (The first time at least...)
4763 * D3D8 simply dies, but I doubt it can do much harm to return
4764 * D3DERR_INVALIDCALL there as well. */
4765 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4766 return WINED3DERR_INVALIDCALL;
4769 if(!This->stateBlock->vertexDecl) {
4770 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4771 return WINED3DERR_INVALIDCALL;
4774 if(This->stateBlock->streamIsUP) {
4775 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4776 This->stateBlock->streamIsUP = FALSE;
4778 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4780 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4782 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4783 idxStride = 2;
4784 } else {
4785 idxStride = 4;
4788 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4789 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4790 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4793 drawPrimitive(iface, index_count, startIndex, idxStride,
4794 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4796 return WINED3D_OK;
4799 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4800 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4803 IWineD3DBuffer *vb;
4805 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4806 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4808 if(!This->stateBlock->vertexDecl) {
4809 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4810 return WINED3DERR_INVALIDCALL;
4813 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4814 vb = This->stateBlock->streamSource[0];
4815 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4816 if (vb) IWineD3DBuffer_Release(vb);
4817 This->stateBlock->streamOffset[0] = 0;
4818 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4819 This->stateBlock->streamIsUP = TRUE;
4820 This->stateBlock->loadBaseVertexIndex = 0;
4822 /* TODO: Only mark dirty if drawing from a different UP address */
4823 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4825 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4827 /* MSDN specifies stream zero settings must be set to NULL */
4828 This->stateBlock->streamStride[0] = 0;
4829 This->stateBlock->streamSource[0] = NULL;
4831 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4832 * the new stream sources or use UP drawing again
4834 return WINED3D_OK;
4837 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4838 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4839 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4841 int idxStride;
4842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4843 IWineD3DBuffer *vb;
4844 IWineD3DBuffer *ib;
4846 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4847 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4849 if(!This->stateBlock->vertexDecl) {
4850 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4851 return WINED3DERR_INVALIDCALL;
4854 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4855 idxStride = 2;
4856 } else {
4857 idxStride = 4;
4860 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4861 vb = This->stateBlock->streamSource[0];
4862 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4863 if (vb) IWineD3DBuffer_Release(vb);
4864 This->stateBlock->streamIsUP = TRUE;
4865 This->stateBlock->streamOffset[0] = 0;
4866 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4868 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4869 This->stateBlock->baseVertexIndex = 0;
4870 This->stateBlock->loadBaseVertexIndex = 0;
4871 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4872 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4873 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4875 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4877 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4878 This->stateBlock->streamSource[0] = NULL;
4879 This->stateBlock->streamStride[0] = 0;
4880 ib = This->stateBlock->pIndexData;
4881 if(ib) {
4882 IWineD3DBuffer_Release(ib);
4883 This->stateBlock->pIndexData = NULL;
4885 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4886 * SetStreamSource to specify a vertex buffer
4889 return WINED3D_OK;
4892 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4893 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4897 /* Mark the state dirty until we have nicer tracking
4898 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4899 * that value.
4901 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4902 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4903 This->stateBlock->baseVertexIndex = 0;
4904 This->up_strided = DrawPrimStrideData;
4905 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4906 This->up_strided = NULL;
4907 return WINED3D_OK;
4910 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4911 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4912 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4915 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4917 /* Mark the state dirty until we have nicer tracking
4918 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4919 * that value.
4921 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4922 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4923 This->stateBlock->streamIsUP = TRUE;
4924 This->stateBlock->baseVertexIndex = 0;
4925 This->up_strided = DrawPrimStrideData;
4926 drawPrimitive(iface, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData);
4927 This->up_strided = NULL;
4928 return WINED3D_OK;
4931 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
4932 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
4933 * not callable by the app directly no parameter validation checks are needed here.
4935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4936 WINED3DLOCKED_BOX src;
4937 WINED3DLOCKED_BOX dst;
4938 HRESULT hr;
4939 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
4941 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4942 * dirtification to improve loading performance.
4944 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4945 if(FAILED(hr)) return hr;
4946 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4947 if(FAILED(hr)) {
4948 IWineD3DVolume_UnlockBox(pSourceVolume);
4949 return hr;
4952 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4954 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4955 if(FAILED(hr)) {
4956 IWineD3DVolume_UnlockBox(pSourceVolume);
4957 } else {
4958 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4960 return hr;
4963 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4964 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4966 HRESULT hr = WINED3D_OK;
4967 WINED3DRESOURCETYPE sourceType;
4968 WINED3DRESOURCETYPE destinationType;
4969 int i ,levels;
4971 /* TODO: think about moving the code into IWineD3DBaseTexture */
4973 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4975 /* verify that the source and destination textures aren't NULL */
4976 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4977 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4978 This, pSourceTexture, pDestinationTexture);
4979 hr = WINED3DERR_INVALIDCALL;
4982 if (pSourceTexture == pDestinationTexture) {
4983 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4984 This, pSourceTexture, pDestinationTexture);
4985 hr = WINED3DERR_INVALIDCALL;
4987 /* Verify that the source and destination textures are the same type */
4988 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4989 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4991 if (sourceType != destinationType) {
4992 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4993 This);
4994 hr = WINED3DERR_INVALIDCALL;
4997 /* check that both textures have the identical numbers of levels */
4998 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4999 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5000 hr = WINED3DERR_INVALIDCALL;
5003 if (WINED3D_OK == hr) {
5004 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5006 /* Make sure that the destination texture is loaded */
5007 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5009 /* Update every surface level of the texture */
5010 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5012 switch (sourceType) {
5013 case WINED3DRTYPE_TEXTURE:
5015 IWineD3DSurface *srcSurface;
5016 IWineD3DSurface *destSurface;
5018 for (i = 0 ; i < levels ; ++i) {
5019 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5020 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5021 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5022 IWineD3DSurface_Release(srcSurface);
5023 IWineD3DSurface_Release(destSurface);
5024 if (WINED3D_OK != hr) {
5025 WARN("(%p) : Call to update surface failed\n", This);
5026 return hr;
5030 break;
5031 case WINED3DRTYPE_CUBETEXTURE:
5033 IWineD3DSurface *srcSurface;
5034 IWineD3DSurface *destSurface;
5035 WINED3DCUBEMAP_FACES faceType;
5037 for (i = 0 ; i < levels ; ++i) {
5038 /* Update each cube face */
5039 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5040 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5041 if (WINED3D_OK != hr) {
5042 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5043 } else {
5044 TRACE("Got srcSurface %p\n", srcSurface);
5046 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5047 if (WINED3D_OK != hr) {
5048 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5049 } else {
5050 TRACE("Got desrSurface %p\n", destSurface);
5052 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5053 IWineD3DSurface_Release(srcSurface);
5054 IWineD3DSurface_Release(destSurface);
5055 if (WINED3D_OK != hr) {
5056 WARN("(%p) : Call to update surface failed\n", This);
5057 return hr;
5062 break;
5064 case WINED3DRTYPE_VOLUMETEXTURE:
5066 IWineD3DVolume *srcVolume = NULL;
5067 IWineD3DVolume *destVolume = NULL;
5069 for (i = 0 ; i < levels ; ++i) {
5070 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5071 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5072 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5073 IWineD3DVolume_Release(srcVolume);
5074 IWineD3DVolume_Release(destVolume);
5075 if (WINED3D_OK != hr) {
5076 WARN("(%p) : Call to update volume failed\n", This);
5077 return hr;
5081 break;
5083 default:
5084 FIXME("(%p) : Unsupported source and destination type\n", This);
5085 hr = WINED3DERR_INVALIDCALL;
5089 return hr;
5092 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5093 IWineD3DSwapChain *swapChain;
5094 HRESULT hr;
5095 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5096 if(hr == WINED3D_OK) {
5097 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5098 IWineD3DSwapChain_Release(swapChain);
5100 return hr;
5103 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5105 IWineD3DBaseTextureImpl *texture;
5106 DWORD i;
5108 TRACE("(%p) : %p\n", This, pNumPasses);
5110 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5111 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5112 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5113 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5115 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5116 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5117 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5120 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5121 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5123 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5124 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5125 return E_FAIL;
5127 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5128 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5129 return E_FAIL;
5131 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5132 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5133 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5134 return E_FAIL;
5138 /* return a sensible default */
5139 *pNumPasses = 1;
5141 TRACE("returning D3D_OK\n");
5142 return WINED3D_OK;
5145 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5147 int i;
5149 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5151 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5152 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
5153 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
5155 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5160 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5162 int j;
5163 UINT NewSize;
5164 PALETTEENTRY **palettes;
5166 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5168 if (PaletteNumber >= MAX_PALETTES) {
5169 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5170 return WINED3DERR_INVALIDCALL;
5173 if (PaletteNumber >= This->NumberOfPalettes) {
5174 NewSize = This->NumberOfPalettes;
5175 do {
5176 NewSize *= 2;
5177 } while(PaletteNumber >= NewSize);
5178 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5179 if (!palettes) {
5180 ERR("Out of memory!\n");
5181 return E_OUTOFMEMORY;
5183 This->palettes = palettes;
5184 This->NumberOfPalettes = NewSize;
5187 if (!This->palettes[PaletteNumber]) {
5188 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5189 if (!This->palettes[PaletteNumber]) {
5190 ERR("Out of memory!\n");
5191 return E_OUTOFMEMORY;
5195 for (j = 0; j < 256; ++j) {
5196 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5197 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5198 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5199 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5201 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5202 TRACE("(%p) : returning\n", This);
5203 return WINED3D_OK;
5206 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5208 int j;
5209 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5210 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5211 /* What happens in such situation isn't documented; Native seems to silently abort
5212 on such conditions. Return Invalid Call. */
5213 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5214 return WINED3DERR_INVALIDCALL;
5216 for (j = 0; j < 256; ++j) {
5217 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5218 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5219 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5220 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5222 TRACE("(%p) : returning\n", This);
5223 return WINED3D_OK;
5226 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5228 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5229 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5230 (tested with reference rasterizer). Return Invalid Call. */
5231 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5232 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5233 return WINED3DERR_INVALIDCALL;
5235 /*TODO: stateblocks */
5236 if (This->currentPalette != PaletteNumber) {
5237 This->currentPalette = PaletteNumber;
5238 dirtify_p8_texture_samplers(This);
5240 TRACE("(%p) : returning\n", This);
5241 return WINED3D_OK;
5244 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5246 if (PaletteNumber == NULL) {
5247 WARN("(%p) : returning Invalid Call\n", This);
5248 return WINED3DERR_INVALIDCALL;
5250 /*TODO: stateblocks */
5251 *PaletteNumber = This->currentPalette;
5252 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5253 return WINED3D_OK;
5256 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5258 static BOOL warned;
5259 if (!warned)
5261 FIXME("(%p) : stub\n", This);
5262 warned = TRUE;
5265 This->softwareVertexProcessing = bSoftware;
5266 return WINED3D_OK;
5270 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5272 static BOOL warned;
5273 if (!warned)
5275 FIXME("(%p) : stub\n", This);
5276 warned = TRUE;
5278 return This->softwareVertexProcessing;
5282 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5284 IWineD3DSwapChain *swapChain;
5285 HRESULT hr;
5287 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5289 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5290 if(hr == WINED3D_OK){
5291 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5292 IWineD3DSwapChain_Release(swapChain);
5293 }else{
5294 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5296 return hr;
5300 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5302 static BOOL warned;
5303 if(nSegments != 0.0f) {
5304 if (!warned)
5306 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5307 warned = TRUE;
5310 return WINED3D_OK;
5313 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5315 static BOOL warned;
5316 if (!warned)
5318 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5319 warned = TRUE;
5321 return 0.0f;
5324 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5326 /** TODO: remove casts to IWineD3DSurfaceImpl
5327 * NOTE: move code to surface to accomplish this
5328 ****************************************/
5329 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5330 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5331 int srcWidth, srcHeight;
5332 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5333 WINED3DFORMAT destFormat, srcFormat;
5334 UINT destSize;
5335 int srcLeft, destLeft, destTop;
5336 WINED3DPOOL srcPool, destPool;
5337 int offset = 0;
5338 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5339 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5340 GLenum dummy;
5341 DWORD sampler;
5342 int bpp;
5343 CONVERT_TYPES convert = NO_CONVERSION;
5345 WINED3DSURFACE_DESC winedesc;
5347 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5349 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5350 srcSurfaceWidth = winedesc.width;
5351 srcSurfaceHeight = winedesc.height;
5352 srcPool = winedesc.pool;
5353 srcFormat = winedesc.format;
5355 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5356 destSurfaceWidth = winedesc.width;
5357 destSurfaceHeight = winedesc.height;
5358 destPool = winedesc.pool;
5359 destFormat = winedesc.format;
5360 destSize = winedesc.size;
5362 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5363 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5364 return WINED3DERR_INVALIDCALL;
5367 /* This call loads the opengl surface directly, instead of copying the surface to the
5368 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5369 * copy in sysmem and use regular surface loading.
5371 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5372 if(convert != NO_CONVERSION) {
5373 return IWineD3DSurface_BltFast(pDestinationSurface,
5374 pDestPoint ? pDestPoint->x : 0,
5375 pDestPoint ? pDestPoint->y : 0,
5376 pSourceSurface, pSourceRect, 0);
5379 if (destFormat == WINED3DFMT_UNKNOWN) {
5380 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5381 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5383 /* Get the update surface description */
5384 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5387 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
5389 ENTER_GL();
5390 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5391 checkGLcall("glActiveTextureARB");
5392 LEAVE_GL();
5394 /* Make sure the surface is loaded and up to date */
5395 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5396 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5398 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5399 dst_format_desc = dst_impl->resource.format_desc;
5401 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5402 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5403 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5404 srcLeft = pSourceRect ? pSourceRect->left : 0;
5405 destLeft = pDestPoint ? pDestPoint->x : 0;
5406 destTop = pDestPoint ? pDestPoint->y : 0;
5409 /* This function doesn't support compressed textures
5410 the pitch is just bytesPerPixel * width */
5411 if(srcWidth != srcSurfaceWidth || srcLeft ){
5412 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5413 offset += srcLeft * src_format_desc->byte_count;
5414 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5416 /* TODO DXT formats */
5418 if(pSourceRect != NULL && pSourceRect->top != 0){
5419 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5421 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5422 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5423 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5425 /* Sanity check */
5426 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5428 /* need to lock the surface to get the data */
5429 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5432 ENTER_GL();
5434 /* TODO: Cube and volume support */
5435 if(rowoffset != 0){
5436 /* not a whole row so we have to do it a line at a time */
5437 int j;
5439 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5440 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5442 for (j = destTop; j < (srcHeight + destTop); ++j)
5444 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5445 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5446 data += rowoffset;
5449 } else { /* Full width, so just write out the whole texture */
5450 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5452 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5454 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5456 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5457 FIXME("Updating part of a compressed texture is not supported.\n");
5459 if (destFormat != srcFormat)
5461 FIXME("Updating mixed format compressed textures is not supported.\n");
5463 else
5465 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5466 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5469 else
5471 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5472 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5475 checkGLcall("glTexSubImage2D");
5477 LEAVE_GL();
5479 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5480 sampler = This->rev_tex_unit_map[0];
5481 if (sampler != WINED3D_UNMAPPED_STAGE)
5483 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5486 return WINED3D_OK;
5489 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5490 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5491 struct WineD3DRectPatch *patch;
5492 GLenum old_primitive_type;
5493 unsigned int i;
5494 struct list *e;
5495 BOOL found;
5496 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5498 if(!(Handle || pRectPatchInfo)) {
5499 /* TODO: Write a test for the return value, thus the FIXME */
5500 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5501 return WINED3DERR_INVALIDCALL;
5504 if(Handle) {
5505 i = PATCHMAP_HASHFUNC(Handle);
5506 found = FALSE;
5507 LIST_FOR_EACH(e, &This->patches[i]) {
5508 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5509 if(patch->Handle == Handle) {
5510 found = TRUE;
5511 break;
5515 if(!found) {
5516 TRACE("Patch does not exist. Creating a new one\n");
5517 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5518 patch->Handle = Handle;
5519 list_add_head(&This->patches[i], &patch->entry);
5520 } else {
5521 TRACE("Found existing patch %p\n", patch);
5523 } else {
5524 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5525 * attributes we have to tesselate, read back, and draw. This needs a patch
5526 * management structure instance. Create one.
5528 * A possible improvement is to check if a vertex shader is used, and if not directly
5529 * draw the patch.
5531 FIXME("Drawing an uncached patch. This is slow\n");
5532 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5535 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5536 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5537 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5538 HRESULT hr;
5539 TRACE("Tesselation density or patch info changed, retesselating\n");
5541 if(pRectPatchInfo) {
5542 patch->RectPatchInfo = *pRectPatchInfo;
5544 patch->numSegs[0] = pNumSegs[0];
5545 patch->numSegs[1] = pNumSegs[1];
5546 patch->numSegs[2] = pNumSegs[2];
5547 patch->numSegs[3] = pNumSegs[3];
5549 hr = tesselate_rectpatch(This, patch);
5550 if(FAILED(hr)) {
5551 WARN("Patch tesselation failed\n");
5553 /* Do not release the handle to store the params of the patch */
5554 if(!Handle) {
5555 HeapFree(GetProcessHeap(), 0, patch);
5557 return hr;
5561 This->currentPatch = patch;
5562 old_primitive_type = This->stateBlock->gl_primitive_type;
5563 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5564 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5565 This->stateBlock->gl_primitive_type = old_primitive_type;
5566 This->currentPatch = NULL;
5568 /* Destroy uncached patches */
5569 if(!Handle) {
5570 HeapFree(GetProcessHeap(), 0, patch->mem);
5571 HeapFree(GetProcessHeap(), 0, patch);
5573 return WINED3D_OK;
5576 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5578 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5579 FIXME("(%p) : Stub\n", This);
5580 return WINED3D_OK;
5583 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5585 int i;
5586 struct WineD3DRectPatch *patch;
5587 struct list *e;
5588 TRACE("(%p) Handle(%d)\n", This, Handle);
5590 i = PATCHMAP_HASHFUNC(Handle);
5591 LIST_FOR_EACH(e, &This->patches[i]) {
5592 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5593 if(patch->Handle == Handle) {
5594 TRACE("Deleting patch %p\n", patch);
5595 list_remove(&patch->entry);
5596 HeapFree(GetProcessHeap(), 0, patch->mem);
5597 HeapFree(GetProcessHeap(), 0, patch);
5598 return WINED3D_OK;
5602 /* TODO: Write a test for the return value */
5603 FIXME("Attempt to destroy nonexistent patch\n");
5604 return WINED3DERR_INVALIDCALL;
5607 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5608 HRESULT hr;
5609 IWineD3DSwapChain *swapchain;
5611 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5612 if (SUCCEEDED(hr)) {
5613 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5614 return swapchain;
5617 return NULL;
5620 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5621 const WINED3DRECT *rect, const float color[4])
5623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5624 struct wined3d_context *context;
5625 IWineD3DSwapChain *swapchain;
5627 swapchain = get_swapchain(surface);
5628 if (swapchain) {
5629 GLenum buffer;
5631 TRACE("Surface %p is onscreen\n", surface);
5633 context = ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
5634 ENTER_GL();
5635 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5636 buffer = surface_get_gl_buffer(surface, swapchain);
5637 glDrawBuffer(buffer);
5638 checkGLcall("glDrawBuffer()");
5639 } else {
5640 TRACE("Surface %p is offscreen\n", surface);
5642 context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
5643 ENTER_GL();
5644 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5645 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5646 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5649 if (rect) {
5650 glEnable(GL_SCISSOR_TEST);
5651 if(!swapchain) {
5652 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5653 } else {
5654 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5655 rect->x2 - rect->x1, rect->y2 - rect->y1);
5657 checkGLcall("glScissor");
5658 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5659 } else {
5660 glDisable(GL_SCISSOR_TEST);
5662 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5664 glDisable(GL_BLEND);
5665 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5667 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5668 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5670 glClearColor(color[0], color[1], color[2], color[3]);
5671 glClear(GL_COLOR_BUFFER_BIT);
5672 checkGLcall("glClear");
5674 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5675 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5676 glDrawBuffer(GL_BACK);
5677 checkGLcall("glDrawBuffer()");
5680 LEAVE_GL();
5683 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5684 unsigned int r, g, b, a;
5685 DWORD ret;
5687 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5688 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5689 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5690 return color;
5692 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5694 a = (color & 0xff000000) >> 24;
5695 r = (color & 0x00ff0000) >> 16;
5696 g = (color & 0x0000ff00) >> 8;
5697 b = (color & 0x000000ff) >> 0;
5699 switch(destfmt)
5701 case WINED3DFMT_B5G6R5_UNORM:
5702 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5703 r = (r * 32) / 256;
5704 g = (g * 64) / 256;
5705 b = (b * 32) / 256;
5706 ret = r << 11;
5707 ret |= g << 5;
5708 ret |= b;
5709 TRACE("Returning %08x\n", ret);
5710 return ret;
5712 case WINED3DFMT_B5G5R5X1_UNORM:
5713 case WINED3DFMT_B5G5R5A1_UNORM:
5714 a = (a * 2) / 256;
5715 r = (r * 32) / 256;
5716 g = (g * 32) / 256;
5717 b = (b * 32) / 256;
5718 ret = a << 15;
5719 ret |= r << 10;
5720 ret |= g << 5;
5721 ret |= b << 0;
5722 TRACE("Returning %08x\n", ret);
5723 return ret;
5725 case WINED3DFMT_A8_UNORM:
5726 TRACE("Returning %08x\n", a);
5727 return a;
5729 case WINED3DFMT_B4G4R4X4_UNORM:
5730 case WINED3DFMT_B4G4R4A4_UNORM:
5731 a = (a * 16) / 256;
5732 r = (r * 16) / 256;
5733 g = (g * 16) / 256;
5734 b = (b * 16) / 256;
5735 ret = a << 12;
5736 ret |= r << 8;
5737 ret |= g << 4;
5738 ret |= b << 0;
5739 TRACE("Returning %08x\n", ret);
5740 return ret;
5742 case WINED3DFMT_B2G3R3_UNORM:
5743 r = (r * 8) / 256;
5744 g = (g * 8) / 256;
5745 b = (b * 4) / 256;
5746 ret = r << 5;
5747 ret |= g << 2;
5748 ret |= b << 0;
5749 TRACE("Returning %08x\n", ret);
5750 return ret;
5752 case WINED3DFMT_R8G8B8X8_UNORM:
5753 case WINED3DFMT_R8G8B8A8_UNORM:
5754 ret = a << 24;
5755 ret |= b << 16;
5756 ret |= g << 8;
5757 ret |= r << 0;
5758 TRACE("Returning %08x\n", ret);
5759 return ret;
5761 case WINED3DFMT_B10G10R10A2_UNORM:
5762 a = (a * 4) / 256;
5763 r = (r * 1024) / 256;
5764 g = (g * 1024) / 256;
5765 b = (b * 1024) / 256;
5766 ret = a << 30;
5767 ret |= r << 20;
5768 ret |= g << 10;
5769 ret |= b << 0;
5770 TRACE("Returning %08x\n", ret);
5771 return ret;
5773 case WINED3DFMT_R10G10B10A2_UNORM:
5774 a = (a * 4) / 256;
5775 r = (r * 1024) / 256;
5776 g = (g * 1024) / 256;
5777 b = (b * 1024) / 256;
5778 ret = a << 30;
5779 ret |= b << 20;
5780 ret |= g << 10;
5781 ret |= r << 0;
5782 TRACE("Returning %08x\n", ret);
5783 return ret;
5785 default:
5786 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5787 return 0;
5791 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5793 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5794 WINEDDBLTFX BltFx;
5795 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5797 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5798 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5799 return WINED3DERR_INVALIDCALL;
5802 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5803 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5804 color_fill_fbo(iface, pSurface, pRect, c);
5805 return WINED3D_OK;
5806 } else {
5807 /* Just forward this to the DirectDraw blitting engine */
5808 memset(&BltFx, 0, sizeof(BltFx));
5809 BltFx.dwSize = sizeof(BltFx);
5810 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5811 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5812 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5816 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5817 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5819 IWineD3DResource *resource;
5820 IWineD3DSurface *surface;
5821 HRESULT hr;
5823 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5824 if (FAILED(hr))
5826 ERR("Failed to get resource, hr %#x\n", hr);
5827 return;
5830 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5832 FIXME("Only supported on surface resources\n");
5833 IWineD3DResource_Release(resource);
5834 return;
5837 surface = (IWineD3DSurface *)resource;
5839 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5841 color_fill_fbo(iface, surface, NULL, color);
5843 else
5845 WINEDDBLTFX BltFx;
5846 WINED3DCOLOR c;
5848 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5850 c = ((DWORD)(color[2] * 255.0f));
5851 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5852 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5853 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5855 /* Just forward this to the DirectDraw blitting engine */
5856 memset(&BltFx, 0, sizeof(BltFx));
5857 BltFx.dwSize = sizeof(BltFx);
5858 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5859 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5860 if (FAILED(hr))
5862 ERR("Blt failed, hr %#x\n", hr);
5866 IWineD3DResource_Release(resource);
5869 /* rendertarget and depth stencil functions */
5870 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5873 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5874 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5875 return WINED3DERR_INVALIDCALL;
5878 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5879 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5880 /* Note inc ref on returned surface */
5881 if(*ppRenderTarget != NULL)
5882 IWineD3DSurface_AddRef(*ppRenderTarget);
5883 return WINED3D_OK;
5886 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5888 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5889 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5890 IWineD3DSwapChainImpl *Swapchain;
5891 HRESULT hr;
5893 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5895 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5896 if(hr != WINED3D_OK) {
5897 ERR("Can't get the swapchain\n");
5898 return hr;
5901 /* Make sure to release the swapchain */
5902 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5904 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5905 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5906 return WINED3DERR_INVALIDCALL;
5908 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5909 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5910 return WINED3DERR_INVALIDCALL;
5913 if(Swapchain->frontBuffer != Front) {
5914 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5916 if(Swapchain->frontBuffer)
5918 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5919 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5921 Swapchain->frontBuffer = Front;
5923 if(Swapchain->frontBuffer) {
5924 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5925 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5929 if(Back && !Swapchain->backBuffer) {
5930 /* We need memory for the back buffer array - only one back buffer this way */
5931 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5932 if(!Swapchain->backBuffer) {
5933 ERR("Out of memory\n");
5934 return E_OUTOFMEMORY;
5938 if(Swapchain->backBuffer[0] != Back) {
5939 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5941 /* What to do about the context here in the case of multithreading? Not sure.
5942 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5944 WARN("No active context?\n");
5946 ENTER_GL();
5947 if(!Swapchain->backBuffer[0]) {
5948 /* GL was told to draw to the front buffer at creation,
5949 * undo that
5951 glDrawBuffer(GL_BACK);
5952 checkGLcall("glDrawBuffer(GL_BACK)");
5953 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5954 Swapchain->presentParms.BackBufferCount = 1;
5955 } else if (!Back) {
5956 /* That makes problems - disable for now */
5957 /* glDrawBuffer(GL_FRONT); */
5958 checkGLcall("glDrawBuffer(GL_FRONT)");
5959 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5960 Swapchain->presentParms.BackBufferCount = 0;
5962 LEAVE_GL();
5964 if(Swapchain->backBuffer[0])
5966 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5967 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5969 Swapchain->backBuffer[0] = Back;
5971 if(Swapchain->backBuffer[0]) {
5972 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5973 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
5974 } else {
5975 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5976 Swapchain->backBuffer = NULL;
5981 return WINED3D_OK;
5984 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5986 *ppZStencilSurface = This->stencilBufferTarget;
5987 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5989 if(*ppZStencilSurface != NULL) {
5990 /* Note inc ref on returned surface */
5991 IWineD3DSurface_AddRef(*ppZStencilSurface);
5992 return WINED3D_OK;
5993 } else {
5994 return WINED3DERR_NOTFOUND;
5998 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5999 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6001 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6002 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6003 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6004 const struct wined3d_gl_info *gl_info;
6005 struct wined3d_context *context;
6006 GLenum gl_filter;
6007 POINT offset = {0, 0};
6009 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6010 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6011 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6012 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6014 switch (filter) {
6015 case WINED3DTEXF_LINEAR:
6016 gl_filter = GL_LINEAR;
6017 break;
6019 default:
6020 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6021 case WINED3DTEXF_NONE:
6022 case WINED3DTEXF_POINT:
6023 gl_filter = GL_NEAREST;
6024 break;
6027 /* Attach src surface to src fbo */
6028 src_swapchain = get_swapchain(src_surface);
6029 dst_swapchain = get_swapchain(dst_surface);
6031 if (src_swapchain) context = ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6032 else if (dst_swapchain) context = ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6033 else context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6035 gl_info = context->gl_info;
6037 if (src_swapchain) {
6038 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6040 TRACE("Source surface %p is onscreen\n", src_surface);
6041 /* Make sure the drawable is up to date. In the offscreen case
6042 * attach_surface_fbo() implicitly takes care of this. */
6043 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6045 if(buffer == GL_FRONT) {
6046 RECT windowsize;
6047 UINT h;
6048 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6049 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6050 h = windowsize.bottom - windowsize.top;
6051 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6052 src_rect->y1 = offset.y + h - src_rect->y1;
6053 src_rect->y2 = offset.y + h - src_rect->y2;
6054 } else {
6055 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6056 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6059 ENTER_GL();
6060 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
6061 glReadBuffer(buffer);
6062 checkGLcall("glReadBuffer()");
6063 } else {
6064 TRACE("Source surface %p is offscreen\n", src_surface);
6065 ENTER_GL();
6066 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
6067 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
6068 glReadBuffer(GL_COLOR_ATTACHMENT0);
6069 checkGLcall("glReadBuffer()");
6070 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
6072 LEAVE_GL();
6074 /* Attach dst surface to dst fbo */
6075 if (dst_swapchain) {
6076 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6078 TRACE("Destination surface %p is onscreen\n", dst_surface);
6079 /* Make sure the drawable is up to date. In the offscreen case
6080 * attach_surface_fbo() implicitly takes care of this. */
6081 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6083 if(buffer == GL_FRONT) {
6084 RECT windowsize;
6085 UINT h;
6086 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6087 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6088 h = windowsize.bottom - windowsize.top;
6089 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6090 dst_rect->y1 = offset.y + h - dst_rect->y1;
6091 dst_rect->y2 = offset.y + h - dst_rect->y2;
6092 } else {
6093 /* Screen coords = window coords, surface height = window height */
6094 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6095 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6098 ENTER_GL();
6099 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
6100 glDrawBuffer(buffer);
6101 checkGLcall("glDrawBuffer()");
6102 } else {
6103 TRACE("Destination surface %p is offscreen\n", dst_surface);
6105 ENTER_GL();
6106 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
6107 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
6108 glDrawBuffer(GL_COLOR_ATTACHMENT0);
6109 checkGLcall("glDrawBuffer()");
6110 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
6112 glDisable(GL_SCISSOR_TEST);
6113 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6115 if (flip) {
6116 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6117 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
6118 checkGLcall("glBlitFramebuffer()");
6119 } else {
6120 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6121 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
6122 checkGLcall("glBlitFramebuffer()");
6125 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6127 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6128 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6129 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6130 glDrawBuffer(GL_BACK);
6131 checkGLcall("glDrawBuffer()");
6133 LEAVE_GL();
6136 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6138 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
6140 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6142 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6143 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6144 This, RenderTargetIndex, GL_LIMITS(buffers));
6145 return WINED3DERR_INVALIDCALL;
6148 /* MSDN says that null disables the render target
6149 but a device must always be associated with a render target
6150 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6152 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6153 FIXME("Trying to set render target 0 to NULL\n");
6154 return WINED3DERR_INVALIDCALL;
6156 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6157 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);
6158 return WINED3DERR_INVALIDCALL;
6161 /* If we are trying to set what we already have, don't bother */
6162 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6163 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6164 return WINED3D_OK;
6166 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6167 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6168 This->render_targets[RenderTargetIndex] = pRenderTarget;
6170 /* Render target 0 is special */
6171 if(RenderTargetIndex == 0 && dxVersion > 7) {
6172 /* Finally, reset the viewport and scissor rect as the MSDN states.
6173 * Tests show that stateblock recording is ignored, the change goes
6174 * directly into the primary stateblock.
6176 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6177 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6178 This->stateBlock->viewport.X = 0;
6179 This->stateBlock->viewport.Y = 0;
6180 This->stateBlock->viewport.MaxZ = 1.0f;
6181 This->stateBlock->viewport.MinZ = 0.0f;
6182 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6184 This->stateBlock->scissorRect.top = 0;
6185 This->stateBlock->scissorRect.left = 0;
6186 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
6187 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
6188 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6190 return WINED3D_OK;
6193 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6195 HRESULT hr = WINED3D_OK;
6196 IWineD3DSurface *tmp;
6198 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6200 if (pNewZStencil == This->stencilBufferTarget) {
6201 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6202 } else {
6203 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6204 * depending on the renter target implementation being used.
6205 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6206 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6207 * stencil buffer and incur an extra memory overhead
6208 ******************************************************/
6210 if (This->stencilBufferTarget) {
6211 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6212 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6213 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6214 } else {
6215 struct wined3d_context *context = ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6216 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
6217 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6221 tmp = This->stencilBufferTarget;
6222 This->stencilBufferTarget = pNewZStencil;
6223 /* should we be calling the parent or the wined3d surface? */
6224 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6225 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6226 hr = WINED3D_OK;
6228 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6229 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6230 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6231 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6232 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6236 return hr;
6239 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6240 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6242 /* TODO: the use of Impl is deprecated. */
6243 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6244 WINED3DLOCKED_RECT lockedRect;
6246 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6248 /* some basic validation checks */
6249 if(This->cursorTexture) {
6250 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6251 ENTER_GL();
6252 glDeleteTextures(1, &This->cursorTexture);
6253 LEAVE_GL();
6254 This->cursorTexture = 0;
6257 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6258 This->haveHardwareCursor = TRUE;
6259 else
6260 This->haveHardwareCursor = FALSE;
6262 if(pCursorBitmap) {
6263 WINED3DLOCKED_RECT rect;
6265 /* MSDN: Cursor must be A8R8G8B8 */
6266 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6268 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6269 return WINED3DERR_INVALIDCALL;
6272 /* MSDN: Cursor must be smaller than the display mode */
6273 if(pSur->currentDesc.Width > This->ddraw_width ||
6274 pSur->currentDesc.Height > This->ddraw_height) {
6275 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);
6276 return WINED3DERR_INVALIDCALL;
6279 if (!This->haveHardwareCursor) {
6280 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6282 /* Do not store the surface's pointer because the application may
6283 * release it after setting the cursor image. Windows doesn't
6284 * addref the set surface, so we can't do this either without
6285 * creating circular refcount dependencies. Copy out the gl texture
6286 * instead.
6288 This->cursorWidth = pSur->currentDesc.Width;
6289 This->cursorHeight = pSur->currentDesc.Height;
6290 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6292 const struct GlPixelFormatDesc *glDesc =
6293 getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, &GLINFO_LOCATION);
6294 char *mem, *bits = rect.pBits;
6295 GLint intfmt = glDesc->glInternal;
6296 GLint format = glDesc->glFormat;
6297 GLint type = glDesc->glType;
6298 INT height = This->cursorHeight;
6299 INT width = This->cursorWidth;
6300 INT bpp = glDesc->byte_count;
6301 DWORD sampler;
6302 INT i;
6304 /* Reformat the texture memory (pitch and width can be
6305 * different) */
6306 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6307 for(i = 0; i < height; i++)
6308 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6309 IWineD3DSurface_UnlockRect(pCursorBitmap);
6311 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6313 ENTER_GL();
6315 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6316 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6317 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6320 /* Make sure that a proper texture unit is selected */
6321 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6322 checkGLcall("glActiveTextureARB");
6323 sampler = This->rev_tex_unit_map[0];
6324 if (sampler != WINED3D_UNMAPPED_STAGE)
6326 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6328 /* Create a new cursor texture */
6329 glGenTextures(1, &This->cursorTexture);
6330 checkGLcall("glGenTextures");
6331 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6332 checkGLcall("glBindTexture");
6333 /* Copy the bitmap memory into the cursor texture */
6334 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6335 HeapFree(GetProcessHeap(), 0, mem);
6336 checkGLcall("glTexImage2D");
6338 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6339 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6340 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6343 LEAVE_GL();
6345 else
6347 FIXME("A cursor texture was not returned.\n");
6348 This->cursorTexture = 0;
6351 else
6353 /* Draw a hardware cursor */
6354 ICONINFO cursorInfo;
6355 HCURSOR cursor;
6356 /* Create and clear maskBits because it is not needed for
6357 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6358 * chunks. */
6359 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6360 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6361 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6362 WINED3DLOCK_NO_DIRTY_UPDATE |
6363 WINED3DLOCK_READONLY
6365 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6366 pSur->currentDesc.Height);
6368 cursorInfo.fIcon = FALSE;
6369 cursorInfo.xHotspot = XHotSpot;
6370 cursorInfo.yHotspot = YHotSpot;
6371 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6372 pSur->currentDesc.Height, 1,
6373 1, &maskBits);
6374 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6375 pSur->currentDesc.Height, 1,
6376 32, lockedRect.pBits);
6377 IWineD3DSurface_UnlockRect(pCursorBitmap);
6378 /* Create our cursor and clean up. */
6379 cursor = CreateIconIndirect(&cursorInfo);
6380 SetCursor(cursor);
6381 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6382 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6383 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6384 This->hardwareCursor = cursor;
6385 HeapFree(GetProcessHeap(), 0, maskBits);
6389 This->xHotSpot = XHotSpot;
6390 This->yHotSpot = YHotSpot;
6391 return WINED3D_OK;
6394 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6396 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6398 This->xScreenSpace = XScreenSpace;
6399 This->yScreenSpace = YScreenSpace;
6401 return;
6405 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6407 BOOL oldVisible = This->bCursorVisible;
6408 POINT pt;
6410 TRACE("(%p) : visible(%d)\n", This, bShow);
6413 * When ShowCursor is first called it should make the cursor appear at the OS's last
6414 * known cursor position. Because of this, some applications just repetitively call
6415 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6417 GetCursorPos(&pt);
6418 This->xScreenSpace = pt.x;
6419 This->yScreenSpace = pt.y;
6421 if (This->haveHardwareCursor) {
6422 This->bCursorVisible = bShow;
6423 if (bShow)
6424 SetCursor(This->hardwareCursor);
6425 else
6426 SetCursor(NULL);
6428 else
6430 if (This->cursorTexture)
6431 This->bCursorVisible = bShow;
6434 return oldVisible;
6437 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6439 IWineD3DResourceImpl *resource;
6440 TRACE("(%p) : state (%u)\n", This, This->state);
6442 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6443 switch (This->state) {
6444 case WINED3D_OK:
6445 return WINED3D_OK;
6446 case WINED3DERR_DEVICELOST:
6448 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6449 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6450 return WINED3DERR_DEVICENOTRESET;
6452 return WINED3DERR_DEVICELOST;
6454 case WINED3DERR_DRIVERINTERNALERROR:
6455 return WINED3DERR_DRIVERINTERNALERROR;
6458 /* Unknown state */
6459 return WINED3DERR_DRIVERINTERNALERROR;
6462 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6463 TRACE("checking resource %p for eviction\n", resource);
6464 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6465 TRACE("Evicting %p\n", resource);
6466 IWineD3DResource_UnLoad(resource);
6468 IWineD3DResource_Release(resource);
6469 return S_OK;
6472 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6474 TRACE("(%p)\n", This);
6476 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6477 return WINED3D_OK;
6480 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6482 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6484 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6485 if(surface->Flags & SFLAG_DIBSECTION) {
6486 /* Release the DC */
6487 SelectObject(surface->hDC, surface->dib.holdbitmap);
6488 DeleteDC(surface->hDC);
6489 /* Release the DIB section */
6490 DeleteObject(surface->dib.DIBsection);
6491 surface->dib.bitmap_data = NULL;
6492 surface->resource.allocatedMemory = NULL;
6493 surface->Flags &= ~SFLAG_DIBSECTION;
6495 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6496 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6497 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6498 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6499 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6500 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6501 } else {
6502 surface->pow2Width = surface->pow2Height = 1;
6503 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6504 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6506 surface->glRect.left = 0;
6507 surface->glRect.top = 0;
6508 surface->glRect.right = surface->pow2Width;
6509 surface->glRect.bottom = surface->pow2Height;
6511 if (surface->texture_name)
6513 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6514 ENTER_GL();
6515 glDeleteTextures(1, &surface->texture_name);
6516 LEAVE_GL();
6517 surface->texture_name = 0;
6518 surface->Flags &= ~SFLAG_CLIENT;
6520 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6521 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6522 surface->Flags |= SFLAG_NONPOW2;
6523 } else {
6524 surface->Flags &= ~SFLAG_NONPOW2;
6526 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6527 surface->resource.allocatedMemory = NULL;
6528 surface->resource.heapMemory = NULL;
6529 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6530 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6531 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6532 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6533 } else {
6534 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6538 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6539 TRACE("Unloading resource %p\n", resource);
6540 IWineD3DResource_UnLoad(resource);
6541 IWineD3DResource_Release(resource);
6542 return S_OK;
6545 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6547 UINT i, count;
6548 WINED3DDISPLAYMODE m;
6549 HRESULT hr;
6551 /* All Windowed modes are supported, as is leaving the current mode */
6552 if(pp->Windowed) return TRUE;
6553 if(!pp->BackBufferWidth) return TRUE;
6554 if(!pp->BackBufferHeight) return TRUE;
6556 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6557 for(i = 0; i < count; i++) {
6558 memset(&m, 0, sizeof(m));
6559 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6560 if(FAILED(hr)) {
6561 ERR("EnumAdapterModes failed\n");
6563 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6564 /* Mode found, it is supported */
6565 return TRUE;
6568 /* Mode not found -> not supported */
6569 return FALSE;
6572 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6574 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6575 const struct wined3d_context *context;
6576 const struct wined3d_gl_info *gl_info;
6577 UINT i;
6578 IWineD3DBaseShaderImpl *shader;
6580 context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6581 gl_info = context->gl_info;
6583 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6584 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6585 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6588 ENTER_GL();
6589 if(This->depth_blt_texture) {
6590 glDeleteTextures(1, &This->depth_blt_texture);
6591 This->depth_blt_texture = 0;
6593 if (This->depth_blt_rb) {
6594 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6595 This->depth_blt_rb = 0;
6596 This->depth_blt_rb_w = 0;
6597 This->depth_blt_rb_h = 0;
6599 LEAVE_GL();
6601 This->blitter->free_private(iface);
6602 This->frag_pipe->free_private(iface);
6603 This->shader_backend->shader_free_private(iface);
6605 ENTER_GL();
6606 for (i = 0; i < GL_LIMITS(textures); i++) {
6607 /* Textures are recreated below */
6608 glDeleteTextures(1, &This->dummyTextureName[i]);
6609 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6610 This->dummyTextureName[i] = 0;
6612 LEAVE_GL();
6614 while(This->numContexts) {
6615 DestroyContext(This, This->contexts[0]);
6617 HeapFree(GetProcessHeap(), 0, swapchain->context);
6618 swapchain->context = NULL;
6619 swapchain->num_contexts = 0;
6622 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6624 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6625 HRESULT hr;
6626 IWineD3DSurfaceImpl *target;
6628 /* Recreate the primary swapchain's context */
6629 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6630 if(swapchain->backBuffer) {
6631 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6632 } else {
6633 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6635 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
6636 &swapchain->presentParms);
6637 swapchain->num_contexts = 1;
6639 create_dummy_textures(This);
6641 hr = This->shader_backend->shader_alloc_private(iface);
6642 if(FAILED(hr)) {
6643 ERR("Failed to recreate shader private data\n");
6644 goto err_out;
6646 hr = This->frag_pipe->alloc_private(iface);
6647 if(FAILED(hr)) {
6648 TRACE("Fragment pipeline private data couldn't be allocated\n");
6649 goto err_out;
6651 hr = This->blitter->alloc_private(iface);
6652 if(FAILED(hr)) {
6653 TRACE("Blitter private data couldn't be allocated\n");
6654 goto err_out;
6657 return WINED3D_OK;
6659 err_out:
6660 This->blitter->free_private(iface);
6661 This->frag_pipe->free_private(iface);
6662 This->shader_backend->shader_free_private(iface);
6663 return hr;
6666 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6668 IWineD3DSwapChainImpl *swapchain;
6669 HRESULT hr;
6670 BOOL DisplayModeChanged = FALSE;
6671 WINED3DDISPLAYMODE mode;
6672 TRACE("(%p)\n", This);
6674 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6675 if(FAILED(hr)) {
6676 ERR("Failed to get the first implicit swapchain\n");
6677 return hr;
6680 if(!is_display_mode_supported(This, pPresentationParameters)) {
6681 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6682 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6683 pPresentationParameters->BackBufferHeight);
6684 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6685 return WINED3DERR_INVALIDCALL;
6688 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6689 * on an existing gl context, so there's no real need for recreation.
6691 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6693 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6695 TRACE("New params:\n");
6696 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6697 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6698 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6699 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6700 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6701 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6702 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6703 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6704 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6705 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6706 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6707 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6708 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6710 /* No special treatment of these parameters. Just store them */
6711 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6712 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6713 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6714 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6716 /* What to do about these? */
6717 if(pPresentationParameters->BackBufferCount != 0 &&
6718 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6719 ERR("Cannot change the back buffer count yet\n");
6721 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6722 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6723 ERR("Cannot change the back buffer format yet\n");
6725 if(pPresentationParameters->hDeviceWindow != NULL &&
6726 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6727 ERR("Cannot change the device window yet\n");
6729 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6730 HRESULT hrc;
6732 TRACE("Creating the depth stencil buffer\n");
6734 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6735 This->parent,
6736 pPresentationParameters->BackBufferWidth,
6737 pPresentationParameters->BackBufferHeight,
6738 pPresentationParameters->AutoDepthStencilFormat,
6739 pPresentationParameters->MultiSampleType,
6740 pPresentationParameters->MultiSampleQuality,
6741 FALSE,
6742 &This->auto_depth_stencil_buffer);
6744 if (FAILED(hrc)) {
6745 ERR("Failed to create the depth stencil buffer\n");
6746 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6747 return WINED3DERR_INVALIDCALL;
6751 /* Reset the depth stencil */
6752 if (pPresentationParameters->EnableAutoDepthStencil)
6753 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6754 else
6755 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6757 TRACE("Resetting stateblock\n");
6758 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6759 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6761 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6763 if(pPresentationParameters->Windowed) {
6764 mode.Width = swapchain->orig_width;
6765 mode.Height = swapchain->orig_height;
6766 mode.RefreshRate = 0;
6767 mode.Format = swapchain->presentParms.BackBufferFormat;
6768 } else {
6769 mode.Width = pPresentationParameters->BackBufferWidth;
6770 mode.Height = pPresentationParameters->BackBufferHeight;
6771 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6772 mode.Format = swapchain->presentParms.BackBufferFormat;
6775 /* Should Width == 800 && Height == 0 set 800x600? */
6776 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6777 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6778 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6780 UINT i;
6782 if(!pPresentationParameters->Windowed) {
6783 DisplayModeChanged = TRUE;
6785 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6786 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6788 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6789 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6790 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6792 if(This->auto_depth_stencil_buffer) {
6793 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6797 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6798 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6799 DisplayModeChanged) {
6801 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6803 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
6804 if(swapchain->presentParms.Windowed) {
6805 /* switch from windowed to fs */
6806 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
6807 pPresentationParameters->BackBufferWidth,
6808 pPresentationParameters->BackBufferHeight);
6809 } else {
6810 /* Fullscreen -> fullscreen mode change */
6811 MoveWindow(swapchain->win_handle, 0, 0,
6812 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6813 TRUE);
6815 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
6816 /* Fullscreen -> windowed switch */
6817 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
6819 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6820 } else if(!pPresentationParameters->Windowed) {
6821 DWORD style = This->style, exStyle = This->exStyle;
6822 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6823 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6824 * Reset to clear up their mess. Guild Wars also loses the device during that.
6826 This->style = 0;
6827 This->exStyle = 0;
6828 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
6829 pPresentationParameters->BackBufferWidth,
6830 pPresentationParameters->BackBufferHeight);
6831 This->style = style;
6832 This->exStyle = exStyle;
6835 /* Note: No parent needed for initial internal stateblock */
6836 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6837 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6838 else TRACE("Created stateblock %p\n", This->stateBlock);
6839 This->updateStateBlock = This->stateBlock;
6840 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6842 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6843 if(FAILED(hr)) {
6844 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6847 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6848 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6850 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6851 * first use
6853 return hr;
6856 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6858 /** FIXME: always true at the moment **/
6859 if(!bEnableDialogs) {
6860 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6862 return WINED3D_OK;
6866 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6868 TRACE("(%p) : pParameters %p\n", This, pParameters);
6870 *pParameters = This->createParms;
6871 return WINED3D_OK;
6874 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6875 IWineD3DSwapChain *swapchain;
6877 TRACE("Relaying to swapchain\n");
6879 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6880 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6881 IWineD3DSwapChain_Release(swapchain);
6883 return;
6886 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6887 IWineD3DSwapChain *swapchain;
6889 TRACE("Relaying to swapchain\n");
6891 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6892 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6893 IWineD3DSwapChain_Release(swapchain);
6895 return;
6899 /** ********************************************************
6900 * Notification functions
6901 ** ********************************************************/
6902 /** This function must be called in the release of a resource when ref == 0,
6903 * the contents of resource must still be correct,
6904 * any handles to other resource held by the caller must be closed
6905 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6906 *****************************************************/
6907 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6909 TRACE("(%p) : Adding resource %p\n", This, resource);
6911 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6914 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6916 TRACE("(%p) : Removing resource %p\n", This, resource);
6918 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6921 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6923 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6924 int counter;
6926 TRACE("(%p) : resource %p\n", This, resource);
6928 context_resource_released((IWineD3DDevice *)This, resource, type);
6930 switch (type) {
6931 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6932 case WINED3DRTYPE_SURFACE: {
6933 unsigned int i;
6935 if (This->d3d_initialized)
6937 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6938 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6939 This->render_targets[i] = NULL;
6942 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6943 This->stencilBufferTarget = NULL;
6947 break;
6949 case WINED3DRTYPE_TEXTURE:
6950 case WINED3DRTYPE_CUBETEXTURE:
6951 case WINED3DRTYPE_VOLUMETEXTURE:
6952 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6953 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6954 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6955 This->stateBlock->textures[counter] = NULL;
6957 if (This->updateStateBlock != This->stateBlock ){
6958 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6959 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6960 This->updateStateBlock->textures[counter] = NULL;
6964 break;
6965 case WINED3DRTYPE_VOLUME:
6966 /* TODO: nothing really? */
6967 break;
6968 case WINED3DRTYPE_BUFFER:
6970 int streamNumber;
6971 TRACE("Cleaning up stream pointers\n");
6973 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6974 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6975 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6977 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6978 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6979 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6980 This->updateStateBlock->streamSource[streamNumber] = 0;
6981 /* Set changed flag? */
6984 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) */
6985 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6986 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6987 This->stateBlock->streamSource[streamNumber] = 0;
6992 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6993 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6994 This->updateStateBlock->pIndexData = NULL;
6997 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6998 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6999 This->stateBlock->pIndexData = NULL;
7003 break;
7005 default:
7006 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7007 break;
7011 /* Remove the resource from the resourceStore */
7012 device_resource_remove(This, resource);
7014 TRACE("Resource released\n");
7018 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7020 IWineD3DResourceImpl *resource, *cursor;
7021 HRESULT ret;
7022 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7024 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7025 TRACE("enumerating resource %p\n", resource);
7026 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7027 ret = pCallback((IWineD3DResource *) resource, pData);
7028 if(ret == S_FALSE) {
7029 TRACE("Canceling enumeration\n");
7030 break;
7033 return WINED3D_OK;
7036 /**********************************************************
7037 * IWineD3DDevice VTbl follows
7038 **********************************************************/
7040 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7042 /*** IUnknown methods ***/
7043 IWineD3DDeviceImpl_QueryInterface,
7044 IWineD3DDeviceImpl_AddRef,
7045 IWineD3DDeviceImpl_Release,
7046 /*** IWineD3DDevice methods ***/
7047 IWineD3DDeviceImpl_GetParent,
7048 /*** Creation methods**/
7049 IWineD3DDeviceImpl_CreateBuffer,
7050 IWineD3DDeviceImpl_CreateVertexBuffer,
7051 IWineD3DDeviceImpl_CreateIndexBuffer,
7052 IWineD3DDeviceImpl_CreateStateBlock,
7053 IWineD3DDeviceImpl_CreateSurface,
7054 IWineD3DDeviceImpl_CreateRendertargetView,
7055 IWineD3DDeviceImpl_CreateTexture,
7056 IWineD3DDeviceImpl_CreateVolumeTexture,
7057 IWineD3DDeviceImpl_CreateVolume,
7058 IWineD3DDeviceImpl_CreateCubeTexture,
7059 IWineD3DDeviceImpl_CreateQuery,
7060 IWineD3DDeviceImpl_CreateSwapChain,
7061 IWineD3DDeviceImpl_CreateVertexDeclaration,
7062 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7063 IWineD3DDeviceImpl_CreateVertexShader,
7064 IWineD3DDeviceImpl_CreatePixelShader,
7065 IWineD3DDeviceImpl_CreatePalette,
7066 /*** Odd functions **/
7067 IWineD3DDeviceImpl_Init3D,
7068 IWineD3DDeviceImpl_InitGDI,
7069 IWineD3DDeviceImpl_Uninit3D,
7070 IWineD3DDeviceImpl_UninitGDI,
7071 IWineD3DDeviceImpl_SetMultithreaded,
7072 IWineD3DDeviceImpl_EvictManagedResources,
7073 IWineD3DDeviceImpl_GetAvailableTextureMem,
7074 IWineD3DDeviceImpl_GetBackBuffer,
7075 IWineD3DDeviceImpl_GetCreationParameters,
7076 IWineD3DDeviceImpl_GetDeviceCaps,
7077 IWineD3DDeviceImpl_GetDirect3D,
7078 IWineD3DDeviceImpl_GetDisplayMode,
7079 IWineD3DDeviceImpl_SetDisplayMode,
7080 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7081 IWineD3DDeviceImpl_GetRasterStatus,
7082 IWineD3DDeviceImpl_GetSwapChain,
7083 IWineD3DDeviceImpl_Reset,
7084 IWineD3DDeviceImpl_SetDialogBoxMode,
7085 IWineD3DDeviceImpl_SetCursorProperties,
7086 IWineD3DDeviceImpl_SetCursorPosition,
7087 IWineD3DDeviceImpl_ShowCursor,
7088 IWineD3DDeviceImpl_TestCooperativeLevel,
7089 /*** Getters and setters **/
7090 IWineD3DDeviceImpl_SetClipPlane,
7091 IWineD3DDeviceImpl_GetClipPlane,
7092 IWineD3DDeviceImpl_SetClipStatus,
7093 IWineD3DDeviceImpl_GetClipStatus,
7094 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7095 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7096 IWineD3DDeviceImpl_SetDepthStencilSurface,
7097 IWineD3DDeviceImpl_GetDepthStencilSurface,
7098 IWineD3DDeviceImpl_SetGammaRamp,
7099 IWineD3DDeviceImpl_GetGammaRamp,
7100 IWineD3DDeviceImpl_SetIndexBuffer,
7101 IWineD3DDeviceImpl_GetIndexBuffer,
7102 IWineD3DDeviceImpl_SetBaseVertexIndex,
7103 IWineD3DDeviceImpl_GetBaseVertexIndex,
7104 IWineD3DDeviceImpl_SetLight,
7105 IWineD3DDeviceImpl_GetLight,
7106 IWineD3DDeviceImpl_SetLightEnable,
7107 IWineD3DDeviceImpl_GetLightEnable,
7108 IWineD3DDeviceImpl_SetMaterial,
7109 IWineD3DDeviceImpl_GetMaterial,
7110 IWineD3DDeviceImpl_SetNPatchMode,
7111 IWineD3DDeviceImpl_GetNPatchMode,
7112 IWineD3DDeviceImpl_SetPaletteEntries,
7113 IWineD3DDeviceImpl_GetPaletteEntries,
7114 IWineD3DDeviceImpl_SetPixelShader,
7115 IWineD3DDeviceImpl_GetPixelShader,
7116 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7117 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7118 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7119 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7120 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7121 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7122 IWineD3DDeviceImpl_SetRenderState,
7123 IWineD3DDeviceImpl_GetRenderState,
7124 IWineD3DDeviceImpl_SetRenderTarget,
7125 IWineD3DDeviceImpl_GetRenderTarget,
7126 IWineD3DDeviceImpl_SetFrontBackBuffers,
7127 IWineD3DDeviceImpl_SetSamplerState,
7128 IWineD3DDeviceImpl_GetSamplerState,
7129 IWineD3DDeviceImpl_SetScissorRect,
7130 IWineD3DDeviceImpl_GetScissorRect,
7131 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7132 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7133 IWineD3DDeviceImpl_SetStreamSource,
7134 IWineD3DDeviceImpl_GetStreamSource,
7135 IWineD3DDeviceImpl_SetStreamSourceFreq,
7136 IWineD3DDeviceImpl_GetStreamSourceFreq,
7137 IWineD3DDeviceImpl_SetTexture,
7138 IWineD3DDeviceImpl_GetTexture,
7139 IWineD3DDeviceImpl_SetTextureStageState,
7140 IWineD3DDeviceImpl_GetTextureStageState,
7141 IWineD3DDeviceImpl_SetTransform,
7142 IWineD3DDeviceImpl_GetTransform,
7143 IWineD3DDeviceImpl_SetVertexDeclaration,
7144 IWineD3DDeviceImpl_GetVertexDeclaration,
7145 IWineD3DDeviceImpl_SetVertexShader,
7146 IWineD3DDeviceImpl_GetVertexShader,
7147 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7148 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7149 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7150 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7151 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7152 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7153 IWineD3DDeviceImpl_SetViewport,
7154 IWineD3DDeviceImpl_GetViewport,
7155 IWineD3DDeviceImpl_MultiplyTransform,
7156 IWineD3DDeviceImpl_ValidateDevice,
7157 IWineD3DDeviceImpl_ProcessVertices,
7158 /*** State block ***/
7159 IWineD3DDeviceImpl_BeginStateBlock,
7160 IWineD3DDeviceImpl_EndStateBlock,
7161 /*** Scene management ***/
7162 IWineD3DDeviceImpl_BeginScene,
7163 IWineD3DDeviceImpl_EndScene,
7164 IWineD3DDeviceImpl_Present,
7165 IWineD3DDeviceImpl_Clear,
7166 IWineD3DDeviceImpl_ClearRendertargetView,
7167 /*** Drawing ***/
7168 IWineD3DDeviceImpl_SetPrimitiveType,
7169 IWineD3DDeviceImpl_GetPrimitiveType,
7170 IWineD3DDeviceImpl_DrawPrimitive,
7171 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7172 IWineD3DDeviceImpl_DrawPrimitiveUP,
7173 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7174 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7175 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7176 IWineD3DDeviceImpl_DrawRectPatch,
7177 IWineD3DDeviceImpl_DrawTriPatch,
7178 IWineD3DDeviceImpl_DeletePatch,
7179 IWineD3DDeviceImpl_ColorFill,
7180 IWineD3DDeviceImpl_UpdateTexture,
7181 IWineD3DDeviceImpl_UpdateSurface,
7182 IWineD3DDeviceImpl_GetFrontBufferData,
7183 /*** object tracking ***/
7184 IWineD3DDeviceImpl_EnumResources
7187 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7188 DWORD rep = This->StateTable[state].representative;
7189 struct wined3d_context *context;
7190 DWORD idx;
7191 BYTE shift;
7192 UINT i;
7194 for(i = 0; i < This->numContexts; i++) {
7195 context = This->contexts[i];
7196 if(isStateDirty(context, rep)) continue;
7198 context->dirtyArray[context->numDirtyEntries++] = rep;
7199 idx = rep >> 5;
7200 shift = rep & 0x1f;
7201 context->isStateDirty[idx] |= (1 << shift);
7205 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7207 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.wineD3DDevice;
7208 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7209 *width = device->pbufferWidth;
7210 *height = device->pbufferHeight;
7213 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7215 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7216 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7217 *width = surface->pow2Width;
7218 *height = surface->pow2Height;
7221 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7223 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7224 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7225 * current context's drawable, which is the size of the back buffer of the swapchain
7226 * the active context belongs to. The back buffer of the swapchain is stored as the
7227 * surface the context belongs to. */
7228 *width = surface->currentDesc.Width;
7229 *height = surface->currentDesc.Height;