push 52d6b63ba2f2d4f9b02b6b922d27bff05a60596f
[wine/hacks.git] / dlls / wined3d / device.c
bloba1b8944f117f62a66aebf8b070937419e3d7f2af
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "config.h"
30 #include <stdio.h>
31 #ifdef HAVE_FLOAT_H
32 # include <float.h>
33 #endif
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
37 #define GLINFO_LOCATION This->adapter->gl_info
39 /* Define the default light parameters as specified by MSDN */
40 const WINED3DLIGHT WINED3D_default_light = {
42 WINED3DLIGHT_DIRECTIONAL, /* Type */
43 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
45 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
46 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
47 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
48 0.0f, /* Range */
49 0.0f, /* Falloff */
50 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
51 0.0f, /* Theta */
52 0.0f /* Phi */
55 /**********************************************************
56 * Global variable / Constants follow
57 **********************************************************/
58 const float identity[] =
60 1.0f, 0.0f, 0.0f, 0.0f,
61 0.0f, 1.0f, 0.0f, 0.0f,
62 0.0f, 0.0f, 1.0f, 0.0f,
63 0.0f, 0.0f, 0.0f, 1.0f,
64 }; /* When needed for comparisons */
66 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
67 * actually have the same values in GL and D3D. */
68 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
70 switch(primitive_type)
72 case WINED3DPT_POINTLIST:
73 return GL_POINTS;
75 case WINED3DPT_LINELIST:
76 return GL_LINES;
78 case WINED3DPT_LINESTRIP:
79 return GL_LINE_STRIP;
81 case WINED3DPT_TRIANGLELIST:
82 return GL_TRIANGLES;
84 case WINED3DPT_TRIANGLESTRIP:
85 return GL_TRIANGLE_STRIP;
87 case WINED3DPT_TRIANGLEFAN:
88 return GL_TRIANGLE_FAN;
90 case WINED3DPT_LINELIST_ADJ:
91 return GL_LINES_ADJACENCY_ARB;
93 case WINED3DPT_LINESTRIP_ADJ:
94 return GL_LINE_STRIP_ADJACENCY_ARB;
96 case WINED3DPT_TRIANGLELIST_ADJ:
97 return GL_TRIANGLES_ADJACENCY_ARB;
99 case WINED3DPT_TRIANGLESTRIP_ADJ:
100 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
102 default:
103 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
104 return GL_NONE;
108 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
110 switch(primitive_type)
112 case GL_POINTS:
113 return WINED3DPT_POINTLIST;
115 case GL_LINES:
116 return WINED3DPT_LINELIST;
118 case GL_LINE_STRIP:
119 return WINED3DPT_LINESTRIP;
121 case GL_TRIANGLES:
122 return WINED3DPT_TRIANGLELIST;
124 case GL_TRIANGLE_STRIP:
125 return WINED3DPT_TRIANGLESTRIP;
127 case GL_TRIANGLE_FAN:
128 return WINED3DPT_TRIANGLEFAN;
130 case GL_LINES_ADJACENCY_ARB:
131 return WINED3DPT_LINELIST_ADJ;
133 case GL_LINE_STRIP_ADJACENCY_ARB:
134 return WINED3DPT_LINESTRIP_ADJ;
136 case GL_TRIANGLES_ADJACENCY_ARB:
137 return WINED3DPT_TRIANGLELIST_ADJ;
139 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
140 return WINED3DPT_TRIANGLESTRIP_ADJ;
142 default:
143 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
144 return WINED3DPT_UNDEFINED;
148 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
150 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
151 *regnum = WINED3D_FFP_POSITION;
152 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
153 *regnum = WINED3D_FFP_BLENDWEIGHT;
154 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
155 *regnum = WINED3D_FFP_BLENDINDICES;
156 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
157 *regnum = WINED3D_FFP_NORMAL;
158 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
159 *regnum = WINED3D_FFP_PSIZE;
160 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
161 *regnum = WINED3D_FFP_DIFFUSE;
162 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
163 *regnum = WINED3D_FFP_SPECULAR;
164 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
165 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
166 else
168 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
169 *regnum = ~0U;
170 return FALSE;
173 return TRUE;
176 /* Context activation is done by the caller. */
177 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
178 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
180 /* We need to deal with frequency data! */
181 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
182 UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
183 const DWORD *streams = declaration->streams;
184 unsigned int i;
186 stream_info->use_map = 0;
187 stream_info->swizzle_map = 0;
189 /* Check for transformed vertices, disable vertex shader if present. */
190 stream_info->position_transformed = declaration->position_transformed;
191 if (declaration->position_transformed) use_vshader = FALSE;
193 /* Translate the declaration into strided data. */
194 for (i = 0; i < declaration->element_count; ++i)
196 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
197 GLuint buffer_object = 0;
198 const BYTE *data = NULL;
199 BOOL stride_used;
200 unsigned int idx;
201 DWORD stride;
203 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
204 element, i + 1, declaration->element_count);
206 if (!This->stateBlock->streamSource[element->input_slot]) continue;
208 stride = This->stateBlock->streamStride[element->input_slot];
209 if (This->stateBlock->streamIsUP)
211 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
212 buffer_object = 0;
213 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
215 else
217 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
218 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
220 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
221 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
222 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
223 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
224 * not, drawStridedSlow is needed, including a vertex buffer path. */
225 if (This->stateBlock->loadBaseVertexIndex < 0)
227 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
228 buffer_object = 0;
229 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
230 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
232 FIXME("System memory vertex data load offset is negative!\n");
236 if (fixup)
238 if (buffer_object) *fixup = TRUE;
239 else if (*fixup && !use_vshader
240 && (element->usage == WINED3DDECLUSAGE_COLOR
241 || element->usage == WINED3DDECLUSAGE_POSITIONT))
243 static BOOL warned = FALSE;
244 if (!warned)
246 /* This may be bad with the fixed function pipeline. */
247 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
248 warned = TRUE;
253 data += element->offset;
255 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
257 if (use_vshader)
259 if (element->output_slot == ~0U)
261 /* TODO: Assuming vertexdeclarations are usually used with the
262 * same or a similar shader, it might be worth it to store the
263 * last used output slot and try that one first. */
264 stride_used = vshader_get_input(This->stateBlock->vertexShader,
265 element->usage, element->usage_idx, &idx);
267 else
269 idx = element->output_slot;
270 stride_used = TRUE;
273 else
275 if (!element->ffp_valid)
277 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
278 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
279 stride_used = FALSE;
281 else
283 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
287 if (stride_used)
289 TRACE("Load %s array %u [usage %s, usage_idx %u, "
290 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
291 use_vshader ? "shader": "fixed function", idx,
292 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
293 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
295 stream_info->elements[idx].format_desc = element->format_desc;
296 stream_info->elements[idx].stride = stride;
297 stream_info->elements[idx].data = data;
298 stream_info->elements[idx].stream_idx = element->input_slot;
299 stream_info->elements[idx].buffer_object = buffer_object;
301 if (!This->adapter->gl_info.supported[EXT_VERTEX_ARRAY_BGRA]
302 && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
304 stream_info->swizzle_map |= 1 << idx;
306 stream_info->use_map |= 1 << idx;
310 /* Now call PreLoad on all the vertex buffers. In the very rare case
311 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
312 * The vertex buffer can now use the strided structure in the device instead of finding its
313 * own again.
315 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
316 * once in there. */
317 for (i = 0; i < stream_count; ++i)
319 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
320 if (vb) IWineD3DBuffer_PreLoad(vb);
324 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
325 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
327 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, gl_info);
328 e->format_desc = format_desc;
329 e->stride = strided->dwStride;
330 e->data = strided->lpData;
331 e->stream_idx = 0;
332 e->buffer_object = 0;
335 void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
336 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
338 unsigned int i;
340 memset(stream_info, 0, sizeof(*stream_info));
342 if (strided->position.lpData)
343 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
344 if (strided->normal.lpData)
345 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
346 if (strided->diffuse.lpData)
347 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
348 if (strided->specular.lpData)
349 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
351 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
353 if (strided->texCoords[i].lpData)
354 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
355 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
358 stream_info->position_transformed = strided->position_transformed;
360 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
362 if (!stream_info->elements[i].format_desc) continue;
364 if (!gl_info->supported[EXT_VERTEX_ARRAY_BGRA]
365 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
367 stream_info->swizzle_map |= 1 << i;
369 stream_info->use_map |= 1 << i;
373 /**********************************************************
374 * IUnknown parts follows
375 **********************************************************/
377 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
381 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
382 if (IsEqualGUID(riid, &IID_IUnknown)
383 || IsEqualGUID(riid, &IID_IWineD3DBase)
384 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
385 IUnknown_AddRef(iface);
386 *ppobj = This;
387 return S_OK;
389 *ppobj = NULL;
390 return E_NOINTERFACE;
393 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
395 ULONG refCount = InterlockedIncrement(&This->ref);
397 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
398 return refCount;
401 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
403 ULONG refCount = InterlockedDecrement(&This->ref);
405 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
407 if (!refCount) {
408 UINT i;
410 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
411 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
412 This->multistate_funcs[i] = NULL;
415 /* TODO: Clean up all the surfaces and textures! */
416 /* NOTE: You must release the parent if the object was created via a callback
417 ** ***************************/
419 if (!list_empty(&This->resources)) {
420 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
421 dumpResources(&This->resources);
424 if(This->contexts) ERR("Context array not freed!\n");
425 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
426 This->haveHardwareCursor = FALSE;
428 IWineD3D_Release(This->wineD3D);
429 This->wineD3D = NULL;
430 HeapFree(GetProcessHeap(), 0, This);
431 TRACE("Freed device %p\n", This);
432 This = NULL;
434 return refCount;
437 /**********************************************************
438 * IWineD3DDevice implementation follows
439 **********************************************************/
440 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
442 *pParent = This->parent;
443 IUnknown_AddRef(This->parent);
444 return WINED3D_OK;
447 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
448 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
451 struct wined3d_buffer *object;
452 HRESULT hr;
454 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
456 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
457 if (!object)
459 ERR("Failed to allocate memory\n");
460 return E_OUTOFMEMORY;
463 FIXME("Ignoring access flags (pool)\n");
465 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
466 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
467 if (FAILED(hr))
469 WARN("Failed to initialize buffer, hr %#x.\n", hr);
470 HeapFree(GetProcessHeap(), 0, object);
471 return hr;
473 object->desc = *desc;
475 TRACE("Created buffer %p.\n", object);
477 *buffer = (IWineD3DBuffer *)object;
479 return WINED3D_OK;
482 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size,
483 DWORD Usage, DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
484 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
487 struct wined3d_buffer *object;
488 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
489 HRESULT hr;
490 BOOL conv;
492 if (Pool == WINED3DPOOL_SCRATCH)
494 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
495 * anyway, SCRATCH vertex buffers aren't usable anywhere
497 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
498 *ppVertexBuffer = NULL;
499 return WINED3DERR_INVALIDCALL;
502 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
503 if (!object)
505 ERR("Out of memory\n");
506 *ppVertexBuffer = NULL;
507 return WINED3DERR_OUTOFVIDEOMEMORY;
510 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
511 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
512 if (FAILED(hr))
514 WARN("Failed to initialize buffer, hr %#x.\n", hr);
515 HeapFree(GetProcessHeap(), 0, object);
516 return hr;
519 TRACE("Created buffer %p.\n", object);
520 TRACE("FVF %#x, Pool %#x.\n", FVF, Pool);
521 *ppVertexBuffer = (IWineD3DBuffer *)object;
523 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
524 * drawStridedFast (half-life 2).
526 * Basically converting the vertices in the buffer is quite expensive, and observations
527 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
528 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
530 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
531 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
532 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
533 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
534 * dx7 apps.
535 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
536 * more. In this call we can convert dx7 buffers too.
538 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
539 if (!This->adapter->gl_info.supported[ARB_VERTEX_BUFFER_OBJECT])
541 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
542 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
543 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
544 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
545 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
546 } else if(dxVersion <= 7 && conv) {
547 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
548 } else {
549 object->flags |= WINED3D_BUFFER_CREATEBO;
551 return WINED3D_OK;
554 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
555 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
556 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
559 struct wined3d_buffer *object;
560 HRESULT hr;
562 TRACE("(%p) Creating index buffer\n", This);
564 /* Allocate the storage for the device */
565 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
566 if (!object)
568 ERR("Out of memory\n");
569 *ppIndexBuffer = NULL;
570 return WINED3DERR_OUTOFVIDEOMEMORY;
573 hr = buffer_init(object, This, Length, Usage, WINED3DFMT_UNKNOWN,
574 Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
575 if (FAILED(hr))
577 WARN("Failed to initialize buffer, hr %#x\n", hr);
578 HeapFree(GetProcessHeap(), 0, object);
579 return hr;
582 TRACE("Created buffer %p.\n", object);
584 if (Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC)
585 && This->adapter->gl_info.supported[ARB_VERTEX_BUFFER_OBJECT])
587 object->flags |= WINED3D_BUFFER_CREATEBO;
590 *ppIndexBuffer = (IWineD3DBuffer *) object;
592 return WINED3D_OK;
595 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
596 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
599 IWineD3DStateBlockImpl *object;
600 HRESULT hr;
602 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
603 if(!object)
605 ERR("Failed to allocate stateblock memory.\n");
606 return E_OUTOFMEMORY;
609 hr = stateblock_init(object, This, type, parent);
610 if (FAILED(hr))
612 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
613 HeapFree(GetProcessHeap(), 0, object);
614 return hr;
617 TRACE("Created stateblock %p.\n", object);
618 *stateblock = (IWineD3DStateBlock *)object;
620 return WINED3D_OK;
623 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
624 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
625 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
626 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
629 IWineD3DSurfaceImpl *object;
630 HRESULT hr;
632 TRACE("(%p) Create surface\n",This);
634 if (Impl == SURFACE_OPENGL && !This->adapter)
636 ERR("OpenGL surfaces are not available without OpenGL.\n");
637 return WINED3DERR_NOTAVAILABLE;
640 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
641 if (!object)
643 ERR("Failed to allocate surface memory.\n");
644 *ppSurface = NULL;
645 return WINED3DERR_OUTOFVIDEOMEMORY;
648 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
649 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
650 if (FAILED(hr))
652 WARN("Failed to initialize surface, returning %#x.\n", hr);
653 HeapFree(GetProcessHeap(), 0, object);
654 *ppSurface = NULL;
655 return hr;
658 TRACE("(%p) : Created surface %p\n", This, object);
660 *ppSurface = (IWineD3DSurface *)object;
662 return hr;
665 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
666 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
668 struct wined3d_rendertarget_view *object;
670 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
671 if (!object)
673 ERR("Failed to allocate memory\n");
674 return E_OUTOFMEMORY;
677 object->vtbl = &wined3d_rendertarget_view_vtbl;
678 object->refcount = 1;
679 IWineD3DResource_AddRef(resource);
680 object->resource = resource;
681 object->parent = parent;
683 *rendertarget_view = (IWineD3DRendertargetView *)object;
685 return WINED3D_OK;
688 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
689 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
690 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
693 IWineD3DTextureImpl *object;
694 HRESULT hr;
696 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
697 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
698 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
700 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
701 if (!object)
703 ERR("Out of memory\n");
704 *ppTexture = NULL;
705 return WINED3DERR_OUTOFVIDEOMEMORY;
708 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
709 if (FAILED(hr))
711 WARN("Failed to initialize texture, returning %#x\n", hr);
712 HeapFree(GetProcessHeap(), 0, object);
713 *ppTexture = NULL;
714 return hr;
717 *ppTexture = (IWineD3DTexture *)object;
719 TRACE("(%p) : Created texture %p\n", This, object);
721 return WINED3D_OK;
724 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
725 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
726 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
729 IWineD3DVolumeTextureImpl *object;
730 HRESULT hr;
732 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
733 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
735 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
736 if (!object)
738 ERR("Out of memory\n");
739 *ppVolumeTexture = NULL;
740 return WINED3DERR_OUTOFVIDEOMEMORY;
743 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
744 if (FAILED(hr))
746 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
747 HeapFree(GetProcessHeap(), 0, object);
748 *ppVolumeTexture = NULL;
749 return hr;
752 TRACE("(%p) : Created volume texture %p.\n", This, object);
753 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
755 return WINED3D_OK;
758 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
759 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
760 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
763 IWineD3DVolumeImpl *object;
764 HRESULT hr;
766 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
767 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
769 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
770 if (!object)
772 ERR("Out of memory\n");
773 *ppVolume = NULL;
774 return WINED3DERR_OUTOFVIDEOMEMORY;
777 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
778 if (FAILED(hr))
780 WARN("Failed to initialize volume, returning %#x.\n", hr);
781 HeapFree(GetProcessHeap(), 0, object);
782 return hr;
785 TRACE("(%p) : Created volume %p.\n", This, object);
786 *ppVolume = (IWineD3DVolume *)object;
788 return WINED3D_OK;
791 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
792 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
793 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
796 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
797 HRESULT hr;
799 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
800 if (!object)
802 ERR("Out of memory\n");
803 *ppCubeTexture = NULL;
804 return WINED3DERR_OUTOFVIDEOMEMORY;
807 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
808 if (FAILED(hr))
810 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
811 HeapFree(GetProcessHeap(), 0, object);
812 *ppCubeTexture = NULL;
813 return hr;
816 TRACE("(%p) : Created Cube Texture %p\n", This, object);
817 *ppCubeTexture = (IWineD3DCubeTexture *)object;
819 return WINED3D_OK;
822 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
824 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
825 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
826 HRESULT hr = WINED3DERR_NOTAVAILABLE;
827 const IWineD3DQueryVtbl *vtable;
829 /* Just a check to see if we support this type of query */
830 switch(Type) {
831 case WINED3DQUERYTYPE_OCCLUSION:
832 TRACE("(%p) occlusion query\n", This);
833 if (gl_info->supported[ARB_OCCLUSION_QUERY])
834 hr = WINED3D_OK;
835 else
836 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
838 vtable = &IWineD3DOcclusionQuery_Vtbl;
839 break;
841 case WINED3DQUERYTYPE_EVENT:
842 if (!gl_info->supported[NV_FENCE] && !gl_info->supported[APPLE_FENCE])
844 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
845 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
847 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
849 vtable = &IWineD3DEventQuery_Vtbl;
850 hr = WINED3D_OK;
851 break;
853 case WINED3DQUERYTYPE_VCACHE:
854 case WINED3DQUERYTYPE_RESOURCEMANAGER:
855 case WINED3DQUERYTYPE_VERTEXSTATS:
856 case WINED3DQUERYTYPE_TIMESTAMP:
857 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
858 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
859 case WINED3DQUERYTYPE_PIPELINETIMINGS:
860 case WINED3DQUERYTYPE_INTERFACETIMINGS:
861 case WINED3DQUERYTYPE_VERTEXTIMINGS:
862 case WINED3DQUERYTYPE_PIXELTIMINGS:
863 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
864 case WINED3DQUERYTYPE_CACHEUTILIZATION:
865 default:
866 /* Use the base Query vtable until we have a special one for each query */
867 vtable = &IWineD3DQuery_Vtbl;
868 FIXME("(%p) Unhandled query type %d\n", This, Type);
870 if(NULL == ppQuery || hr != WINED3D_OK) {
871 return hr;
874 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
875 if(!object)
877 ERR("Out of memory\n");
878 *ppQuery = NULL;
879 return WINED3DERR_OUTOFVIDEOMEMORY;
882 object->lpVtbl = vtable;
883 object->type = Type;
884 object->state = QUERY_CREATED;
885 object->wineD3DDevice = This;
886 object->parent = parent;
887 object->ref = 1;
889 *ppQuery = (IWineD3DQuery *)object;
891 /* allocated the 'extended' data based on the type of query requested */
892 switch(Type){
893 case WINED3DQUERYTYPE_OCCLUSION:
894 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
895 ((struct wined3d_occlusion_query *)object->extendedData)->context = NULL;
896 break;
898 case WINED3DQUERYTYPE_EVENT:
899 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query));
900 ((struct wined3d_event_query *)object->extendedData)->context = NULL;
901 break;
903 case WINED3DQUERYTYPE_VCACHE:
904 case WINED3DQUERYTYPE_RESOURCEMANAGER:
905 case WINED3DQUERYTYPE_VERTEXSTATS:
906 case WINED3DQUERYTYPE_TIMESTAMP:
907 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
908 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
909 case WINED3DQUERYTYPE_PIPELINETIMINGS:
910 case WINED3DQUERYTYPE_INTERFACETIMINGS:
911 case WINED3DQUERYTYPE_VERTEXTIMINGS:
912 case WINED3DQUERYTYPE_PIXELTIMINGS:
913 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
914 case WINED3DQUERYTYPE_CACHEUTILIZATION:
915 default:
916 object->extendedData = 0;
917 FIXME("(%p) Unhandled query type %d\n",This , Type);
919 TRACE("(%p) : Created Query %p\n", This, object);
920 return WINED3D_OK;
923 /*****************************************************************************
924 * IWineD3DDeviceImpl_SetupFullscreenWindow
926 * Helper function that modifies a HWND's Style and ExStyle for proper
927 * fullscreen use.
929 * Params:
930 * iface: Pointer to the IWineD3DDevice interface
931 * window: Window to setup
933 *****************************************************************************/
934 static LONG fullscreen_style(LONG orig_style) {
935 LONG style = orig_style;
936 style &= ~WS_CAPTION;
937 style &= ~WS_THICKFRAME;
939 /* Make sure the window is managed, otherwise we won't get keyboard input */
940 style |= WS_POPUP | WS_SYSMENU;
942 return style;
945 static LONG fullscreen_exStyle(LONG orig_exStyle) {
946 LONG exStyle = orig_exStyle;
948 /* Filter out window decorations */
949 exStyle &= ~WS_EX_WINDOWEDGE;
950 exStyle &= ~WS_EX_CLIENTEDGE;
952 return exStyle;
955 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
958 LONG style, exStyle;
959 /* Don't do anything if an original style is stored.
960 * That shouldn't happen
962 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
963 if (This->style || This->exStyle) {
964 ERR("(%p): Want to change the window parameters of HWND %p, but "
965 "another style is stored for restoration afterwards\n", This, window);
968 /* Get the parameters and save them */
969 style = GetWindowLongW(window, GWL_STYLE);
970 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
971 This->style = style;
972 This->exStyle = exStyle;
974 style = fullscreen_style(style);
975 exStyle = fullscreen_exStyle(exStyle);
977 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
978 This->style, This->exStyle, style, exStyle);
980 SetWindowLongW(window, GWL_STYLE, style);
981 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
983 /* Inform the window about the update. */
984 SetWindowPos(window, HWND_TOP, 0, 0,
985 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
988 /*****************************************************************************
989 * IWineD3DDeviceImpl_RestoreWindow
991 * Helper function that restores a windows' properties when taking it out
992 * of fullscreen mode
994 * Params:
995 * iface: Pointer to the IWineD3DDevice interface
996 * window: Window to setup
998 *****************************************************************************/
999 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1001 LONG style, exStyle;
1003 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1004 * switch, do nothing
1006 if (!This->style && !This->exStyle) return;
1008 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1009 This, window, This->style, This->exStyle);
1011 style = GetWindowLongW(window, GWL_STYLE);
1012 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1014 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1015 * Some applications change it before calling Reset() when switching between windowed and
1016 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1018 if(style == fullscreen_style(This->style) &&
1019 exStyle == fullscreen_style(This->exStyle)) {
1020 SetWindowLongW(window, GWL_STYLE, This->style);
1021 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1024 /* Delete the old values */
1025 This->style = 0;
1026 This->exStyle = 0;
1028 /* Inform the window about the update */
1029 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1030 0, 0, 0, 0, /* Pos, Size, ignored */
1031 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1034 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1035 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1036 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1037 IUnknown *parent, WINED3DSURFTYPE surface_type)
1039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1041 HDC hDc;
1042 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1043 HRESULT hr;
1044 BOOL displaymode_set = FALSE;
1045 WINED3DDISPLAYMODE Mode;
1046 const struct GlPixelFormatDesc *format_desc;
1048 TRACE("(%p) : Created Additional Swap Chain\n", This);
1050 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1051 * does a device hold a reference to a swap chain giving them a lifetime of the device
1052 * or does the swap chain notify the device of its destruction.
1053 *******************************/
1055 /* Check the params */
1056 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1057 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1058 return WINED3DERR_INVALIDCALL;
1059 } else if (pPresentationParameters->BackBufferCount > 1) {
1060 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");
1063 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1064 if(!object)
1066 ERR("Out of memory\n");
1067 *ppSwapChain = NULL;
1068 return WINED3DERR_OUTOFVIDEOMEMORY;
1071 switch(surface_type) {
1072 case SURFACE_GDI:
1073 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1074 break;
1075 case SURFACE_OPENGL:
1076 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1077 break;
1078 case SURFACE_UNKNOWN:
1079 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1080 HeapFree(GetProcessHeap(), 0, object);
1081 return WINED3DERR_INVALIDCALL;
1083 object->wineD3DDevice = This;
1084 object->parent = parent;
1085 object->ref = 1;
1087 *ppSwapChain = (IWineD3DSwapChain *)object;
1089 /*********************
1090 * Lookup the window Handle and the relating X window handle
1091 ********************/
1093 /* Setup hwnd we are using, plus which display this equates to */
1094 object->win_handle = pPresentationParameters->hDeviceWindow;
1095 if (!object->win_handle) {
1096 object->win_handle = This->createParms.hFocusWindow;
1098 if(!pPresentationParameters->Windowed && object->win_handle) {
1099 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1100 pPresentationParameters->BackBufferWidth,
1101 pPresentationParameters->BackBufferHeight);
1104 hDc = GetDC(object->win_handle);
1105 TRACE("Using hDc %p\n", hDc);
1107 if (NULL == hDc) {
1108 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1109 return WINED3DERR_NOTAVAILABLE;
1112 /* Get info on the current display setup */
1113 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1114 object->orig_width = Mode.Width;
1115 object->orig_height = Mode.Height;
1116 object->orig_fmt = Mode.Format;
1117 format_desc = getFormatDescEntry(Mode.Format, &This->adapter->gl_info);
1119 if (pPresentationParameters->Windowed &&
1120 ((pPresentationParameters->BackBufferWidth == 0) ||
1121 (pPresentationParameters->BackBufferHeight == 0) ||
1122 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1124 RECT Rect;
1125 GetClientRect(object->win_handle, &Rect);
1127 if (pPresentationParameters->BackBufferWidth == 0) {
1128 pPresentationParameters->BackBufferWidth = Rect.right;
1129 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1131 if (pPresentationParameters->BackBufferHeight == 0) {
1132 pPresentationParameters->BackBufferHeight = Rect.bottom;
1133 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1135 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1136 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1137 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1141 /* Put the correct figures in the presentation parameters */
1142 TRACE("Copying across presentation parameters\n");
1143 object->presentParms = *pPresentationParameters;
1145 TRACE("calling rendertarget CB\n");
1146 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1147 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1148 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1149 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1150 if (SUCCEEDED(hr)) {
1151 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1152 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1153 if(surface_type == SURFACE_OPENGL) {
1154 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1156 } else {
1157 ERR("Failed to create the front buffer\n");
1158 goto error;
1161 /*********************
1162 * Windowed / Fullscreen
1163 *******************/
1166 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1167 * so we should really check to see if there is a fullscreen swapchain already
1168 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1169 **************************************/
1171 if (!pPresentationParameters->Windowed) {
1172 WINED3DDISPLAYMODE mode;
1175 /* Change the display settings */
1176 mode.Width = pPresentationParameters->BackBufferWidth;
1177 mode.Height = pPresentationParameters->BackBufferHeight;
1178 mode.Format = pPresentationParameters->BackBufferFormat;
1179 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1181 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1182 displaymode_set = TRUE;
1186 * Create an opengl context for the display visual
1187 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1188 * use different properties after that point in time. FIXME: How to handle when requested format
1189 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1190 * it chooses is identical to the one already being used!
1191 **********************************/
1192 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1194 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1195 if(!object->context) {
1196 ERR("Failed to create the context array\n");
1197 hr = E_OUTOFMEMORY;
1198 goto error;
1200 object->num_contexts = 1;
1202 if (surface_type == SURFACE_OPENGL)
1204 object->context[0] = context_create(This, (IWineD3DSurfaceImpl *)object->frontBuffer,
1205 object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1206 if (!object->context[0]) {
1207 ERR("Failed to create a new context\n");
1208 hr = WINED3DERR_NOTAVAILABLE;
1209 goto error;
1210 } else {
1211 TRACE("Context created (HWND=%p, glContext=%p)\n",
1212 object->win_handle, object->context[0]->glCtx);
1216 /*********************
1217 * Create the back, front and stencil buffers
1218 *******************/
1219 if(object->presentParms.BackBufferCount > 0) {
1220 UINT i;
1222 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1223 if(!object->backBuffer) {
1224 ERR("Out of memory\n");
1225 hr = E_OUTOFMEMORY;
1226 goto error;
1229 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1230 TRACE("calling rendertarget CB\n");
1231 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1232 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1233 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1234 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1235 if(SUCCEEDED(hr)) {
1236 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1237 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1238 } else {
1239 ERR("Cannot create new back buffer\n");
1240 goto error;
1242 if(surface_type == SURFACE_OPENGL) {
1243 ENTER_GL();
1244 glDrawBuffer(GL_BACK);
1245 checkGLcall("glDrawBuffer(GL_BACK)");
1246 LEAVE_GL();
1249 } else {
1250 object->backBuffer = NULL;
1252 /* Single buffering - draw to front buffer */
1253 if(surface_type == SURFACE_OPENGL) {
1254 ENTER_GL();
1255 glDrawBuffer(GL_FRONT);
1256 checkGLcall("glDrawBuffer(GL_FRONT)");
1257 LEAVE_GL();
1261 if (object->context[0]) context_release(object->context[0]);
1263 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1264 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1265 TRACE("Creating depth stencil buffer\n");
1266 if (This->auto_depth_stencil_buffer == NULL ) {
1267 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1268 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1269 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1270 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1271 &This->auto_depth_stencil_buffer);
1272 if (SUCCEEDED(hr)) {
1273 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1274 } else {
1275 ERR("Failed to create the auto depth stencil\n");
1276 goto error;
1281 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1283 TRACE("Created swapchain %p\n", object);
1284 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1285 return WINED3D_OK;
1287 error:
1288 if (displaymode_set) {
1289 DEVMODEW devmode;
1290 RECT clip_rc;
1292 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1293 ClipCursor(NULL);
1295 /* Change the display settings */
1296 memset(&devmode, 0, sizeof(devmode));
1297 devmode.dmSize = sizeof(devmode);
1298 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1299 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1300 devmode.dmPelsWidth = object->orig_width;
1301 devmode.dmPelsHeight = object->orig_height;
1302 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1305 if (object->backBuffer) {
1306 UINT i;
1307 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1308 if (object->backBuffer[i]) IWineD3DSurface_Release(object->backBuffer[i]);
1310 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1311 object->backBuffer = NULL;
1313 if(object->context && object->context[0])
1315 context_release(object->context[0]);
1316 context_destroy(This, object->context[0]);
1318 if (object->frontBuffer) IWineD3DSurface_Release(object->frontBuffer);
1319 HeapFree(GetProcessHeap(), 0, object);
1320 return hr;
1323 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1324 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1326 TRACE("(%p)\n", This);
1328 return This->NumberOfSwapChains;
1331 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1333 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1335 if(iSwapChain < This->NumberOfSwapChains) {
1336 *pSwapChain = This->swapchains[iSwapChain];
1337 IWineD3DSwapChain_AddRef(*pSwapChain);
1338 TRACE("(%p) returning %p\n", This, *pSwapChain);
1339 return WINED3D_OK;
1340 } else {
1341 TRACE("Swapchain out of range\n");
1342 *pSwapChain = NULL;
1343 return WINED3DERR_INVALIDCALL;
1347 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1348 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1349 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1352 IWineD3DVertexDeclarationImpl *object = NULL;
1353 HRESULT hr;
1355 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1356 iface, declaration, parent, elements, element_count);
1358 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1359 if(!object)
1361 ERR("Failed to allocate vertex declaration memory.\n");
1362 return E_OUTOFMEMORY;
1365 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1366 if (FAILED(hr))
1368 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1369 HeapFree(GetProcessHeap(), 0, object);
1370 return hr;
1373 TRACE("Created vertex declaration %p.\n", object);
1374 *declaration = (IWineD3DVertexDeclaration *)object;
1376 return WINED3D_OK;
1379 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1380 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1382 unsigned int idx, idx2;
1383 unsigned int offset;
1384 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1385 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1386 BOOL has_blend_idx = has_blend &&
1387 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1388 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1389 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1390 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1391 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1392 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1393 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1395 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1396 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1397 WINED3DVERTEXELEMENT *elements = NULL;
1399 unsigned int size;
1400 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1401 if (has_blend_idx) num_blends--;
1403 /* Compute declaration size */
1404 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1405 has_psize + has_diffuse + has_specular + num_textures;
1407 /* convert the declaration */
1408 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1409 if (!elements) return ~0U;
1411 idx = 0;
1412 if (has_pos) {
1413 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1414 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1415 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1417 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1418 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1419 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1421 else {
1422 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1423 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1425 elements[idx].usage_idx = 0;
1426 idx++;
1428 if (has_blend && (num_blends > 0)) {
1429 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1430 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1431 else {
1432 switch(num_blends) {
1433 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1434 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1435 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1436 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1437 default:
1438 ERR("Unexpected amount of blend values: %u\n", num_blends);
1441 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1442 elements[idx].usage_idx = 0;
1443 idx++;
1445 if (has_blend_idx) {
1446 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1447 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1448 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1449 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1450 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1451 else
1452 elements[idx].format = WINED3DFMT_R32_FLOAT;
1453 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1454 elements[idx].usage_idx = 0;
1455 idx++;
1457 if (has_normal) {
1458 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1459 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1460 elements[idx].usage_idx = 0;
1461 idx++;
1463 if (has_psize) {
1464 elements[idx].format = WINED3DFMT_R32_FLOAT;
1465 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1466 elements[idx].usage_idx = 0;
1467 idx++;
1469 if (has_diffuse) {
1470 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1471 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1472 elements[idx].usage_idx = 0;
1473 idx++;
1475 if (has_specular) {
1476 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1477 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1478 elements[idx].usage_idx = 1;
1479 idx++;
1481 for (idx2 = 0; idx2 < num_textures; idx2++) {
1482 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1483 switch (numcoords) {
1484 case WINED3DFVF_TEXTUREFORMAT1:
1485 elements[idx].format = WINED3DFMT_R32_FLOAT;
1486 break;
1487 case WINED3DFVF_TEXTUREFORMAT2:
1488 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1489 break;
1490 case WINED3DFVF_TEXTUREFORMAT3:
1491 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1492 break;
1493 case WINED3DFVF_TEXTUREFORMAT4:
1494 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1495 break;
1497 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1498 elements[idx].usage_idx = idx2;
1499 idx++;
1502 /* Now compute offsets, and initialize the rest of the fields */
1503 for (idx = 0, offset = 0; idx < size; ++idx)
1505 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1506 elements[idx].input_slot = 0;
1507 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1508 elements[idx].offset = offset;
1509 offset += format_desc->component_count * format_desc->component_size;
1512 *ppVertexElements = elements;
1513 return size;
1516 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1517 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1518 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1521 WINED3DVERTEXELEMENT *elements;
1522 unsigned int size;
1523 DWORD hr;
1525 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1527 size = ConvertFvfToDeclaration(This, fvf, &elements);
1528 if (size == ~0U) return E_OUTOFMEMORY;
1530 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1531 HeapFree(GetProcessHeap(), 0, elements);
1532 return hr;
1535 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1536 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1537 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1538 const struct wined3d_parent_ops *parent_ops)
1540 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1541 IWineD3DVertexShaderImpl *object;
1542 HRESULT hr;
1544 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1545 if (!object)
1547 ERR("Failed to allocate shader memory.\n");
1548 return E_OUTOFMEMORY;
1551 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1552 if (FAILED(hr))
1554 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1555 HeapFree(GetProcessHeap(), 0, object);
1556 return hr;
1559 TRACE("Created vertex shader %p.\n", object);
1560 *ppVertexShader = (IWineD3DVertexShader *)object;
1562 return WINED3D_OK;
1565 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1566 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1567 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1568 const struct wined3d_parent_ops *parent_ops)
1570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1571 IWineD3DPixelShaderImpl *object;
1572 HRESULT hr;
1574 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1575 if (!object)
1577 ERR("Failed to allocate shader memory.\n");
1578 return E_OUTOFMEMORY;
1581 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1582 if (FAILED(hr))
1584 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1585 HeapFree(GetProcessHeap(), 0, object);
1586 return hr;
1589 TRACE("Created pixel shader %p.\n", object);
1590 *ppPixelShader = (IWineD3DPixelShader *)object;
1592 return WINED3D_OK;
1595 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1596 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1599 IWineD3DPaletteImpl *object;
1600 HRESULT hr;
1601 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1603 /* Create the new object */
1604 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1605 if(!object) {
1606 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1607 return E_OUTOFMEMORY;
1610 object->lpVtbl = &IWineD3DPalette_Vtbl;
1611 object->ref = 1;
1612 object->Flags = Flags;
1613 object->parent = Parent;
1614 object->wineD3DDevice = This;
1615 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1616 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1618 if(!object->hpal) {
1619 HeapFree( GetProcessHeap(), 0, object);
1620 return E_OUTOFMEMORY;
1623 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1624 if(FAILED(hr)) {
1625 IWineD3DPalette_Release((IWineD3DPalette *) object);
1626 return hr;
1629 *Palette = (IWineD3DPalette *) object;
1631 return WINED3D_OK;
1634 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1635 HBITMAP hbm;
1636 BITMAP bm;
1637 HRESULT hr;
1638 HDC dcb = NULL, dcs = NULL;
1639 WINEDDCOLORKEY colorkey;
1641 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1642 if(hbm)
1644 GetObjectA(hbm, sizeof(BITMAP), &bm);
1645 dcb = CreateCompatibleDC(NULL);
1646 if(!dcb) goto out;
1647 SelectObject(dcb, hbm);
1649 else
1651 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1652 * couldn't be loaded
1654 memset(&bm, 0, sizeof(bm));
1655 bm.bmWidth = 32;
1656 bm.bmHeight = 32;
1659 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1660 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1661 NULL, &wined3d_null_parent_ops);
1662 if(FAILED(hr)) {
1663 ERR("Wine logo requested, but failed to create surface\n");
1664 goto out;
1667 if(dcb) {
1668 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1669 if(FAILED(hr)) goto out;
1670 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1671 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1673 colorkey.dwColorSpaceLowValue = 0;
1674 colorkey.dwColorSpaceHighValue = 0;
1675 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1676 } else {
1677 /* Fill the surface with a white color to show that wined3d is there */
1678 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1681 out:
1682 if(dcb) {
1683 DeleteDC(dcb);
1685 if(hbm) {
1686 DeleteObject(hbm);
1688 return;
1691 /* Context activation is done by the caller. */
1692 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1694 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1695 unsigned int i;
1696 /* Under DirectX you can have texture stage operations even if no texture is
1697 bound, whereas opengl will only do texture operations when a valid texture is
1698 bound. We emulate this by creating dummy textures and binding them to each
1699 texture stage, but disable all stages by default. Hence if a stage is enabled
1700 then the default texture will kick in until replaced by a SetTexture call */
1701 ENTER_GL();
1703 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1705 /* The dummy texture does not have client storage backing */
1706 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1707 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1710 for (i = 0; i < gl_info->limits.textures; ++i)
1712 GLubyte white = 255;
1714 /* Make appropriate texture active */
1715 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1716 checkGLcall("glActiveTextureARB");
1718 /* Generate an opengl texture name */
1719 glGenTextures(1, &This->dummyTextureName[i]);
1720 checkGLcall("glGenTextures");
1721 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1723 /* Generate a dummy 2d texture (not using 1d because they cause many
1724 * DRI drivers fall back to sw) */
1725 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1726 checkGLcall("glBindTexture");
1728 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1729 checkGLcall("glTexImage2D");
1732 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1734 /* Reenable because if supported it is enabled by default */
1735 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1736 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1739 LEAVE_GL();
1742 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1743 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1746 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1747 IWineD3DSwapChainImpl *swapchain = NULL;
1748 struct wined3d_context *context;
1749 HRESULT hr;
1750 DWORD state;
1751 unsigned int i;
1753 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1755 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1756 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1758 /* TODO: Test if OpenGL is compiled in and loaded */
1760 TRACE("(%p) : Creating stateblock\n", This);
1761 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1762 hr = IWineD3DDevice_CreateStateBlock(iface,
1763 WINED3DSBT_INIT,
1764 (IWineD3DStateBlock **)&This->stateBlock,
1765 NULL);
1766 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1767 WARN("Failed to create stateblock\n");
1768 goto err_out;
1770 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1771 This->updateStateBlock = This->stateBlock;
1772 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1774 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1775 sizeof(IWineD3DSurface *) * gl_info->limits.buffers);
1776 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1777 sizeof(GLenum) * gl_info->limits.buffers);
1779 This->NumberOfPalettes = 1;
1780 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1781 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1782 ERR("Out of memory!\n");
1783 goto err_out;
1785 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1786 if(!This->palettes[0]) {
1787 ERR("Out of memory!\n");
1788 goto err_out;
1790 for (i = 0; i < 256; ++i) {
1791 This->palettes[0][i].peRed = 0xFF;
1792 This->palettes[0][i].peGreen = 0xFF;
1793 This->palettes[0][i].peBlue = 0xFF;
1794 This->palettes[0][i].peFlags = 0xFF;
1796 This->currentPalette = 0;
1798 /* Initialize the texture unit mapping to a 1:1 mapping */
1799 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1801 if (state < gl_info->limits.fragment_samplers)
1803 This->texUnitMap[state] = state;
1804 This->rev_tex_unit_map[state] = state;
1805 } else {
1806 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1807 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1811 /* Setup the implicit swapchain. This also initializes a context. */
1812 TRACE("Creating implicit swapchain\n");
1813 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1814 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1815 if (FAILED(hr))
1817 WARN("Failed to create implicit swapchain\n");
1818 goto err_out;
1821 This->NumberOfSwapChains = 1;
1822 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1823 if(!This->swapchains) {
1824 ERR("Out of memory!\n");
1825 goto err_out;
1827 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1829 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1830 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1831 This->render_targets[0] = swapchain->backBuffer[0];
1833 else {
1834 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1835 This->render_targets[0] = swapchain->frontBuffer;
1837 IWineD3DSurface_AddRef(This->render_targets[0]);
1839 /* Depth Stencil support */
1840 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1841 if (NULL != This->stencilBufferTarget) {
1842 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1845 hr = This->shader_backend->shader_alloc_private(iface);
1846 if(FAILED(hr)) {
1847 TRACE("Shader private data couldn't be allocated\n");
1848 goto err_out;
1850 hr = This->frag_pipe->alloc_private(iface);
1851 if(FAILED(hr)) {
1852 TRACE("Fragment pipeline private data couldn't be allocated\n");
1853 goto err_out;
1855 hr = This->blitter->alloc_private(iface);
1856 if(FAILED(hr)) {
1857 TRACE("Blitter private data couldn't be allocated\n");
1858 goto err_out;
1861 /* Set up some starting GL setup */
1863 /* Setup all the devices defaults */
1864 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1866 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1868 create_dummy_textures(This);
1870 ENTER_GL();
1872 /* Initialize the current view state */
1873 This->view_ident = 1;
1874 This->contexts[0]->last_was_rhw = 0;
1875 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1876 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1878 switch(wined3d_settings.offscreen_rendering_mode) {
1879 case ORM_FBO:
1880 case ORM_PBUFFER:
1881 This->offscreenBuffer = GL_BACK;
1882 break;
1884 case ORM_BACKBUFFER:
1886 if (context_get_current()->aux_buffers > 0)
1888 TRACE("Using auxilliary buffer for offscreen rendering\n");
1889 This->offscreenBuffer = GL_AUX0;
1890 } else {
1891 TRACE("Using back buffer for offscreen rendering\n");
1892 This->offscreenBuffer = GL_BACK;
1897 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1898 LEAVE_GL();
1900 context_release(context);
1902 /* Clear the screen */
1903 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1904 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1905 0x00, 1.0f, 0);
1907 This->d3d_initialized = TRUE;
1909 if(wined3d_settings.logo) {
1910 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1912 This->highest_dirty_ps_const = 0;
1913 This->highest_dirty_vs_const = 0;
1914 return WINED3D_OK;
1916 err_out:
1917 HeapFree(GetProcessHeap(), 0, This->render_targets);
1918 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1919 HeapFree(GetProcessHeap(), 0, This->swapchains);
1920 This->NumberOfSwapChains = 0;
1921 if(This->palettes) {
1922 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1923 HeapFree(GetProcessHeap(), 0, This->palettes);
1925 This->NumberOfPalettes = 0;
1926 if(swapchain) {
1927 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1929 if(This->stateBlock) {
1930 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1931 This->stateBlock = NULL;
1933 if (This->blit_priv) {
1934 This->blitter->free_private(iface);
1936 if (This->fragment_priv) {
1937 This->frag_pipe->free_private(iface);
1939 if (This->shader_priv) {
1940 This->shader_backend->shader_free_private(iface);
1942 return hr;
1945 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1946 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1949 IWineD3DSwapChainImpl *swapchain = NULL;
1950 HRESULT hr;
1952 /* Setup the implicit swapchain */
1953 TRACE("Creating implicit swapchain\n");
1954 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1955 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1956 if (FAILED(hr))
1958 WARN("Failed to create implicit swapchain\n");
1959 goto err_out;
1962 This->NumberOfSwapChains = 1;
1963 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1964 if(!This->swapchains) {
1965 ERR("Out of memory!\n");
1966 goto err_out;
1968 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1969 return WINED3D_OK;
1971 err_out:
1972 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1973 return hr;
1976 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1978 IWineD3DResource_UnLoad(resource);
1979 IWineD3DResource_Release(resource);
1980 return WINED3D_OK;
1983 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1984 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1987 const struct wined3d_gl_info *gl_info;
1988 struct wined3d_context *context;
1989 int sampler;
1990 UINT i;
1991 TRACE("(%p)\n", This);
1993 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1995 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1996 * it was created. Thus make sure a context is active for the glDelete* calls
1998 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1999 gl_info = context->gl_info;
2001 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2003 /* Unload resources */
2004 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2006 TRACE("Deleting high order patches\n");
2007 for(i = 0; i < PATCHMAP_SIZE; i++) {
2008 struct list *e1, *e2;
2009 struct WineD3DRectPatch *patch;
2010 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2011 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2012 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2016 /* Delete the palette conversion shader if it is around */
2017 if(This->paletteConversionShader) {
2018 ENTER_GL();
2019 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2020 LEAVE_GL();
2021 This->paletteConversionShader = 0;
2024 /* Delete the pbuffer context if there is any */
2025 if(This->pbufferContext) context_destroy(This, This->pbufferContext);
2027 /* Delete the mouse cursor texture */
2028 if(This->cursorTexture) {
2029 ENTER_GL();
2030 glDeleteTextures(1, &This->cursorTexture);
2031 LEAVE_GL();
2032 This->cursorTexture = 0;
2035 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2036 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2038 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2039 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2042 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2043 * private data, it might contain opengl pointers
2045 if(This->depth_blt_texture) {
2046 ENTER_GL();
2047 glDeleteTextures(1, &This->depth_blt_texture);
2048 LEAVE_GL();
2049 This->depth_blt_texture = 0;
2051 if (This->depth_blt_rb) {
2052 ENTER_GL();
2053 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2054 LEAVE_GL();
2055 This->depth_blt_rb = 0;
2056 This->depth_blt_rb_w = 0;
2057 This->depth_blt_rb_h = 0;
2060 /* Release the update stateblock */
2061 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2062 if(This->updateStateBlock != This->stateBlock)
2063 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2065 This->updateStateBlock = NULL;
2067 { /* because were not doing proper internal refcounts releasing the primary state block
2068 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2069 to set this->stateBlock = NULL; first */
2070 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2071 This->stateBlock = NULL;
2073 /* Release the stateblock */
2074 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2075 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2079 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2080 This->blitter->free_private(iface);
2081 This->frag_pipe->free_private(iface);
2082 This->shader_backend->shader_free_private(iface);
2084 /* Release the buffers (with sanity checks)*/
2085 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2086 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2087 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2088 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2090 This->stencilBufferTarget = NULL;
2092 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2093 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2094 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2096 TRACE("Setting rendertarget to NULL\n");
2097 This->render_targets[0] = NULL;
2099 if (This->auto_depth_stencil_buffer) {
2100 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
2102 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2104 This->auto_depth_stencil_buffer = NULL;
2107 context_release(context);
2109 for(i=0; i < This->NumberOfSwapChains; i++) {
2110 TRACE("Releasing the implicit swapchain %d\n", i);
2111 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2112 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2116 HeapFree(GetProcessHeap(), 0, This->swapchains);
2117 This->swapchains = NULL;
2118 This->NumberOfSwapChains = 0;
2120 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2121 HeapFree(GetProcessHeap(), 0, This->palettes);
2122 This->palettes = NULL;
2123 This->NumberOfPalettes = 0;
2125 HeapFree(GetProcessHeap(), 0, This->render_targets);
2126 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2127 This->render_targets = NULL;
2128 This->draw_buffers = NULL;
2130 This->d3d_initialized = FALSE;
2131 return WINED3D_OK;
2134 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2136 unsigned int i;
2138 for(i=0; i < This->NumberOfSwapChains; i++) {
2139 TRACE("Releasing the implicit swapchain %d\n", i);
2140 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2141 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2145 HeapFree(GetProcessHeap(), 0, This->swapchains);
2146 This->swapchains = NULL;
2147 This->NumberOfSwapChains = 0;
2148 return WINED3D_OK;
2151 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2152 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2153 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2155 * There is no way to deactivate thread safety once it is enabled.
2157 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2160 /*For now just store the flag(needed in case of ddraw) */
2161 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2163 return;
2166 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2167 const WINED3DDISPLAYMODE* pMode) {
2168 DEVMODEW devmode;
2169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2170 LONG ret;
2171 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
2172 RECT clip_rc;
2174 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2176 /* Resize the screen even without a window:
2177 * The app could have unset it with SetCooperativeLevel, but not called
2178 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2179 * but we don't have any hwnd
2182 memset(&devmode, 0, sizeof(devmode));
2183 devmode.dmSize = sizeof(devmode);
2184 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2185 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2186 devmode.dmPelsWidth = pMode->Width;
2187 devmode.dmPelsHeight = pMode->Height;
2189 devmode.dmDisplayFrequency = pMode->RefreshRate;
2190 if (pMode->RefreshRate != 0) {
2191 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2194 /* Only change the mode if necessary */
2195 if( (This->ddraw_width == pMode->Width) &&
2196 (This->ddraw_height == pMode->Height) &&
2197 (This->ddraw_format == pMode->Format) &&
2198 (pMode->RefreshRate == 0) ) {
2199 return WINED3D_OK;
2202 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2203 if (ret != DISP_CHANGE_SUCCESSFUL) {
2204 if(devmode.dmDisplayFrequency != 0) {
2205 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2206 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2207 devmode.dmDisplayFrequency = 0;
2208 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2210 if(ret != DISP_CHANGE_SUCCESSFUL) {
2211 return WINED3DERR_NOTAVAILABLE;
2215 /* Store the new values */
2216 This->ddraw_width = pMode->Width;
2217 This->ddraw_height = pMode->Height;
2218 This->ddraw_format = pMode->Format;
2220 /* And finally clip mouse to our screen */
2221 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2222 ClipCursor(&clip_rc);
2224 return WINED3D_OK;
2227 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2229 *ppD3D= This->wineD3D;
2230 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2231 IWineD3D_AddRef(*ppD3D);
2232 return WINED3D_OK;
2235 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2238 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2239 (This->adapter->TextureRam/(1024*1024)),
2240 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2241 /* return simulated texture memory left */
2242 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2245 /*****
2246 * Get / Set Stream Source
2247 *****/
2248 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2249 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2252 IWineD3DBuffer *oldSrc;
2254 if (StreamNumber >= MAX_STREAMS) {
2255 WARN("Stream out of range %d\n", StreamNumber);
2256 return WINED3DERR_INVALIDCALL;
2257 } else if(OffsetInBytes & 0x3) {
2258 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2259 return WINED3DERR_INVALIDCALL;
2262 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2263 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2265 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2267 if(oldSrc == pStreamData &&
2268 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2269 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2270 TRACE("Application is setting the old values over, nothing to do\n");
2271 return WINED3D_OK;
2274 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2275 if (pStreamData) {
2276 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2277 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2280 /* Handle recording of state blocks */
2281 if (This->isRecordingState) {
2282 TRACE("Recording... not performing anything\n");
2283 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2284 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2285 return WINED3D_OK;
2288 if (pStreamData != NULL) {
2289 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2290 IWineD3DBuffer_AddRef(pStreamData);
2292 if (oldSrc != NULL) {
2293 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2294 IWineD3DBuffer_Release(oldSrc);
2297 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2299 return WINED3D_OK;
2302 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2303 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2307 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2308 This->stateBlock->streamSource[StreamNumber],
2309 This->stateBlock->streamOffset[StreamNumber],
2310 This->stateBlock->streamStride[StreamNumber]);
2312 if (StreamNumber >= MAX_STREAMS) {
2313 WARN("Stream out of range %d\n", StreamNumber);
2314 return WINED3DERR_INVALIDCALL;
2316 *pStream = This->stateBlock->streamSource[StreamNumber];
2317 *pStride = This->stateBlock->streamStride[StreamNumber];
2318 if (pOffset) {
2319 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2322 if (*pStream != NULL) {
2323 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2325 return WINED3D_OK;
2328 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2330 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2331 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2333 /* Verify input at least in d3d9 this is invalid*/
2334 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2335 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2336 return WINED3DERR_INVALIDCALL;
2338 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2339 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2340 return WINED3DERR_INVALIDCALL;
2342 if( Divider == 0 ){
2343 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2344 return WINED3DERR_INVALIDCALL;
2347 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2348 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2350 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2351 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2353 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2354 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2355 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2358 return WINED3D_OK;
2361 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2364 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2365 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2367 TRACE("(%p) : returning %d\n", This, *Divider);
2369 return WINED3D_OK;
2372 /*****
2373 * Get / Set & Multiply Transform
2374 *****/
2375 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2378 /* Most of this routine, comments included copied from ddraw tree initially: */
2379 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2381 /* Handle recording of state blocks */
2382 if (This->isRecordingState) {
2383 TRACE("Recording... not performing anything\n");
2384 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2385 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2386 return WINED3D_OK;
2390 * If the new matrix is the same as the current one,
2391 * we cut off any further processing. this seems to be a reasonable
2392 * optimization because as was noticed, some apps (warcraft3 for example)
2393 * tend towards setting the same matrix repeatedly for some reason.
2395 * From here on we assume that the new matrix is different, wherever it matters.
2397 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2398 TRACE("The app is setting the same matrix over again\n");
2399 return WINED3D_OK;
2400 } else {
2401 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2405 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2406 where ViewMat = Camera space, WorldMat = world space.
2408 In OpenGL, camera and world space is combined into GL_MODELVIEW
2409 matrix. The Projection matrix stay projection matrix.
2412 /* Capture the times we can just ignore the change for now */
2413 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2414 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2415 /* Handled by the state manager */
2418 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2419 return WINED3D_OK;
2422 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2424 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2425 *pMatrix = This->stateBlock->transforms[State];
2426 return WINED3D_OK;
2429 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2430 const WINED3DMATRIX *mat = NULL;
2431 WINED3DMATRIX temp;
2433 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2434 * below means it will be recorded in a state block change, but it
2435 * works regardless where it is recorded.
2436 * If this is found to be wrong, change to StateBlock.
2438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2439 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2441 if (State <= HIGHEST_TRANSFORMSTATE)
2443 mat = &This->updateStateBlock->transforms[State];
2444 } else {
2445 FIXME("Unhandled transform state!!\n");
2448 multiply_matrix(&temp, mat, pMatrix);
2450 /* Apply change via set transform - will reapply to eg. lights this way */
2451 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2454 /*****
2455 * Get / Set Light
2456 *****/
2457 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2458 you can reference any indexes you want as long as that number max are enabled at any
2459 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2460 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2461 but when recording, just build a chain pretty much of commands to be replayed. */
2463 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2464 float rho;
2465 struct wined3d_light_info *object = NULL;
2466 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2467 struct list *e;
2469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2470 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2472 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2473 * the gl driver.
2475 if(!pLight) {
2476 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2477 return WINED3DERR_INVALIDCALL;
2480 switch(pLight->Type) {
2481 case WINED3DLIGHT_POINT:
2482 case WINED3DLIGHT_SPOT:
2483 case WINED3DLIGHT_PARALLELPOINT:
2484 case WINED3DLIGHT_GLSPOT:
2485 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2486 * most wanted
2488 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2490 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2491 return WINED3DERR_INVALIDCALL;
2493 break;
2495 case WINED3DLIGHT_DIRECTIONAL:
2496 /* Ignores attenuation */
2497 break;
2499 default:
2500 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2501 return WINED3DERR_INVALIDCALL;
2504 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2506 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2507 if(object->OriginalIndex == Index) break;
2508 object = NULL;
2511 if(!object) {
2512 TRACE("Adding new light\n");
2513 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2514 if(!object) {
2515 ERR("Out of memory error when allocating a light\n");
2516 return E_OUTOFMEMORY;
2518 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2519 object->glIndex = -1;
2520 object->OriginalIndex = Index;
2523 /* Initialize the object */
2524 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,
2525 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2526 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2527 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2528 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2529 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2530 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2532 /* Save away the information */
2533 object->OriginalParms = *pLight;
2535 switch (pLight->Type) {
2536 case WINED3DLIGHT_POINT:
2537 /* Position */
2538 object->lightPosn[0] = pLight->Position.x;
2539 object->lightPosn[1] = pLight->Position.y;
2540 object->lightPosn[2] = pLight->Position.z;
2541 object->lightPosn[3] = 1.0f;
2542 object->cutoff = 180.0f;
2543 /* FIXME: Range */
2544 break;
2546 case WINED3DLIGHT_DIRECTIONAL:
2547 /* Direction */
2548 object->lightPosn[0] = -pLight->Direction.x;
2549 object->lightPosn[1] = -pLight->Direction.y;
2550 object->lightPosn[2] = -pLight->Direction.z;
2551 object->lightPosn[3] = 0.0f;
2552 object->exponent = 0.0f;
2553 object->cutoff = 180.0f;
2554 break;
2556 case WINED3DLIGHT_SPOT:
2557 /* Position */
2558 object->lightPosn[0] = pLight->Position.x;
2559 object->lightPosn[1] = pLight->Position.y;
2560 object->lightPosn[2] = pLight->Position.z;
2561 object->lightPosn[3] = 1.0f;
2563 /* Direction */
2564 object->lightDirn[0] = pLight->Direction.x;
2565 object->lightDirn[1] = pLight->Direction.y;
2566 object->lightDirn[2] = pLight->Direction.z;
2567 object->lightDirn[3] = 1.0f;
2570 * opengl-ish and d3d-ish spot lights use too different models for the
2571 * light "intensity" as a function of the angle towards the main light direction,
2572 * so we only can approximate very roughly.
2573 * however spot lights are rather rarely used in games (if ever used at all).
2574 * furthermore if still used, probably nobody pays attention to such details.
2576 if (pLight->Falloff == 0) {
2577 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2578 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2579 * will always be 1.0 for both of them, and we don't have to care for the
2580 * rest of the rather complex calculation
2582 object->exponent = 0.0f;
2583 } else {
2584 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2585 if (rho < 0.0001f) rho = 0.0001f;
2586 object->exponent = -0.3f/logf(cosf(rho/2));
2588 if (object->exponent > 128.0f)
2590 object->exponent = 128.0f;
2592 object->cutoff = pLight->Phi*90/M_PI;
2594 /* FIXME: Range */
2595 break;
2597 default:
2598 FIXME("Unrecognized light type %d\n", pLight->Type);
2601 /* Update the live definitions if the light is currently assigned a glIndex */
2602 if (object->glIndex != -1 && !This->isRecordingState) {
2603 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2605 return WINED3D_OK;
2608 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2610 struct wined3d_light_info *lightInfo = NULL;
2611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2612 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2613 struct list *e;
2614 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2616 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2618 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2619 if(lightInfo->OriginalIndex == Index) break;
2620 lightInfo = NULL;
2623 if (lightInfo == NULL) {
2624 TRACE("Light information requested but light not defined\n");
2625 return WINED3DERR_INVALIDCALL;
2628 *pLight = lightInfo->OriginalParms;
2629 return WINED3D_OK;
2632 /*****
2633 * Get / Set Light Enable
2634 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2635 *****/
2636 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2638 struct wined3d_light_info *lightInfo = NULL;
2639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2640 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2641 struct list *e;
2642 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2644 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2646 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2647 if(lightInfo->OriginalIndex == Index) break;
2648 lightInfo = NULL;
2650 TRACE("Found light: %p\n", lightInfo);
2652 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2653 if (lightInfo == NULL) {
2655 TRACE("Light enabled requested but light not defined, so defining one!\n");
2656 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2658 /* Search for it again! Should be fairly quick as near head of list */
2659 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2661 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2662 if(lightInfo->OriginalIndex == Index) break;
2663 lightInfo = NULL;
2665 if (lightInfo == NULL) {
2666 FIXME("Adding default lights has failed dismally\n");
2667 return WINED3DERR_INVALIDCALL;
2671 if(!Enable) {
2672 if(lightInfo->glIndex != -1) {
2673 if(!This->isRecordingState) {
2674 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2677 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2678 lightInfo->glIndex = -1;
2679 } else {
2680 TRACE("Light already disabled, nothing to do\n");
2682 lightInfo->enabled = FALSE;
2683 } else {
2684 lightInfo->enabled = TRUE;
2685 if (lightInfo->glIndex != -1) {
2686 /* nop */
2687 TRACE("Nothing to do as light was enabled\n");
2688 } else {
2689 int i;
2690 /* Find a free gl light */
2691 for(i = 0; i < This->maxConcurrentLights; i++) {
2692 if(This->updateStateBlock->activeLights[i] == NULL) {
2693 This->updateStateBlock->activeLights[i] = lightInfo;
2694 lightInfo->glIndex = i;
2695 break;
2698 if(lightInfo->glIndex == -1) {
2699 /* Our tests show that Windows returns D3D_OK in this situation, even with
2700 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2701 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2702 * as well for those lights.
2704 * TODO: Test how this affects rendering
2706 WARN("Too many concurrently active lights\n");
2707 return WINED3D_OK;
2710 /* i == lightInfo->glIndex */
2711 if(!This->isRecordingState) {
2712 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2717 return WINED3D_OK;
2720 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2722 struct wined3d_light_info *lightInfo = NULL;
2723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2724 struct list *e;
2725 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2726 TRACE("(%p) : for idx(%d)\n", This, Index);
2728 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2730 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2731 if(lightInfo->OriginalIndex == Index) break;
2732 lightInfo = NULL;
2735 if (lightInfo == NULL) {
2736 TRACE("Light enabled state requested but light not defined\n");
2737 return WINED3DERR_INVALIDCALL;
2739 /* true is 128 according to SetLightEnable */
2740 *pEnable = lightInfo->enabled ? 128 : 0;
2741 return WINED3D_OK;
2744 /*****
2745 * Get / Set Clip Planes
2746 *****/
2747 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2748 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2749 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2751 /* Validate Index */
2752 if (Index >= This->adapter->gl_info.limits.clipplanes)
2754 TRACE("Application has requested clipplane this device doesn't support\n");
2755 return WINED3DERR_INVALIDCALL;
2758 This->updateStateBlock->changed.clipplane |= 1 << Index;
2760 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2761 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2762 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2763 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2764 TRACE("Application is setting old values over, nothing to do\n");
2765 return WINED3D_OK;
2768 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2769 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2770 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2771 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2773 /* Handle recording of state blocks */
2774 if (This->isRecordingState) {
2775 TRACE("Recording... not performing anything\n");
2776 return WINED3D_OK;
2779 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2781 return WINED3D_OK;
2784 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2786 TRACE("(%p) : for idx %d\n", This, Index);
2788 /* Validate Index */
2789 if (Index >= This->adapter->gl_info.limits.clipplanes)
2791 TRACE("Application has requested clipplane this device doesn't support\n");
2792 return WINED3DERR_INVALIDCALL;
2795 pPlane[0] = This->stateBlock->clipplane[Index][0];
2796 pPlane[1] = This->stateBlock->clipplane[Index][1];
2797 pPlane[2] = This->stateBlock->clipplane[Index][2];
2798 pPlane[3] = This->stateBlock->clipplane[Index][3];
2799 return WINED3D_OK;
2802 /*****
2803 * Get / Set Clip Plane Status
2804 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2805 *****/
2806 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2808 FIXME("(%p) : stub\n", This);
2809 if (NULL == pClipStatus) {
2810 return WINED3DERR_INVALIDCALL;
2812 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2813 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2814 return WINED3D_OK;
2817 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2819 FIXME("(%p) : stub\n", This);
2820 if (NULL == pClipStatus) {
2821 return WINED3DERR_INVALIDCALL;
2823 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2824 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2825 return WINED3D_OK;
2828 /*****
2829 * Get / Set Material
2830 *****/
2831 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2834 This->updateStateBlock->changed.material = TRUE;
2835 This->updateStateBlock->material = *pMaterial;
2837 /* Handle recording of state blocks */
2838 if (This->isRecordingState) {
2839 TRACE("Recording... not performing anything\n");
2840 return WINED3D_OK;
2843 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2844 return WINED3D_OK;
2847 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2849 *pMaterial = This->updateStateBlock->material;
2850 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2851 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2852 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2853 pMaterial->Ambient.b, pMaterial->Ambient.a);
2854 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2855 pMaterial->Specular.b, pMaterial->Specular.a);
2856 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2857 pMaterial->Emissive.b, pMaterial->Emissive.a);
2858 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2860 return WINED3D_OK;
2863 /*****
2864 * Get / Set Indices
2865 *****/
2866 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2867 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2870 IWineD3DBuffer *oldIdxs;
2872 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2873 oldIdxs = This->updateStateBlock->pIndexData;
2875 This->updateStateBlock->changed.indices = TRUE;
2876 This->updateStateBlock->pIndexData = pIndexData;
2877 This->updateStateBlock->IndexFmt = fmt;
2879 /* Handle recording of state blocks */
2880 if (This->isRecordingState) {
2881 TRACE("Recording... not performing anything\n");
2882 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2883 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2884 return WINED3D_OK;
2887 if(oldIdxs != pIndexData) {
2888 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2889 if(pIndexData) {
2890 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2891 IWineD3DBuffer_AddRef(pIndexData);
2893 if(oldIdxs) {
2894 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2895 IWineD3DBuffer_Release(oldIdxs);
2899 return WINED3D_OK;
2902 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2906 *ppIndexData = This->stateBlock->pIndexData;
2908 /* up ref count on ppindexdata */
2909 if (*ppIndexData) {
2910 IWineD3DBuffer_AddRef(*ppIndexData);
2911 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2912 }else{
2913 TRACE("(%p) No index data set\n", This);
2915 TRACE("Returning %p\n", *ppIndexData);
2917 return WINED3D_OK;
2920 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2921 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2923 TRACE("(%p)->(%d)\n", This, BaseIndex);
2925 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2926 TRACE("Application is setting the old value over, nothing to do\n");
2927 return WINED3D_OK;
2930 This->updateStateBlock->baseVertexIndex = BaseIndex;
2932 if (This->isRecordingState) {
2933 TRACE("Recording... not performing anything\n");
2934 return WINED3D_OK;
2936 /* The base vertex index affects the stream sources */
2937 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2938 return WINED3D_OK;
2941 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2943 TRACE("(%p) : base_index %p\n", This, base_index);
2945 *base_index = This->stateBlock->baseVertexIndex;
2947 TRACE("Returning %u\n", *base_index);
2949 return WINED3D_OK;
2952 /*****
2953 * Get / Set Viewports
2954 *****/
2955 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2958 TRACE("(%p)\n", This);
2959 This->updateStateBlock->changed.viewport = TRUE;
2960 This->updateStateBlock->viewport = *pViewport;
2962 /* Handle recording of state blocks */
2963 if (This->isRecordingState) {
2964 TRACE("Recording... not performing anything\n");
2965 return WINED3D_OK;
2968 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2969 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2971 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2972 return WINED3D_OK;
2976 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2978 TRACE("(%p)\n", This);
2979 *pViewport = This->stateBlock->viewport;
2980 return WINED3D_OK;
2983 /*****
2984 * Get / Set Render States
2985 * TODO: Verify against dx9 definitions
2986 *****/
2987 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2989 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2990 DWORD oldValue = This->stateBlock->renderState[State];
2992 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2994 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2995 This->updateStateBlock->renderState[State] = Value;
2997 /* Handle recording of state blocks */
2998 if (This->isRecordingState) {
2999 TRACE("Recording... not performing anything\n");
3000 return WINED3D_OK;
3003 /* Compared here and not before the assignment to allow proper stateblock recording */
3004 if(Value == oldValue) {
3005 TRACE("Application is setting the old value over, nothing to do\n");
3006 } else {
3007 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3010 return WINED3D_OK;
3013 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3015 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3016 *pValue = This->stateBlock->renderState[State];
3017 return WINED3D_OK;
3020 /*****
3021 * Get / Set Sampler States
3022 * TODO: Verify against dx9 definitions
3023 *****/
3025 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3027 DWORD oldValue;
3029 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3030 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3032 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3033 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3036 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3037 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3038 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3041 * SetSampler is designed to allow for more than the standard up to 8 textures
3042 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3043 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3045 * http://developer.nvidia.com/object/General_FAQ.html#t6
3047 * There are two new settings for GForce
3048 * the sampler one:
3049 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3050 * and the texture one:
3051 * GL_MAX_TEXTURE_COORDS_ARB.
3052 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3053 ******************/
3055 oldValue = This->stateBlock->samplerState[Sampler][Type];
3056 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3057 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3059 /* Handle recording of state blocks */
3060 if (This->isRecordingState) {
3061 TRACE("Recording... not performing anything\n");
3062 return WINED3D_OK;
3065 if(oldValue == Value) {
3066 TRACE("Application is setting the old value over, nothing to do\n");
3067 return WINED3D_OK;
3070 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3072 return WINED3D_OK;
3075 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3078 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3079 This, Sampler, debug_d3dsamplerstate(Type), Type);
3081 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3082 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3085 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3086 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3087 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3089 *Value = This->stateBlock->samplerState[Sampler][Type];
3090 TRACE("(%p) : Returning %#x\n", This, *Value);
3092 return WINED3D_OK;
3095 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3098 This->updateStateBlock->changed.scissorRect = TRUE;
3099 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3100 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3101 return WINED3D_OK;
3103 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3105 if(This->isRecordingState) {
3106 TRACE("Recording... not performing anything\n");
3107 return WINED3D_OK;
3110 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3112 return WINED3D_OK;
3115 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3118 *pRect = This->updateStateBlock->scissorRect;
3119 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3120 return WINED3D_OK;
3123 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3125 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3127 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3129 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3130 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3132 This->updateStateBlock->vertexDecl = pDecl;
3133 This->updateStateBlock->changed.vertexDecl = TRUE;
3135 if (This->isRecordingState) {
3136 TRACE("Recording... not performing anything\n");
3137 return WINED3D_OK;
3138 } else if(pDecl == oldDecl) {
3139 /* Checked after the assignment to allow proper stateblock recording */
3140 TRACE("Application is setting the old declaration over, nothing to do\n");
3141 return WINED3D_OK;
3144 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3145 return WINED3D_OK;
3148 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3151 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3153 *ppDecl = This->stateBlock->vertexDecl;
3154 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3155 return WINED3D_OK;
3158 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3160 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3162 This->updateStateBlock->vertexShader = pShader;
3163 This->updateStateBlock->changed.vertexShader = TRUE;
3165 if (This->isRecordingState) {
3166 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3167 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3168 TRACE("Recording... not performing anything\n");
3169 return WINED3D_OK;
3170 } else if(oldShader == pShader) {
3171 /* Checked here to allow proper stateblock recording */
3172 TRACE("App is setting the old shader over, nothing to do\n");
3173 return WINED3D_OK;
3176 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3177 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3178 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3180 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3182 return WINED3D_OK;
3185 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3188 if (NULL == ppShader) {
3189 return WINED3DERR_INVALIDCALL;
3191 *ppShader = This->stateBlock->vertexShader;
3192 if( NULL != *ppShader)
3193 IWineD3DVertexShader_AddRef(*ppShader);
3195 TRACE("(%p) : returning %p\n", This, *ppShader);
3196 return WINED3D_OK;
3199 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3200 IWineD3DDevice *iface,
3201 UINT start,
3202 CONST BOOL *srcData,
3203 UINT count) {
3205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3206 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3208 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3209 iface, srcData, start, count);
3211 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3213 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3214 for (i = 0; i < cnt; i++)
3215 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3217 for (i = start; i < cnt + start; ++i) {
3218 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3221 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3223 return WINED3D_OK;
3226 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3227 IWineD3DDevice *iface,
3228 UINT start,
3229 BOOL *dstData,
3230 UINT count) {
3232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3233 int cnt = min(count, MAX_CONST_B - start);
3235 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3236 iface, dstData, start, count);
3238 if (dstData == NULL || cnt < 0)
3239 return WINED3DERR_INVALIDCALL;
3241 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3242 return WINED3D_OK;
3245 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3246 IWineD3DDevice *iface,
3247 UINT start,
3248 CONST int *srcData,
3249 UINT count) {
3251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3252 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3254 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3255 iface, srcData, start, count);
3257 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3259 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3260 for (i = 0; i < cnt; i++)
3261 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3262 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3264 for (i = start; i < cnt + start; ++i) {
3265 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3268 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3270 return WINED3D_OK;
3273 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3274 IWineD3DDevice *iface,
3275 UINT start,
3276 int *dstData,
3277 UINT count) {
3279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3280 int cnt = min(count, MAX_CONST_I - start);
3282 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3283 iface, dstData, start, count);
3285 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3286 return WINED3DERR_INVALIDCALL;
3288 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3289 return WINED3D_OK;
3292 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3293 IWineD3DDevice *iface,
3294 UINT start,
3295 CONST float *srcData,
3296 UINT count) {
3298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3299 UINT i;
3301 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3302 iface, srcData, start, count);
3304 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3305 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3306 return WINED3DERR_INVALIDCALL;
3308 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3309 if(TRACE_ON(d3d)) {
3310 for (i = 0; i < count; i++)
3311 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3312 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3315 if (!This->isRecordingState)
3317 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3318 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3321 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3322 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3324 return WINED3D_OK;
3327 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3328 IWineD3DDevice *iface,
3329 UINT start,
3330 float *dstData,
3331 UINT count) {
3333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3334 int cnt = min(count, This->d3d_vshader_constantF - start);
3336 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3337 iface, dstData, start, count);
3339 if (dstData == NULL || cnt < 0)
3340 return WINED3DERR_INVALIDCALL;
3342 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3343 return WINED3D_OK;
3346 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3347 DWORD i;
3348 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3350 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3354 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3356 DWORD i = This->rev_tex_unit_map[unit];
3357 DWORD j = This->texUnitMap[stage];
3359 This->texUnitMap[stage] = unit;
3360 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3362 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3365 This->rev_tex_unit_map[unit] = stage;
3366 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3368 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3372 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3373 int i;
3375 This->fixed_function_usage_map = 0;
3376 for (i = 0; i < MAX_TEXTURES; ++i) {
3377 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3378 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3379 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3380 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3381 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3382 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3383 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3384 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3386 if (color_op == WINED3DTOP_DISABLE) {
3387 /* Not used, and disable higher stages */
3388 break;
3391 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3392 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3393 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3394 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3395 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3396 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3397 This->fixed_function_usage_map |= (1 << i);
3400 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3401 This->fixed_function_usage_map |= (1 << (i + 1));
3406 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3407 unsigned int i, tex;
3408 WORD ffu_map;
3410 device_update_fixed_function_usage_map(This);
3411 ffu_map = This->fixed_function_usage_map;
3413 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3414 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3415 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3417 if (!(ffu_map & 1)) continue;
3419 if (This->texUnitMap[i] != i) {
3420 device_map_stage(This, i, i);
3421 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3422 markTextureStagesDirty(This, i);
3425 return;
3428 /* Now work out the mapping */
3429 tex = 0;
3430 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3432 if (!(ffu_map & 1)) continue;
3434 if (This->texUnitMap[i] != tex) {
3435 device_map_stage(This, i, tex);
3436 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3437 markTextureStagesDirty(This, i);
3440 ++tex;
3444 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3445 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3446 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3447 unsigned int i;
3449 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3450 if (sampler_type[i] && This->texUnitMap[i] != i)
3452 device_map_stage(This, i, i);
3453 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3454 if (i < MAX_TEXTURES) {
3455 markTextureStagesDirty(This, i);
3461 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3462 const DWORD *vshader_sampler_tokens, DWORD unit)
3464 DWORD current_mapping = This->rev_tex_unit_map[unit];
3466 /* Not currently used */
3467 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3469 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3470 /* Used by a fragment sampler */
3472 if (!pshader_sampler_tokens) {
3473 /* No pixel shader, check fixed function */
3474 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3477 /* Pixel shader, check the shader's sampler map */
3478 return !pshader_sampler_tokens[current_mapping];
3481 /* Used by a vertex sampler */
3482 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3485 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3486 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3487 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3488 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3489 int start = min(MAX_COMBINED_SAMPLERS, This->adapter->gl_info.limits.combined_samplers) - 1;
3490 int i;
3492 if (ps) {
3493 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3495 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3496 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3497 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3500 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3501 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3502 if (vshader_sampler_type[i])
3504 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3506 /* Already mapped somewhere */
3507 continue;
3510 while (start >= 0) {
3511 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3513 device_map_stage(This, vsampler_idx, start);
3514 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3516 --start;
3517 break;
3520 --start;
3526 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3527 BOOL vs = use_vs(This->stateBlock);
3528 BOOL ps = use_ps(This->stateBlock);
3530 * Rules are:
3531 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3532 * that would be really messy and require shader recompilation
3533 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3534 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3536 if (ps) {
3537 device_map_psamplers(This);
3538 } else {
3539 device_map_fixed_function_samplers(This);
3542 if (vs) {
3543 device_map_vsamplers(This, ps);
3547 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3549 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3550 This->updateStateBlock->pixelShader = pShader;
3551 This->updateStateBlock->changed.pixelShader = TRUE;
3553 /* Handle recording of state blocks */
3554 if (This->isRecordingState) {
3555 TRACE("Recording... not performing anything\n");
3558 if (This->isRecordingState) {
3559 TRACE("Recording... not performing anything\n");
3560 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3561 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3562 return WINED3D_OK;
3565 if(pShader == oldShader) {
3566 TRACE("App is setting the old pixel shader over, nothing to do\n");
3567 return WINED3D_OK;
3570 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3571 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3573 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3574 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3576 return WINED3D_OK;
3579 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3582 if (NULL == ppShader) {
3583 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3584 return WINED3DERR_INVALIDCALL;
3587 *ppShader = This->stateBlock->pixelShader;
3588 if (NULL != *ppShader) {
3589 IWineD3DPixelShader_AddRef(*ppShader);
3591 TRACE("(%p) : returning %p\n", This, *ppShader);
3592 return WINED3D_OK;
3595 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3596 IWineD3DDevice *iface,
3597 UINT start,
3598 CONST BOOL *srcData,
3599 UINT count) {
3601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3602 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3604 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3605 iface, srcData, start, count);
3607 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3609 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3610 for (i = 0; i < cnt; i++)
3611 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3613 for (i = start; i < cnt + start; ++i) {
3614 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3617 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3619 return WINED3D_OK;
3622 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3623 IWineD3DDevice *iface,
3624 UINT start,
3625 BOOL *dstData,
3626 UINT count) {
3628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3629 int cnt = min(count, MAX_CONST_B - start);
3631 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3632 iface, dstData, start, count);
3634 if (dstData == NULL || cnt < 0)
3635 return WINED3DERR_INVALIDCALL;
3637 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3638 return WINED3D_OK;
3641 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3642 IWineD3DDevice *iface,
3643 UINT start,
3644 CONST int *srcData,
3645 UINT count) {
3647 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3648 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3650 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3651 iface, srcData, start, count);
3653 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3655 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3656 for (i = 0; i < cnt; i++)
3657 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3658 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3660 for (i = start; i < cnt + start; ++i) {
3661 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3664 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3666 return WINED3D_OK;
3669 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3670 IWineD3DDevice *iface,
3671 UINT start,
3672 int *dstData,
3673 UINT count) {
3675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3676 int cnt = min(count, MAX_CONST_I - start);
3678 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3679 iface, dstData, start, count);
3681 if (dstData == NULL || cnt < 0)
3682 return WINED3DERR_INVALIDCALL;
3684 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3685 return WINED3D_OK;
3688 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3689 IWineD3DDevice *iface,
3690 UINT start,
3691 CONST float *srcData,
3692 UINT count) {
3694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3695 UINT i;
3697 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3698 iface, srcData, start, count);
3700 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3701 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3702 return WINED3DERR_INVALIDCALL;
3704 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3705 if(TRACE_ON(d3d)) {
3706 for (i = 0; i < count; i++)
3707 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3708 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3711 if (!This->isRecordingState)
3713 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3714 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3717 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3718 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3720 return WINED3D_OK;
3723 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3724 IWineD3DDevice *iface,
3725 UINT start,
3726 float *dstData,
3727 UINT count) {
3729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3730 int cnt = min(count, This->d3d_pshader_constantF - start);
3732 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3733 iface, dstData, start, count);
3735 if (dstData == NULL || cnt < 0)
3736 return WINED3DERR_INVALIDCALL;
3738 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3739 return WINED3D_OK;
3742 /* Context activation is done by the caller. */
3743 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3744 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3745 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3746 DWORD DestFVF)
3748 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3749 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3750 unsigned int i;
3751 WINED3DVIEWPORT vp;
3752 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3753 BOOL doClip;
3754 DWORD numTextures;
3756 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3758 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3761 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3763 ERR("Source has no position mask\n");
3764 return WINED3DERR_INVALIDCALL;
3767 /* We might access VBOs from this code, so hold the lock */
3768 ENTER_GL();
3770 if (dest->resource.allocatedMemory == NULL) {
3771 buffer_get_sysmem(dest);
3774 /* Get a pointer into the destination vbo(create one if none exists) and
3775 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3777 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3779 dest->flags |= WINED3D_BUFFER_CREATEBO;
3780 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3783 if (dest->buffer_object)
3785 unsigned char extrabytes = 0;
3786 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3787 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3788 * this may write 4 extra bytes beyond the area that should be written
3790 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3791 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3792 if(!dest_conv_addr) {
3793 ERR("Out of memory\n");
3794 /* Continue without storing converted vertices */
3796 dest_conv = dest_conv_addr;
3799 /* Should I clip?
3800 * a) WINED3DRS_CLIPPING is enabled
3801 * b) WINED3DVOP_CLIP is passed
3803 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3804 static BOOL warned = FALSE;
3806 * The clipping code is not quite correct. Some things need
3807 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3808 * so disable clipping for now.
3809 * (The graphics in Half-Life are broken, and my processvertices
3810 * test crashes with IDirect3DDevice3)
3811 doClip = TRUE;
3813 doClip = FALSE;
3814 if(!warned) {
3815 warned = TRUE;
3816 FIXME("Clipping is broken and disabled for now\n");
3818 } else doClip = FALSE;
3819 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3821 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3822 WINED3DTS_VIEW,
3823 &view_mat);
3824 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3825 WINED3DTS_PROJECTION,
3826 &proj_mat);
3827 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3828 WINED3DTS_WORLDMATRIX(0),
3829 &world_mat);
3831 TRACE("View mat:\n");
3832 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);
3833 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);
3834 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);
3835 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);
3837 TRACE("Proj mat:\n");
3838 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);
3839 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);
3840 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);
3841 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);
3843 TRACE("World mat:\n");
3844 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);
3845 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);
3846 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);
3847 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);
3849 /* Get the viewport */
3850 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3851 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3852 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3854 multiply_matrix(&mat,&view_mat,&world_mat);
3855 multiply_matrix(&mat,&proj_mat,&mat);
3857 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3859 for (i = 0; i < dwCount; i+= 1) {
3860 unsigned int tex_index;
3862 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3863 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3864 /* The position first */
3865 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3866 const float *p = (const float *)(element->data + i * element->stride);
3867 float x, y, z, rhw;
3868 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3870 /* Multiplication with world, view and projection matrix */
3871 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);
3872 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);
3873 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);
3874 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);
3876 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3878 /* WARNING: The following things are taken from d3d7 and were not yet checked
3879 * against d3d8 or d3d9!
3882 /* Clipping conditions: From msdn
3884 * A vertex is clipped if it does not match the following requirements
3885 * -rhw < x <= rhw
3886 * -rhw < y <= rhw
3887 * 0 < z <= rhw
3888 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3890 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3891 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3895 if( !doClip ||
3896 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3897 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3898 ( rhw > eps ) ) ) {
3900 /* "Normal" viewport transformation (not clipped)
3901 * 1) The values are divided by rhw
3902 * 2) The y axis is negative, so multiply it with -1
3903 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3904 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3905 * 4) Multiply x with Width/2 and add Width/2
3906 * 5) The same for the height
3907 * 6) Add the viewpoint X and Y to the 2D coordinates and
3908 * The minimum Z value to z
3909 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3911 * Well, basically it's simply a linear transformation into viewport
3912 * coordinates
3915 x /= rhw;
3916 y /= rhw;
3917 z /= rhw;
3919 y *= -1;
3921 x *= vp.Width / 2;
3922 y *= vp.Height / 2;
3923 z *= vp.MaxZ - vp.MinZ;
3925 x += vp.Width / 2 + vp.X;
3926 y += vp.Height / 2 + vp.Y;
3927 z += vp.MinZ;
3929 rhw = 1 / rhw;
3930 } else {
3931 /* That vertex got clipped
3932 * Contrary to OpenGL it is not dropped completely, it just
3933 * undergoes a different calculation.
3935 TRACE("Vertex got clipped\n");
3936 x += rhw;
3937 y += rhw;
3939 x /= 2;
3940 y /= 2;
3942 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3943 * outside of the main vertex buffer memory. That needs some more
3944 * investigation...
3948 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3951 ( (float *) dest_ptr)[0] = x;
3952 ( (float *) dest_ptr)[1] = y;
3953 ( (float *) dest_ptr)[2] = z;
3954 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3956 dest_ptr += 3 * sizeof(float);
3958 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3959 dest_ptr += sizeof(float);
3962 if(dest_conv) {
3963 float w = 1 / rhw;
3964 ( (float *) dest_conv)[0] = x * w;
3965 ( (float *) dest_conv)[1] = y * w;
3966 ( (float *) dest_conv)[2] = z * w;
3967 ( (float *) dest_conv)[3] = w;
3969 dest_conv += 3 * sizeof(float);
3971 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3972 dest_conv += sizeof(float);
3976 if (DestFVF & WINED3DFVF_PSIZE) {
3977 dest_ptr += sizeof(DWORD);
3978 if(dest_conv) dest_conv += sizeof(DWORD);
3980 if (DestFVF & WINED3DFVF_NORMAL) {
3981 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3982 const float *normal = (const float *)(element->data + i * element->stride);
3983 /* AFAIK this should go into the lighting information */
3984 FIXME("Didn't expect the destination to have a normal\n");
3985 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3986 if(dest_conv) {
3987 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3991 if (DestFVF & WINED3DFVF_DIFFUSE) {
3992 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3993 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3994 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3996 static BOOL warned = FALSE;
3998 if(!warned) {
3999 ERR("No diffuse color in source, but destination has one\n");
4000 warned = TRUE;
4003 *( (DWORD *) dest_ptr) = 0xffffffff;
4004 dest_ptr += sizeof(DWORD);
4006 if(dest_conv) {
4007 *( (DWORD *) dest_conv) = 0xffffffff;
4008 dest_conv += sizeof(DWORD);
4011 else {
4012 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4013 if(dest_conv) {
4014 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4015 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4016 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4017 dest_conv += sizeof(DWORD);
4022 if (DestFVF & WINED3DFVF_SPECULAR)
4024 /* What's the color value in the feedback buffer? */
4025 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4026 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4027 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4029 static BOOL warned = FALSE;
4031 if(!warned) {
4032 ERR("No specular color in source, but destination has one\n");
4033 warned = TRUE;
4036 *( (DWORD *) dest_ptr) = 0xFF000000;
4037 dest_ptr += sizeof(DWORD);
4039 if(dest_conv) {
4040 *( (DWORD *) dest_conv) = 0xFF000000;
4041 dest_conv += sizeof(DWORD);
4044 else {
4045 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4046 if(dest_conv) {
4047 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4048 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4049 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4050 dest_conv += sizeof(DWORD);
4055 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4056 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4057 const float *tex_coord = (const float *)(element->data + i * element->stride);
4058 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4060 ERR("No source texture, but destination requests one\n");
4061 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4062 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4064 else {
4065 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4066 if(dest_conv) {
4067 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4073 if(dest_conv) {
4074 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4075 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4076 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4077 dwCount * get_flexible_vertex_size(DestFVF),
4078 dest_conv_addr));
4079 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4080 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4083 LEAVE_GL();
4085 return WINED3D_OK;
4087 #undef copy_and_next
4089 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4090 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4091 DWORD DestFVF)
4093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4094 struct wined3d_stream_info stream_info;
4095 struct wined3d_context *context;
4096 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4097 HRESULT hr;
4099 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4101 if(pVertexDecl) {
4102 ERR("Output vertex declaration not implemented yet\n");
4105 /* Need any context to write to the vbo. */
4106 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4108 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4109 * control the streamIsUP flag, thus restore it afterwards.
4111 This->stateBlock->streamIsUP = FALSE;
4112 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4113 This->stateBlock->streamIsUP = streamWasUP;
4115 if(vbo || SrcStartIndex) {
4116 unsigned int i;
4117 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4118 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4120 * Also get the start index in, but only loop over all elements if there's something to add at all.
4122 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4124 struct wined3d_stream_info_element *e;
4126 if (!(stream_info.use_map & (1 << i))) continue;
4128 e = &stream_info.elements[i];
4129 if (e->buffer_object)
4131 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4132 e->buffer_object = 0;
4133 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4134 ENTER_GL();
4135 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4136 vb->buffer_object = 0;
4137 LEAVE_GL();
4139 if (e->data) e->data += e->stride * SrcStartIndex;
4143 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4144 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4146 context_release(context);
4148 return hr;
4151 /*****
4152 * Get / Set Texture Stage States
4153 * TODO: Verify against dx9 definitions
4154 *****/
4155 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4157 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4159 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4161 if (Stage >= MAX_TEXTURES) {
4162 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4163 return WINED3D_OK;
4166 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4167 This->updateStateBlock->textureState[Stage][Type] = Value;
4169 if (This->isRecordingState) {
4170 TRACE("Recording... not performing anything\n");
4171 return WINED3D_OK;
4174 /* Checked after the assignments to allow proper stateblock recording */
4175 if(oldValue == Value) {
4176 TRACE("App is setting the old value over, nothing to do\n");
4177 return WINED3D_OK;
4180 if(Stage > This->stateBlock->lowest_disabled_stage &&
4181 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4182 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4183 * Changes in other states are important on disabled stages too
4185 return WINED3D_OK;
4188 if(Type == WINED3DTSS_COLOROP) {
4189 unsigned int i;
4191 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4192 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4193 * they have to be disabled
4195 * The current stage is dirtified below.
4197 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4198 TRACE("Additionally dirtifying stage %u\n", i);
4199 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4201 This->stateBlock->lowest_disabled_stage = Stage;
4202 TRACE("New lowest disabled: %u\n", Stage);
4203 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4204 /* Previously disabled stage enabled. Stages above it may need enabling
4205 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4206 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4208 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4211 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4213 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4214 break;
4216 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4217 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4219 This->stateBlock->lowest_disabled_stage = i;
4220 TRACE("New lowest disabled: %u\n", i);
4224 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4226 return WINED3D_OK;
4229 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4231 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4232 *pValue = This->updateStateBlock->textureState[Stage][Type];
4233 return WINED3D_OK;
4236 /*****
4237 * Get / Set Texture
4238 *****/
4239 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4240 DWORD stage, IWineD3DBaseTexture *texture)
4242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4243 IWineD3DBaseTexture *prev;
4245 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4247 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4248 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4250 /* Windows accepts overflowing this array... we do not. */
4251 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4253 WARN("Ignoring invalid stage %u.\n", stage);
4254 return WINED3D_OK;
4257 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4258 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4260 WARN("Rejecting attempt to set scratch texture.\n");
4261 return WINED3DERR_INVALIDCALL;
4264 This->updateStateBlock->changed.textures |= 1 << stage;
4266 prev = This->updateStateBlock->textures[stage];
4267 TRACE("Previous texture %p.\n", prev);
4269 if (texture == prev)
4271 TRACE("App is setting the same texture again, nothing to do.\n");
4272 return WINED3D_OK;
4275 TRACE("Setting new texture to %p.\n", texture);
4276 This->updateStateBlock->textures[stage] = texture;
4278 if (This->isRecordingState)
4280 TRACE("Recording... not performing anything\n");
4282 if (texture) IWineD3DBaseTexture_AddRef(texture);
4283 if (prev) IWineD3DBaseTexture_Release(prev);
4285 return WINED3D_OK;
4288 if (texture)
4290 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4291 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4292 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4294 IWineD3DBaseTexture_AddRef(texture);
4296 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4298 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4301 if (!prev && stage < MAX_TEXTURES)
4303 /* The source arguments for color and alpha ops have different
4304 * meanings when a NULL texture is bound, so the COLOROP and
4305 * ALPHAOP have to be dirtified. */
4306 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4307 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4310 if (bind_count == 1) t->baseTexture.sampler = stage;
4313 if (prev)
4315 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4316 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4318 IWineD3DBaseTexture_Release(prev);
4320 if (!texture && stage < MAX_TEXTURES)
4322 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4323 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4326 if (bind_count && t->baseTexture.sampler == stage)
4328 unsigned int i;
4330 /* Search for other stages the texture is bound to. Shouldn't
4331 * happen if applications bind textures to a single stage only. */
4332 TRACE("Searching for other stages the texture is bound to.\n");
4333 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4335 if (This->updateStateBlock->textures[i] == prev)
4337 TRACE("Texture is also bound to stage %u.\n", i);
4338 t->baseTexture.sampler = i;
4339 break;
4345 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4347 return WINED3D_OK;
4350 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4353 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4355 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4356 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4359 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4360 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4361 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4364 *ppTexture=This->stateBlock->textures[Stage];
4365 if (*ppTexture)
4366 IWineD3DBaseTexture_AddRef(*ppTexture);
4368 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4370 return WINED3D_OK;
4373 /*****
4374 * Get Back Buffer
4375 *****/
4376 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4377 IWineD3DSurface **ppBackBuffer) {
4378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4379 IWineD3DSwapChain *swapChain;
4380 HRESULT hr;
4382 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4384 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4385 if (hr == WINED3D_OK) {
4386 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4387 IWineD3DSwapChain_Release(swapChain);
4388 } else {
4389 *ppBackBuffer = NULL;
4391 return hr;
4394 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4396 WARN("(%p) : stub, calling idirect3d for now\n", This);
4397 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4400 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4402 IWineD3DSwapChain *swapChain;
4403 HRESULT hr;
4405 if(iSwapChain > 0) {
4406 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4407 if (hr == WINED3D_OK) {
4408 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4409 IWineD3DSwapChain_Release(swapChain);
4410 } else {
4411 FIXME("(%p) Error getting display mode\n", This);
4413 } else {
4414 /* Don't read the real display mode,
4415 but return the stored mode instead. X11 can't change the color
4416 depth, and some apps are pretty angry if they SetDisplayMode from
4417 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4419 Also don't relay to the swapchain because with ddraw it's possible
4420 that there isn't a swapchain at all */
4421 pMode->Width = This->ddraw_width;
4422 pMode->Height = This->ddraw_height;
4423 pMode->Format = This->ddraw_format;
4424 pMode->RefreshRate = 0;
4425 hr = WINED3D_OK;
4428 return hr;
4431 /*****
4432 * Stateblock related functions
4433 *****/
4435 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4437 IWineD3DStateBlock *stateblock;
4438 HRESULT hr;
4440 TRACE("(%p)\n", This);
4442 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4444 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4445 if (FAILED(hr)) return hr;
4447 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4448 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4449 This->isRecordingState = TRUE;
4451 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4453 return WINED3D_OK;
4456 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4458 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4460 if (!This->isRecordingState) {
4461 WARN("(%p) not recording! returning error\n", This);
4462 *ppStateBlock = NULL;
4463 return WINED3DERR_INVALIDCALL;
4466 stateblock_init_contained_states(object);
4468 *ppStateBlock = (IWineD3DStateBlock*) object;
4469 This->isRecordingState = FALSE;
4470 This->updateStateBlock = This->stateBlock;
4471 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4472 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4473 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4474 return WINED3D_OK;
4477 /*****
4478 * Scene related functions
4479 *****/
4480 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4481 /* At the moment we have no need for any functionality at the beginning
4482 of a scene */
4483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4484 TRACE("(%p)\n", This);
4486 if(This->inScene) {
4487 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4488 return WINED3DERR_INVALIDCALL;
4490 This->inScene = TRUE;
4491 return WINED3D_OK;
4494 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4497 struct wined3d_context *context;
4499 TRACE("(%p)\n", This);
4501 if(!This->inScene) {
4502 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4503 return WINED3DERR_INVALIDCALL;
4506 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4507 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4508 wglFlush();
4509 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4510 * fails. */
4511 context_release(context);
4513 This->inScene = FALSE;
4514 return WINED3D_OK;
4517 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4518 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4519 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4521 IWineD3DSwapChain *swapChain = NULL;
4522 int i;
4523 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4525 TRACE("(%p) Presenting the frame\n", This);
4527 for(i = 0 ; i < swapchains ; i ++) {
4529 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4530 TRACE("presentinng chain %d, %p\n", i, swapChain);
4531 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4532 IWineD3DSwapChain_Release(swapChain);
4535 return WINED3D_OK;
4538 /* Not called from the VTable (internal subroutine) */
4539 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4540 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4541 float Z, DWORD Stencil) {
4542 GLbitfield glMask = 0;
4543 unsigned int i;
4544 WINED3DRECT curRect;
4545 RECT vp_rect;
4546 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4547 UINT drawable_width, drawable_height;
4548 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4549 IWineD3DSwapChainImpl *swapchain = NULL;
4550 struct wined3d_context *context;
4552 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4553 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4554 * for the cleared parts, and the untouched parts.
4556 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4557 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4558 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4559 * checking all this if the dest surface is in the drawable anyway.
4561 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4562 while(1) {
4563 if(vp->X != 0 || vp->Y != 0 ||
4564 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4565 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4566 break;
4568 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4569 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4570 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4571 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4572 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4573 break;
4575 if(Count > 0 && pRects && (
4576 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4577 pRects[0].x2 < target->currentDesc.Width ||
4578 pRects[0].y2 < target->currentDesc.Height)) {
4579 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4580 break;
4582 break;
4586 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4588 target->get_drawable_size(context, &drawable_width, &drawable_height);
4590 ENTER_GL();
4592 /* Only set the values up once, as they are not changing */
4593 if (Flags & WINED3DCLEAR_STENCIL) {
4594 glClearStencil(Stencil);
4595 checkGLcall("glClearStencil");
4596 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4597 glStencilMask(0xFFFFFFFF);
4600 if (Flags & WINED3DCLEAR_ZBUFFER) {
4601 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4602 glDepthMask(GL_TRUE);
4603 glClearDepth(Z);
4604 checkGLcall("glClearDepth");
4605 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4606 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4608 if (vp->X != 0 || vp->Y != 0 ||
4609 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4610 surface_load_ds_location(This->stencilBufferTarget, context, location);
4612 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4613 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4614 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4615 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4616 surface_load_ds_location(This->stencilBufferTarget, context, location);
4618 else if (Count > 0 && pRects && (
4619 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4620 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4621 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4622 surface_load_ds_location(This->stencilBufferTarget, context, location);
4626 if (Flags & WINED3DCLEAR_TARGET) {
4627 TRACE("Clearing screen with glClear to color %x\n", Color);
4628 glClearColor(D3DCOLOR_R(Color),
4629 D3DCOLOR_G(Color),
4630 D3DCOLOR_B(Color),
4631 D3DCOLOR_A(Color));
4632 checkGLcall("glClearColor");
4634 /* Clear ALL colors! */
4635 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4636 glMask = glMask | GL_COLOR_BUFFER_BIT;
4639 vp_rect.left = vp->X;
4640 vp_rect.top = vp->Y;
4641 vp_rect.right = vp->X + vp->Width;
4642 vp_rect.bottom = vp->Y + vp->Height;
4643 if (!(Count > 0 && pRects)) {
4644 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4645 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4647 if (context->render_offscreen)
4649 glScissor(vp_rect.left, vp_rect.top,
4650 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4651 } else {
4652 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4653 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4655 checkGLcall("glScissor");
4656 glClear(glMask);
4657 checkGLcall("glClear");
4658 } else {
4659 /* Now process each rect in turn */
4660 for (i = 0; i < Count; i++) {
4661 /* Note gl uses lower left, width/height */
4662 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4663 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4664 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4666 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4667 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4668 curRect.x1, (target->currentDesc.Height - curRect.y2),
4669 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4671 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4672 * The rectangle is not cleared, no error is returned, but further rectanlges are
4673 * still cleared if they are valid
4675 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4676 TRACE("Rectangle with negative dimensions, ignoring\n");
4677 continue;
4680 if (context->render_offscreen)
4682 glScissor(curRect.x1, curRect.y1,
4683 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4684 } else {
4685 glScissor(curRect.x1, drawable_height - curRect.y2,
4686 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4688 checkGLcall("glScissor");
4690 glClear(glMask);
4691 checkGLcall("glClear");
4695 /* Restore the old values (why..?) */
4696 if (Flags & WINED3DCLEAR_STENCIL) {
4697 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4699 if (Flags & WINED3DCLEAR_TARGET) {
4700 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4701 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4702 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4703 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4704 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4706 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4707 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4709 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4711 if (Flags & WINED3DCLEAR_ZBUFFER) {
4712 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4713 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4714 surface_modify_ds_location(This->stencilBufferTarget, location);
4717 LEAVE_GL();
4719 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
4720 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
4721 wglFlush();
4723 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
4726 context_release(context);
4728 return WINED3D_OK;
4731 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4732 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4734 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4736 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4737 Count, pRects, Flags, Color, Z, Stencil);
4739 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4740 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4741 /* TODO: What about depth stencil buffers without stencil bits? */
4742 return WINED3DERR_INVALIDCALL;
4745 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4748 /*****
4749 * Drawing functions
4750 *****/
4752 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4753 WINED3DPRIMITIVETYPE primitive_type)
4755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4757 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4759 This->updateStateBlock->changed.primitive_type = TRUE;
4760 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4763 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4764 WINED3DPRIMITIVETYPE *primitive_type)
4766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4768 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4770 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4772 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4775 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4779 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4781 if(!This->stateBlock->vertexDecl) {
4782 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4783 return WINED3DERR_INVALIDCALL;
4786 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4787 if(This->stateBlock->streamIsUP) {
4788 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4789 This->stateBlock->streamIsUP = FALSE;
4792 if(This->stateBlock->loadBaseVertexIndex != 0) {
4793 This->stateBlock->loadBaseVertexIndex = 0;
4794 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4796 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4797 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4798 return WINED3D_OK;
4801 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4804 UINT idxStride = 2;
4805 IWineD3DBuffer *pIB;
4806 GLuint vbo;
4808 pIB = This->stateBlock->pIndexData;
4809 if (!pIB) {
4810 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4811 * without an index buffer set. (The first time at least...)
4812 * D3D8 simply dies, but I doubt it can do much harm to return
4813 * D3DERR_INVALIDCALL there as well. */
4814 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4815 return WINED3DERR_INVALIDCALL;
4818 if(!This->stateBlock->vertexDecl) {
4819 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4820 return WINED3DERR_INVALIDCALL;
4823 if(This->stateBlock->streamIsUP) {
4824 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4825 This->stateBlock->streamIsUP = FALSE;
4827 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4829 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4831 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4832 idxStride = 2;
4833 } else {
4834 idxStride = 4;
4837 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4838 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4839 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4842 drawPrimitive(iface, index_count, startIndex, idxStride,
4843 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4845 return WINED3D_OK;
4848 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4849 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4852 IWineD3DBuffer *vb;
4854 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4855 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4857 if(!This->stateBlock->vertexDecl) {
4858 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4859 return WINED3DERR_INVALIDCALL;
4862 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4863 vb = This->stateBlock->streamSource[0];
4864 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4865 if (vb) IWineD3DBuffer_Release(vb);
4866 This->stateBlock->streamOffset[0] = 0;
4867 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4868 This->stateBlock->streamIsUP = TRUE;
4869 This->stateBlock->loadBaseVertexIndex = 0;
4871 /* TODO: Only mark dirty if drawing from a different UP address */
4872 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4874 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4876 /* MSDN specifies stream zero settings must be set to NULL */
4877 This->stateBlock->streamStride[0] = 0;
4878 This->stateBlock->streamSource[0] = NULL;
4880 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4881 * the new stream sources or use UP drawing again
4883 return WINED3D_OK;
4886 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4887 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4888 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4890 int idxStride;
4891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4892 IWineD3DBuffer *vb;
4893 IWineD3DBuffer *ib;
4895 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4896 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4898 if(!This->stateBlock->vertexDecl) {
4899 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4900 return WINED3DERR_INVALIDCALL;
4903 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4904 idxStride = 2;
4905 } else {
4906 idxStride = 4;
4909 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4910 vb = This->stateBlock->streamSource[0];
4911 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4912 if (vb) IWineD3DBuffer_Release(vb);
4913 This->stateBlock->streamIsUP = TRUE;
4914 This->stateBlock->streamOffset[0] = 0;
4915 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4917 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4918 This->stateBlock->baseVertexIndex = 0;
4919 This->stateBlock->loadBaseVertexIndex = 0;
4920 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4921 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4922 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4924 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4926 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4927 This->stateBlock->streamSource[0] = NULL;
4928 This->stateBlock->streamStride[0] = 0;
4929 ib = This->stateBlock->pIndexData;
4930 if(ib) {
4931 IWineD3DBuffer_Release(ib);
4932 This->stateBlock->pIndexData = NULL;
4934 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4935 * SetStreamSource to specify a vertex buffer
4938 return WINED3D_OK;
4941 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4942 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4946 /* Mark the state dirty until we have nicer tracking
4947 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4948 * that value.
4950 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4951 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4952 This->stateBlock->baseVertexIndex = 0;
4953 This->up_strided = DrawPrimStrideData;
4954 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4955 This->up_strided = NULL;
4956 return WINED3D_OK;
4959 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4960 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4961 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4964 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4966 /* Mark the state dirty until we have nicer tracking
4967 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4968 * that value.
4970 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4971 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4972 This->stateBlock->streamIsUP = TRUE;
4973 This->stateBlock->baseVertexIndex = 0;
4974 This->up_strided = DrawPrimStrideData;
4975 drawPrimitive(iface, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData);
4976 This->up_strided = NULL;
4977 return WINED3D_OK;
4980 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
4981 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
4982 * not callable by the app directly no parameter validation checks are needed here.
4984 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4985 WINED3DLOCKED_BOX src;
4986 WINED3DLOCKED_BOX dst;
4987 HRESULT hr;
4988 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
4990 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4991 * dirtification to improve loading performance.
4993 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4994 if(FAILED(hr)) return hr;
4995 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4996 if(FAILED(hr)) {
4997 IWineD3DVolume_UnlockBox(pSourceVolume);
4998 return hr;
5001 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5003 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5004 if(FAILED(hr)) {
5005 IWineD3DVolume_UnlockBox(pSourceVolume);
5006 } else {
5007 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5009 return hr;
5012 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
5013 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
5015 unsigned int level_count, i;
5016 WINED3DRESOURCETYPE type;
5017 HRESULT hr;
5019 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
5021 /* Verify that the source and destination textures are non-NULL. */
5022 if (!src_texture || !dst_texture)
5024 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5025 return WINED3DERR_INVALIDCALL;
5028 if (src_texture == dst_texture)
5030 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5031 return WINED3DERR_INVALIDCALL;
5034 /* Verify that the source and destination textures are the same type. */
5035 type = IWineD3DBaseTexture_GetType(src_texture);
5036 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
5038 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5039 return WINED3DERR_INVALIDCALL;
5042 /* Check that both textures have the identical numbers of levels. */
5043 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
5044 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
5046 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5047 return WINED3DERR_INVALIDCALL;
5050 /* Make sure that the destination texture is loaded. */
5051 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
5053 /* Update every surface level of the texture. */
5054 switch (type)
5056 case WINED3DRTYPE_TEXTURE:
5058 IWineD3DSurface *src_surface;
5059 IWineD3DSurface *dst_surface;
5061 for (i = 0; i < level_count; ++i)
5063 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
5064 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
5065 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5066 IWineD3DSurface_Release(dst_surface);
5067 IWineD3DSurface_Release(src_surface);
5068 if (FAILED(hr))
5070 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5071 return hr;
5074 break;
5077 case WINED3DRTYPE_CUBETEXTURE:
5079 IWineD3DSurface *src_surface;
5080 IWineD3DSurface *dst_surface;
5081 WINED3DCUBEMAP_FACES face;
5083 for (i = 0; i < level_count; ++i)
5085 /* Update each cube face. */
5086 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
5088 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
5089 face, i, &src_surface);
5090 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5091 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
5092 face, i, &dst_surface);
5093 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
5094 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
5095 IWineD3DSurface_Release(dst_surface);
5096 IWineD3DSurface_Release(src_surface);
5097 if (FAILED(hr))
5099 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
5100 return hr;
5104 break;
5107 case WINED3DRTYPE_VOLUMETEXTURE:
5109 IWineD3DVolume *src_volume;
5110 IWineD3DVolume *dst_volume;
5112 for (i = 0; i < level_count; ++i)
5114 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
5115 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
5116 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
5117 IWineD3DVolume_Release(dst_volume);
5118 IWineD3DVolume_Release(src_volume);
5119 if (FAILED(hr))
5121 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5122 return hr;
5125 break;
5128 default:
5129 FIXME("Unsupported texture type %#x.\n", type);
5130 return WINED3DERR_INVALIDCALL;
5133 return WINED3D_OK;
5136 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5137 IWineD3DSwapChain *swapChain;
5138 HRESULT hr;
5139 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5140 if(hr == WINED3D_OK) {
5141 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5142 IWineD3DSwapChain_Release(swapChain);
5144 return hr;
5147 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5149 IWineD3DBaseTextureImpl *texture;
5150 DWORD i;
5152 TRACE("(%p) : %p\n", This, pNumPasses);
5154 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5155 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5156 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5157 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5159 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5160 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5161 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5164 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5165 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5167 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5168 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5169 return E_FAIL;
5171 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5172 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5173 return E_FAIL;
5175 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5176 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5177 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5178 return E_FAIL;
5182 /* return a sensible default */
5183 *pNumPasses = 1;
5185 TRACE("returning D3D_OK\n");
5186 return WINED3D_OK;
5189 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5191 int i;
5193 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5195 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5196 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
5197 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
5199 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5204 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5206 int j;
5207 UINT NewSize;
5208 PALETTEENTRY **palettes;
5210 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5212 if (PaletteNumber >= MAX_PALETTES) {
5213 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5214 return WINED3DERR_INVALIDCALL;
5217 if (PaletteNumber >= This->NumberOfPalettes) {
5218 NewSize = This->NumberOfPalettes;
5219 do {
5220 NewSize *= 2;
5221 } while(PaletteNumber >= NewSize);
5222 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5223 if (!palettes) {
5224 ERR("Out of memory!\n");
5225 return E_OUTOFMEMORY;
5227 This->palettes = palettes;
5228 This->NumberOfPalettes = NewSize;
5231 if (!This->palettes[PaletteNumber]) {
5232 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5233 if (!This->palettes[PaletteNumber]) {
5234 ERR("Out of memory!\n");
5235 return E_OUTOFMEMORY;
5239 for (j = 0; j < 256; ++j) {
5240 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5241 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5242 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5243 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5245 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5246 TRACE("(%p) : returning\n", This);
5247 return WINED3D_OK;
5250 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5252 int j;
5253 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5254 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5255 /* What happens in such situation isn't documented; Native seems to silently abort
5256 on such conditions. Return Invalid Call. */
5257 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5258 return WINED3DERR_INVALIDCALL;
5260 for (j = 0; j < 256; ++j) {
5261 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5262 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5263 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5264 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5266 TRACE("(%p) : returning\n", This);
5267 return WINED3D_OK;
5270 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5272 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5273 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5274 (tested with reference rasterizer). Return Invalid Call. */
5275 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5276 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5277 return WINED3DERR_INVALIDCALL;
5279 /*TODO: stateblocks */
5280 if (This->currentPalette != PaletteNumber) {
5281 This->currentPalette = PaletteNumber;
5282 dirtify_p8_texture_samplers(This);
5284 TRACE("(%p) : returning\n", This);
5285 return WINED3D_OK;
5288 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5290 if (PaletteNumber == NULL) {
5291 WARN("(%p) : returning Invalid Call\n", This);
5292 return WINED3DERR_INVALIDCALL;
5294 /*TODO: stateblocks */
5295 *PaletteNumber = This->currentPalette;
5296 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5297 return WINED3D_OK;
5300 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5302 static BOOL warned;
5303 if (!warned)
5305 FIXME("(%p) : stub\n", This);
5306 warned = TRUE;
5309 This->softwareVertexProcessing = bSoftware;
5310 return WINED3D_OK;
5314 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5316 static BOOL warned;
5317 if (!warned)
5319 FIXME("(%p) : stub\n", This);
5320 warned = TRUE;
5322 return This->softwareVertexProcessing;
5326 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5327 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5328 IWineD3DSwapChain *swapChain;
5329 HRESULT hr;
5331 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5333 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5334 if(hr == WINED3D_OK){
5335 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5336 IWineD3DSwapChain_Release(swapChain);
5337 }else{
5338 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5340 return hr;
5344 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5346 static BOOL warned;
5347 if(nSegments != 0.0f) {
5348 if (!warned)
5350 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5351 warned = TRUE;
5354 return WINED3D_OK;
5357 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5359 static BOOL warned;
5360 if (!warned)
5362 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5363 warned = TRUE;
5365 return 0.0f;
5368 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5370 /** TODO: remove casts to IWineD3DSurfaceImpl
5371 * NOTE: move code to surface to accomplish this
5372 ****************************************/
5373 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5374 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5375 int srcWidth, srcHeight;
5376 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5377 WINED3DFORMAT destFormat, srcFormat;
5378 UINT destSize;
5379 int srcLeft, destLeft, destTop;
5380 WINED3DPOOL srcPool, destPool;
5381 int offset = 0;
5382 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5383 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5384 GLenum dummy;
5385 DWORD sampler;
5386 int bpp;
5387 CONVERT_TYPES convert = NO_CONVERSION;
5388 struct wined3d_context *context;
5390 WINED3DSURFACE_DESC winedesc;
5392 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5394 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5395 srcSurfaceWidth = winedesc.width;
5396 srcSurfaceHeight = winedesc.height;
5397 srcPool = winedesc.pool;
5398 srcFormat = winedesc.format;
5400 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5401 destSurfaceWidth = winedesc.width;
5402 destSurfaceHeight = winedesc.height;
5403 destPool = winedesc.pool;
5404 destFormat = winedesc.format;
5405 destSize = winedesc.size;
5407 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5408 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5409 return WINED3DERR_INVALIDCALL;
5412 /* This call loads the opengl surface directly, instead of copying the surface to the
5413 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5414 * copy in sysmem and use regular surface loading.
5416 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5417 if(convert != NO_CONVERSION) {
5418 return IWineD3DSurface_BltFast(pDestinationSurface,
5419 pDestPoint ? pDestPoint->x : 0,
5420 pDestPoint ? pDestPoint->y : 0,
5421 pSourceSurface, pSourceRect, 0);
5424 if (destFormat == WINED3DFMT_UNKNOWN) {
5425 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5426 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5428 /* Get the update surface description */
5429 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5432 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5434 ENTER_GL();
5435 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5436 checkGLcall("glActiveTextureARB");
5437 LEAVE_GL();
5439 /* Make sure the surface is loaded and up to date */
5440 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5441 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5443 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5444 dst_format_desc = dst_impl->resource.format_desc;
5446 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5447 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5448 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5449 srcLeft = pSourceRect ? pSourceRect->left : 0;
5450 destLeft = pDestPoint ? pDestPoint->x : 0;
5451 destTop = pDestPoint ? pDestPoint->y : 0;
5454 /* This function doesn't support compressed textures
5455 the pitch is just bytesPerPixel * width */
5456 if(srcWidth != srcSurfaceWidth || srcLeft ){
5457 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5458 offset += srcLeft * src_format_desc->byte_count;
5459 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5461 /* TODO DXT formats */
5463 if(pSourceRect != NULL && pSourceRect->top != 0){
5464 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5466 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5467 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5468 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5470 /* Sanity check */
5471 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5473 /* need to lock the surface to get the data */
5474 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5477 ENTER_GL();
5479 /* TODO: Cube and volume support */
5480 if(rowoffset != 0){
5481 /* not a whole row so we have to do it a line at a time */
5482 int j;
5484 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5485 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5487 for (j = destTop; j < (srcHeight + destTop); ++j)
5489 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5490 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5491 data += rowoffset;
5494 } else { /* Full width, so just write out the whole texture */
5495 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5497 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5499 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5501 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5502 FIXME("Updating part of a compressed texture is not supported.\n");
5504 if (destFormat != srcFormat)
5506 FIXME("Updating mixed format compressed textures is not supported.\n");
5508 else
5510 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5511 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5514 else
5516 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5517 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5520 checkGLcall("glTexSubImage2D");
5522 LEAVE_GL();
5523 context_release(context);
5525 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5526 sampler = This->rev_tex_unit_map[0];
5527 if (sampler != WINED3D_UNMAPPED_STAGE)
5529 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5532 return WINED3D_OK;
5535 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5537 struct WineD3DRectPatch *patch;
5538 GLenum old_primitive_type;
5539 unsigned int i;
5540 struct list *e;
5541 BOOL found;
5542 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5544 if(!(Handle || pRectPatchInfo)) {
5545 /* TODO: Write a test for the return value, thus the FIXME */
5546 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5547 return WINED3DERR_INVALIDCALL;
5550 if(Handle) {
5551 i = PATCHMAP_HASHFUNC(Handle);
5552 found = FALSE;
5553 LIST_FOR_EACH(e, &This->patches[i]) {
5554 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5555 if(patch->Handle == Handle) {
5556 found = TRUE;
5557 break;
5561 if(!found) {
5562 TRACE("Patch does not exist. Creating a new one\n");
5563 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5564 patch->Handle = Handle;
5565 list_add_head(&This->patches[i], &patch->entry);
5566 } else {
5567 TRACE("Found existing patch %p\n", patch);
5569 } else {
5570 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5571 * attributes we have to tesselate, read back, and draw. This needs a patch
5572 * management structure instance. Create one.
5574 * A possible improvement is to check if a vertex shader is used, and if not directly
5575 * draw the patch.
5577 FIXME("Drawing an uncached patch. This is slow\n");
5578 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5581 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5582 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5583 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5584 HRESULT hr;
5585 TRACE("Tesselation density or patch info changed, retesselating\n");
5587 if(pRectPatchInfo) {
5588 patch->RectPatchInfo = *pRectPatchInfo;
5590 patch->numSegs[0] = pNumSegs[0];
5591 patch->numSegs[1] = pNumSegs[1];
5592 patch->numSegs[2] = pNumSegs[2];
5593 patch->numSegs[3] = pNumSegs[3];
5595 hr = tesselate_rectpatch(This, patch);
5596 if(FAILED(hr)) {
5597 WARN("Patch tesselation failed\n");
5599 /* Do not release the handle to store the params of the patch */
5600 if(!Handle) {
5601 HeapFree(GetProcessHeap(), 0, patch);
5603 return hr;
5607 This->currentPatch = patch;
5608 old_primitive_type = This->stateBlock->gl_primitive_type;
5609 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5610 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5611 This->stateBlock->gl_primitive_type = old_primitive_type;
5612 This->currentPatch = NULL;
5614 /* Destroy uncached patches */
5615 if(!Handle) {
5616 HeapFree(GetProcessHeap(), 0, patch->mem);
5617 HeapFree(GetProcessHeap(), 0, patch);
5619 return WINED3D_OK;
5622 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5624 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5625 FIXME("(%p) : Stub\n", This);
5626 return WINED3D_OK;
5629 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5631 int i;
5632 struct WineD3DRectPatch *patch;
5633 struct list *e;
5634 TRACE("(%p) Handle(%d)\n", This, Handle);
5636 i = PATCHMAP_HASHFUNC(Handle);
5637 LIST_FOR_EACH(e, &This->patches[i]) {
5638 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5639 if(patch->Handle == Handle) {
5640 TRACE("Deleting patch %p\n", patch);
5641 list_remove(&patch->entry);
5642 HeapFree(GetProcessHeap(), 0, patch->mem);
5643 HeapFree(GetProcessHeap(), 0, patch);
5644 return WINED3D_OK;
5648 /* TODO: Write a test for the return value */
5649 FIXME("Attempt to destroy nonexistent patch\n");
5650 return WINED3DERR_INVALIDCALL;
5653 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5654 HRESULT hr;
5655 IWineD3DSwapChain *swapchain;
5657 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5658 if (SUCCEEDED(hr)) {
5659 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5660 return swapchain;
5663 return NULL;
5666 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5667 const WINED3DRECT *rect, const float color[4])
5669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5670 struct wined3d_context *context;
5671 IWineD3DSwapChain *swapchain;
5673 swapchain = get_swapchain(surface);
5674 if (swapchain) {
5675 GLenum buffer;
5677 TRACE("Surface %p is onscreen\n", surface);
5679 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5680 ENTER_GL();
5681 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5682 buffer = surface_get_gl_buffer(surface, swapchain);
5683 glDrawBuffer(buffer);
5684 checkGLcall("glDrawBuffer()");
5685 } else {
5686 TRACE("Surface %p is offscreen\n", surface);
5688 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5689 ENTER_GL();
5690 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5691 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5692 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5695 if (rect) {
5696 glEnable(GL_SCISSOR_TEST);
5697 if(!swapchain) {
5698 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5699 } else {
5700 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5701 rect->x2 - rect->x1, rect->y2 - rect->y1);
5703 checkGLcall("glScissor");
5704 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5705 } else {
5706 glDisable(GL_SCISSOR_TEST);
5708 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5710 glDisable(GL_BLEND);
5711 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5713 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5714 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5716 glClearColor(color[0], color[1], color[2], color[3]);
5717 glClear(GL_COLOR_BUFFER_BIT);
5718 checkGLcall("glClear");
5720 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5721 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5722 glDrawBuffer(GL_BACK);
5723 checkGLcall("glDrawBuffer()");
5726 LEAVE_GL();
5727 context_release(context);
5730 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5731 unsigned int r, g, b, a;
5732 DWORD ret;
5734 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5735 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5736 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5737 return color;
5739 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5741 a = (color & 0xff000000) >> 24;
5742 r = (color & 0x00ff0000) >> 16;
5743 g = (color & 0x0000ff00) >> 8;
5744 b = (color & 0x000000ff) >> 0;
5746 switch(destfmt)
5748 case WINED3DFMT_B5G6R5_UNORM:
5749 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5750 r = (r * 32) / 256;
5751 g = (g * 64) / 256;
5752 b = (b * 32) / 256;
5753 ret = r << 11;
5754 ret |= g << 5;
5755 ret |= b;
5756 TRACE("Returning %08x\n", ret);
5757 return ret;
5759 case WINED3DFMT_B5G5R5X1_UNORM:
5760 case WINED3DFMT_B5G5R5A1_UNORM:
5761 a = (a * 2) / 256;
5762 r = (r * 32) / 256;
5763 g = (g * 32) / 256;
5764 b = (b * 32) / 256;
5765 ret = a << 15;
5766 ret |= r << 10;
5767 ret |= g << 5;
5768 ret |= b << 0;
5769 TRACE("Returning %08x\n", ret);
5770 return ret;
5772 case WINED3DFMT_A8_UNORM:
5773 TRACE("Returning %08x\n", a);
5774 return a;
5776 case WINED3DFMT_B4G4R4X4_UNORM:
5777 case WINED3DFMT_B4G4R4A4_UNORM:
5778 a = (a * 16) / 256;
5779 r = (r * 16) / 256;
5780 g = (g * 16) / 256;
5781 b = (b * 16) / 256;
5782 ret = a << 12;
5783 ret |= r << 8;
5784 ret |= g << 4;
5785 ret |= b << 0;
5786 TRACE("Returning %08x\n", ret);
5787 return ret;
5789 case WINED3DFMT_B2G3R3_UNORM:
5790 r = (r * 8) / 256;
5791 g = (g * 8) / 256;
5792 b = (b * 4) / 256;
5793 ret = r << 5;
5794 ret |= g << 2;
5795 ret |= b << 0;
5796 TRACE("Returning %08x\n", ret);
5797 return ret;
5799 case WINED3DFMT_R8G8B8X8_UNORM:
5800 case WINED3DFMT_R8G8B8A8_UNORM:
5801 ret = a << 24;
5802 ret |= b << 16;
5803 ret |= g << 8;
5804 ret |= r << 0;
5805 TRACE("Returning %08x\n", ret);
5806 return ret;
5808 case WINED3DFMT_B10G10R10A2_UNORM:
5809 a = (a * 4) / 256;
5810 r = (r * 1024) / 256;
5811 g = (g * 1024) / 256;
5812 b = (b * 1024) / 256;
5813 ret = a << 30;
5814 ret |= r << 20;
5815 ret |= g << 10;
5816 ret |= b << 0;
5817 TRACE("Returning %08x\n", ret);
5818 return ret;
5820 case WINED3DFMT_R10G10B10A2_UNORM:
5821 a = (a * 4) / 256;
5822 r = (r * 1024) / 256;
5823 g = (g * 1024) / 256;
5824 b = (b * 1024) / 256;
5825 ret = a << 30;
5826 ret |= b << 20;
5827 ret |= g << 10;
5828 ret |= r << 0;
5829 TRACE("Returning %08x\n", ret);
5830 return ret;
5832 default:
5833 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5834 return 0;
5838 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5840 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5841 WINEDDBLTFX BltFx;
5842 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5844 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5845 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5846 return WINED3DERR_INVALIDCALL;
5849 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5850 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5851 color_fill_fbo(iface, pSurface, pRect, c);
5852 return WINED3D_OK;
5853 } else {
5854 /* Just forward this to the DirectDraw blitting engine */
5855 memset(&BltFx, 0, sizeof(BltFx));
5856 BltFx.dwSize = sizeof(BltFx);
5857 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5858 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5859 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5863 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5864 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5866 IWineD3DResource *resource;
5867 IWineD3DSurface *surface;
5868 HRESULT hr;
5870 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5871 if (FAILED(hr))
5873 ERR("Failed to get resource, hr %#x\n", hr);
5874 return;
5877 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5879 FIXME("Only supported on surface resources\n");
5880 IWineD3DResource_Release(resource);
5881 return;
5884 surface = (IWineD3DSurface *)resource;
5886 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5888 color_fill_fbo(iface, surface, NULL, color);
5890 else
5892 WINEDDBLTFX BltFx;
5893 WINED3DCOLOR c;
5895 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5897 c = ((DWORD)(color[2] * 255.0f));
5898 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5899 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5900 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5902 /* Just forward this to the DirectDraw blitting engine */
5903 memset(&BltFx, 0, sizeof(BltFx));
5904 BltFx.dwSize = sizeof(BltFx);
5905 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5906 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5907 if (FAILED(hr))
5909 ERR("Blt failed, hr %#x\n", hr);
5913 IWineD3DResource_Release(resource);
5916 /* rendertarget and depth stencil functions */
5917 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5920 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5922 ERR("(%p) : Only %d render targets are supported.\n",
5923 This, This->adapter->gl_info.limits.buffers);
5924 return WINED3DERR_INVALIDCALL;
5927 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5928 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5929 /* Note inc ref on returned surface */
5930 if(*ppRenderTarget != NULL)
5931 IWineD3DSurface_AddRef(*ppRenderTarget);
5932 return WINED3D_OK;
5935 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5936 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5937 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5938 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5939 IWineD3DSwapChainImpl *Swapchain;
5940 HRESULT hr;
5942 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5944 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5945 if(hr != WINED3D_OK) {
5946 ERR("Can't get the swapchain\n");
5947 return hr;
5950 /* Make sure to release the swapchain */
5951 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5953 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5954 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5955 return WINED3DERR_INVALIDCALL;
5957 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5958 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5959 return WINED3DERR_INVALIDCALL;
5962 if(Swapchain->frontBuffer != Front) {
5963 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5965 if(Swapchain->frontBuffer)
5967 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5968 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5970 Swapchain->frontBuffer = Front;
5972 if(Swapchain->frontBuffer) {
5973 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5974 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5978 if(Back && !Swapchain->backBuffer) {
5979 /* We need memory for the back buffer array - only one back buffer this way */
5980 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5981 if(!Swapchain->backBuffer) {
5982 ERR("Out of memory\n");
5983 return E_OUTOFMEMORY;
5987 if(Swapchain->backBuffer[0] != Back) {
5988 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5990 /* What to do about the context here in the case of multithreading? Not sure.
5991 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5993 WARN("No active context?\n");
5995 ENTER_GL();
5996 if(!Swapchain->backBuffer[0]) {
5997 /* GL was told to draw to the front buffer at creation,
5998 * undo that
6000 glDrawBuffer(GL_BACK);
6001 checkGLcall("glDrawBuffer(GL_BACK)");
6002 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6003 Swapchain->presentParms.BackBufferCount = 1;
6004 } else if (!Back) {
6005 /* That makes problems - disable for now */
6006 /* glDrawBuffer(GL_FRONT); */
6007 checkGLcall("glDrawBuffer(GL_FRONT)");
6008 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6009 Swapchain->presentParms.BackBufferCount = 0;
6011 LEAVE_GL();
6013 if(Swapchain->backBuffer[0])
6015 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6016 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6018 Swapchain->backBuffer[0] = Back;
6020 if(Swapchain->backBuffer[0]) {
6021 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6022 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6023 } else {
6024 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6025 Swapchain->backBuffer = NULL;
6030 return WINED3D_OK;
6033 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6035 *ppZStencilSurface = This->stencilBufferTarget;
6036 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6038 if(*ppZStencilSurface != NULL) {
6039 /* Note inc ref on returned surface */
6040 IWineD3DSurface_AddRef(*ppZStencilSurface);
6041 return WINED3D_OK;
6042 } else {
6043 return WINED3DERR_NOTFOUND;
6047 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6048 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6051 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6052 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6053 const struct wined3d_gl_info *gl_info;
6054 struct wined3d_context *context;
6055 GLenum gl_filter;
6056 POINT offset = {0, 0};
6058 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6059 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6060 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6061 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6063 switch (filter) {
6064 case WINED3DTEXF_LINEAR:
6065 gl_filter = GL_LINEAR;
6066 break;
6068 default:
6069 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6070 case WINED3DTEXF_NONE:
6071 case WINED3DTEXF_POINT:
6072 gl_filter = GL_NEAREST;
6073 break;
6076 /* Attach src surface to src fbo */
6077 src_swapchain = get_swapchain(src_surface);
6078 dst_swapchain = get_swapchain(dst_surface);
6080 if (src_swapchain) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
6081 else if (dst_swapchain) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6082 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6084 gl_info = context->gl_info;
6086 if (src_swapchain) {
6087 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6089 TRACE("Source surface %p is onscreen\n", src_surface);
6090 /* Make sure the drawable is up to date. In the offscreen case
6091 * attach_surface_fbo() implicitly takes care of this. */
6092 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6094 if(buffer == GL_FRONT) {
6095 RECT windowsize;
6096 UINT h;
6097 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6098 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6099 h = windowsize.bottom - windowsize.top;
6100 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6101 src_rect->y1 = offset.y + h - src_rect->y1;
6102 src_rect->y2 = offset.y + h - src_rect->y2;
6103 } else {
6104 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6105 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6108 ENTER_GL();
6109 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
6110 glReadBuffer(buffer);
6111 checkGLcall("glReadBuffer()");
6112 } else {
6113 TRACE("Source surface %p is offscreen\n", src_surface);
6114 ENTER_GL();
6115 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
6116 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
6117 glReadBuffer(GL_COLOR_ATTACHMENT0);
6118 checkGLcall("glReadBuffer()");
6119 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
6121 LEAVE_GL();
6123 /* Attach dst surface to dst fbo */
6124 if (dst_swapchain) {
6125 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6127 TRACE("Destination surface %p is onscreen\n", dst_surface);
6128 /* Make sure the drawable is up to date. In the offscreen case
6129 * attach_surface_fbo() implicitly takes care of this. */
6130 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6132 if(buffer == GL_FRONT) {
6133 RECT windowsize;
6134 UINT h;
6135 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6136 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6137 h = windowsize.bottom - windowsize.top;
6138 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6139 dst_rect->y1 = offset.y + h - dst_rect->y1;
6140 dst_rect->y2 = offset.y + h - dst_rect->y2;
6141 } else {
6142 /* Screen coords = window coords, surface height = window height */
6143 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6144 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6147 ENTER_GL();
6148 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
6149 glDrawBuffer(buffer);
6150 checkGLcall("glDrawBuffer()");
6151 } else {
6152 TRACE("Destination surface %p is offscreen\n", dst_surface);
6154 ENTER_GL();
6155 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
6156 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
6157 glDrawBuffer(GL_COLOR_ATTACHMENT0);
6158 checkGLcall("glDrawBuffer()");
6159 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
6161 glDisable(GL_SCISSOR_TEST);
6162 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6164 if (flip) {
6165 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6166 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
6167 checkGLcall("glBlitFramebuffer()");
6168 } else {
6169 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6170 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
6171 checkGLcall("glBlitFramebuffer()");
6174 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6176 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6177 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6178 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6179 glDrawBuffer(GL_BACK);
6180 checkGLcall("glDrawBuffer()");
6182 LEAVE_GL();
6184 context_release(context);
6187 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6189 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
6191 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6193 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
6195 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6196 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
6197 return WINED3DERR_INVALIDCALL;
6200 /* MSDN says that null disables the render target
6201 but a device must always be associated with a render target
6202 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6204 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6205 FIXME("Trying to set render target 0 to NULL\n");
6206 return WINED3DERR_INVALIDCALL;
6208 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6209 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);
6210 return WINED3DERR_INVALIDCALL;
6213 /* If we are trying to set what we already have, don't bother */
6214 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6215 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6216 return WINED3D_OK;
6218 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6219 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6220 This->render_targets[RenderTargetIndex] = pRenderTarget;
6222 /* Render target 0 is special */
6223 if(RenderTargetIndex == 0 && dxVersion > 7) {
6224 /* Finally, reset the viewport and scissor rect as the MSDN states.
6225 * Tests show that stateblock recording is ignored, the change goes
6226 * directly into the primary stateblock.
6228 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6229 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6230 This->stateBlock->viewport.X = 0;
6231 This->stateBlock->viewport.Y = 0;
6232 This->stateBlock->viewport.MaxZ = 1.0f;
6233 This->stateBlock->viewport.MinZ = 0.0f;
6234 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6236 This->stateBlock->scissorRect.top = 0;
6237 This->stateBlock->scissorRect.left = 0;
6238 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
6239 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
6240 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6242 return WINED3D_OK;
6245 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6247 HRESULT hr = WINED3D_OK;
6248 IWineD3DSurface *tmp;
6250 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6252 if (pNewZStencil == This->stencilBufferTarget) {
6253 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6254 } else {
6255 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6256 * depending on the renter target implementation being used.
6257 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6258 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6259 * stencil buffer and incur an extra memory overhead
6260 ******************************************************/
6262 if (This->stencilBufferTarget) {
6263 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6264 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6265 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6266 } else {
6267 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6268 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
6269 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6270 context_release(context);
6274 tmp = This->stencilBufferTarget;
6275 This->stencilBufferTarget = pNewZStencil;
6276 /* should we be calling the parent or the wined3d surface? */
6277 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6278 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6279 hr = WINED3D_OK;
6281 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6282 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6283 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6284 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6285 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6289 return hr;
6292 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6293 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6295 /* TODO: the use of Impl is deprecated. */
6296 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6297 WINED3DLOCKED_RECT lockedRect;
6299 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6301 /* some basic validation checks */
6302 if(This->cursorTexture) {
6303 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6304 ENTER_GL();
6305 glDeleteTextures(1, &This->cursorTexture);
6306 LEAVE_GL();
6307 context_release(context);
6308 This->cursorTexture = 0;
6311 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6312 This->haveHardwareCursor = TRUE;
6313 else
6314 This->haveHardwareCursor = FALSE;
6316 if(pCursorBitmap) {
6317 WINED3DLOCKED_RECT rect;
6319 /* MSDN: Cursor must be A8R8G8B8 */
6320 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6322 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6323 return WINED3DERR_INVALIDCALL;
6326 /* MSDN: Cursor must be smaller than the display mode */
6327 if(pSur->currentDesc.Width > This->ddraw_width ||
6328 pSur->currentDesc.Height > This->ddraw_height) {
6329 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);
6330 return WINED3DERR_INVALIDCALL;
6333 if (!This->haveHardwareCursor) {
6334 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6336 /* Do not store the surface's pointer because the application may
6337 * release it after setting the cursor image. Windows doesn't
6338 * addref the set surface, so we can't do this either without
6339 * creating circular refcount dependencies. Copy out the gl texture
6340 * instead.
6342 This->cursorWidth = pSur->currentDesc.Width;
6343 This->cursorHeight = pSur->currentDesc.Height;
6344 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6346 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6347 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6348 struct wined3d_context *context;
6349 char *mem, *bits = rect.pBits;
6350 GLint intfmt = glDesc->glInternal;
6351 GLint format = glDesc->glFormat;
6352 GLint type = glDesc->glType;
6353 INT height = This->cursorHeight;
6354 INT width = This->cursorWidth;
6355 INT bpp = glDesc->byte_count;
6356 DWORD sampler;
6357 INT i;
6359 /* Reformat the texture memory (pitch and width can be
6360 * different) */
6361 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6362 for(i = 0; i < height; i++)
6363 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6364 IWineD3DSurface_UnlockRect(pCursorBitmap);
6366 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6368 ENTER_GL();
6370 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6372 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6373 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6376 /* Make sure that a proper texture unit is selected */
6377 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6378 checkGLcall("glActiveTextureARB");
6379 sampler = This->rev_tex_unit_map[0];
6380 if (sampler != WINED3D_UNMAPPED_STAGE)
6382 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6384 /* Create a new cursor texture */
6385 glGenTextures(1, &This->cursorTexture);
6386 checkGLcall("glGenTextures");
6387 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6388 checkGLcall("glBindTexture");
6389 /* Copy the bitmap memory into the cursor texture */
6390 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6391 HeapFree(GetProcessHeap(), 0, mem);
6392 checkGLcall("glTexImage2D");
6394 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6396 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6397 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6400 LEAVE_GL();
6402 context_release(context);
6404 else
6406 FIXME("A cursor texture was not returned.\n");
6407 This->cursorTexture = 0;
6410 else
6412 /* Draw a hardware cursor */
6413 ICONINFO cursorInfo;
6414 HCURSOR cursor;
6415 /* Create and clear maskBits because it is not needed for
6416 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6417 * chunks. */
6418 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6419 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6420 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6421 WINED3DLOCK_NO_DIRTY_UPDATE |
6422 WINED3DLOCK_READONLY
6424 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6425 pSur->currentDesc.Height);
6427 cursorInfo.fIcon = FALSE;
6428 cursorInfo.xHotspot = XHotSpot;
6429 cursorInfo.yHotspot = YHotSpot;
6430 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6431 1, 1, maskBits);
6432 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6433 1, 32, lockedRect.pBits);
6434 IWineD3DSurface_UnlockRect(pCursorBitmap);
6435 /* Create our cursor and clean up. */
6436 cursor = CreateIconIndirect(&cursorInfo);
6437 SetCursor(cursor);
6438 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6439 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6440 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6441 This->hardwareCursor = cursor;
6442 HeapFree(GetProcessHeap(), 0, maskBits);
6446 This->xHotSpot = XHotSpot;
6447 This->yHotSpot = YHotSpot;
6448 return WINED3D_OK;
6451 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6453 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6455 This->xScreenSpace = XScreenSpace;
6456 This->yScreenSpace = YScreenSpace;
6458 return;
6462 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6464 BOOL oldVisible = This->bCursorVisible;
6465 POINT pt;
6467 TRACE("(%p) : visible(%d)\n", This, bShow);
6470 * When ShowCursor is first called it should make the cursor appear at the OS's last
6471 * known cursor position. Because of this, some applications just repetitively call
6472 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6474 GetCursorPos(&pt);
6475 This->xScreenSpace = pt.x;
6476 This->yScreenSpace = pt.y;
6478 if (This->haveHardwareCursor) {
6479 This->bCursorVisible = bShow;
6480 if (bShow)
6481 SetCursor(This->hardwareCursor);
6482 else
6483 SetCursor(NULL);
6485 else
6487 if (This->cursorTexture)
6488 This->bCursorVisible = bShow;
6491 return oldVisible;
6494 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6496 IWineD3DResourceImpl *resource;
6497 TRACE("(%p) : state (%u)\n", This, This->state);
6499 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6500 switch (This->state) {
6501 case WINED3D_OK:
6502 return WINED3D_OK;
6503 case WINED3DERR_DEVICELOST:
6505 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6506 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6507 return WINED3DERR_DEVICENOTRESET;
6509 return WINED3DERR_DEVICELOST;
6511 case WINED3DERR_DRIVERINTERNALERROR:
6512 return WINED3DERR_DRIVERINTERNALERROR;
6515 /* Unknown state */
6516 return WINED3DERR_DRIVERINTERNALERROR;
6519 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6520 TRACE("checking resource %p for eviction\n", resource);
6521 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6522 TRACE("Evicting %p\n", resource);
6523 IWineD3DResource_UnLoad(resource);
6525 IWineD3DResource_Release(resource);
6526 return S_OK;
6529 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6531 TRACE("(%p)\n", This);
6533 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6534 return WINED3D_OK;
6537 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6539 IWineD3DDeviceImpl *device = surface->resource.wineD3DDevice;
6540 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6542 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6543 if(surface->Flags & SFLAG_DIBSECTION) {
6544 /* Release the DC */
6545 SelectObject(surface->hDC, surface->dib.holdbitmap);
6546 DeleteDC(surface->hDC);
6547 /* Release the DIB section */
6548 DeleteObject(surface->dib.DIBsection);
6549 surface->dib.bitmap_data = NULL;
6550 surface->resource.allocatedMemory = NULL;
6551 surface->Flags &= ~SFLAG_DIBSECTION;
6553 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6554 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6555 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6556 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6558 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6559 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6560 } else {
6561 surface->pow2Width = surface->pow2Height = 1;
6562 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6563 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6565 surface->glRect.left = 0;
6566 surface->glRect.top = 0;
6567 surface->glRect.right = surface->pow2Width;
6568 surface->glRect.bottom = surface->pow2Height;
6570 if (surface->texture_name)
6572 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6573 ENTER_GL();
6574 glDeleteTextures(1, &surface->texture_name);
6575 LEAVE_GL();
6576 context_release(context);
6577 surface->texture_name = 0;
6578 surface->Flags &= ~SFLAG_CLIENT;
6580 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6581 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6582 surface->Flags |= SFLAG_NONPOW2;
6583 } else {
6584 surface->Flags &= ~SFLAG_NONPOW2;
6586 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6587 surface->resource.allocatedMemory = NULL;
6588 surface->resource.heapMemory = NULL;
6589 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6590 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6591 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6592 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6593 } else {
6594 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6598 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6599 TRACE("Unloading resource %p\n", resource);
6600 IWineD3DResource_UnLoad(resource);
6601 IWineD3DResource_Release(resource);
6602 return S_OK;
6605 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6607 UINT i, count;
6608 WINED3DDISPLAYMODE m;
6609 HRESULT hr;
6611 /* All Windowed modes are supported, as is leaving the current mode */
6612 if(pp->Windowed) return TRUE;
6613 if(!pp->BackBufferWidth) return TRUE;
6614 if(!pp->BackBufferHeight) return TRUE;
6616 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6617 for(i = 0; i < count; i++) {
6618 memset(&m, 0, sizeof(m));
6619 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6620 if(FAILED(hr)) {
6621 ERR("EnumAdapterModes failed\n");
6623 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6624 /* Mode found, it is supported */
6625 return TRUE;
6628 /* Mode not found -> not supported */
6629 return FALSE;
6632 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6634 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6635 const struct wined3d_gl_info *gl_info;
6636 struct wined3d_context *context;
6637 UINT i;
6638 IWineD3DBaseShaderImpl *shader;
6640 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6641 gl_info = context->gl_info;
6643 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6644 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6645 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6648 ENTER_GL();
6649 if(This->depth_blt_texture) {
6650 glDeleteTextures(1, &This->depth_blt_texture);
6651 This->depth_blt_texture = 0;
6653 if (This->depth_blt_rb) {
6654 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6655 This->depth_blt_rb = 0;
6656 This->depth_blt_rb_w = 0;
6657 This->depth_blt_rb_h = 0;
6659 LEAVE_GL();
6661 This->blitter->free_private(iface);
6662 This->frag_pipe->free_private(iface);
6663 This->shader_backend->shader_free_private(iface);
6665 ENTER_GL();
6666 for (i = 0; i < This->adapter->gl_info.limits.textures; ++i)
6668 /* Textures are recreated below */
6669 glDeleteTextures(1, &This->dummyTextureName[i]);
6670 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6671 This->dummyTextureName[i] = 0;
6673 LEAVE_GL();
6675 context_release(context);
6677 while (This->numContexts)
6679 context_destroy(This, This->contexts[0]);
6681 HeapFree(GetProcessHeap(), 0, swapchain->context);
6682 swapchain->context = NULL;
6683 swapchain->num_contexts = 0;
6686 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6688 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6689 HRESULT hr;
6690 IWineD3DSurfaceImpl *target;
6692 /* Recreate the primary swapchain's context */
6693 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6694 if(swapchain->backBuffer) {
6695 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6696 } else {
6697 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6699 swapchain->context[0] = context_create(This, target, swapchain->win_handle, FALSE, &swapchain->presentParms);
6700 swapchain->num_contexts = 1;
6702 create_dummy_textures(This);
6704 context_release(swapchain->context[0]);
6706 hr = This->shader_backend->shader_alloc_private(iface);
6707 if(FAILED(hr)) {
6708 ERR("Failed to recreate shader private data\n");
6709 goto err_out;
6711 hr = This->frag_pipe->alloc_private(iface);
6712 if(FAILED(hr)) {
6713 TRACE("Fragment pipeline private data couldn't be allocated\n");
6714 goto err_out;
6716 hr = This->blitter->alloc_private(iface);
6717 if(FAILED(hr)) {
6718 TRACE("Blitter private data couldn't be allocated\n");
6719 goto err_out;
6722 return WINED3D_OK;
6724 err_out:
6725 This->blitter->free_private(iface);
6726 This->frag_pipe->free_private(iface);
6727 This->shader_backend->shader_free_private(iface);
6728 return hr;
6731 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6733 IWineD3DSwapChainImpl *swapchain;
6734 HRESULT hr;
6735 BOOL DisplayModeChanged = FALSE;
6736 WINED3DDISPLAYMODE mode;
6737 TRACE("(%p)\n", This);
6739 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6740 if(FAILED(hr)) {
6741 ERR("Failed to get the first implicit swapchain\n");
6742 return hr;
6745 if(!is_display_mode_supported(This, pPresentationParameters)) {
6746 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6747 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6748 pPresentationParameters->BackBufferHeight);
6749 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6750 return WINED3DERR_INVALIDCALL;
6753 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6754 * on an existing gl context, so there's no real need for recreation.
6756 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6758 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6760 TRACE("New params:\n");
6761 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6762 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6763 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6764 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6765 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6766 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6767 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6768 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6769 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6770 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6771 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6772 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6773 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6775 /* No special treatment of these parameters. Just store them */
6776 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6777 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6778 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6779 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6781 /* What to do about these? */
6782 if(pPresentationParameters->BackBufferCount != 0 &&
6783 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6784 ERR("Cannot change the back buffer count yet\n");
6786 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6787 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6788 ERR("Cannot change the back buffer format yet\n");
6790 if(pPresentationParameters->hDeviceWindow != NULL &&
6791 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6792 ERR("Cannot change the device window yet\n");
6794 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6795 HRESULT hrc;
6797 TRACE("Creating the depth stencil buffer\n");
6799 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6800 This->parent,
6801 pPresentationParameters->BackBufferWidth,
6802 pPresentationParameters->BackBufferHeight,
6803 pPresentationParameters->AutoDepthStencilFormat,
6804 pPresentationParameters->MultiSampleType,
6805 pPresentationParameters->MultiSampleQuality,
6806 FALSE,
6807 &This->auto_depth_stencil_buffer);
6809 if (FAILED(hrc)) {
6810 ERR("Failed to create the depth stencil buffer\n");
6811 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6812 return WINED3DERR_INVALIDCALL;
6816 /* Reset the depth stencil */
6817 if (pPresentationParameters->EnableAutoDepthStencil)
6818 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6819 else
6820 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6822 TRACE("Resetting stateblock\n");
6823 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6824 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6826 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6828 if(pPresentationParameters->Windowed) {
6829 mode.Width = swapchain->orig_width;
6830 mode.Height = swapchain->orig_height;
6831 mode.RefreshRate = 0;
6832 mode.Format = swapchain->presentParms.BackBufferFormat;
6833 } else {
6834 mode.Width = pPresentationParameters->BackBufferWidth;
6835 mode.Height = pPresentationParameters->BackBufferHeight;
6836 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6837 mode.Format = swapchain->presentParms.BackBufferFormat;
6840 /* Should Width == 800 && Height == 0 set 800x600? */
6841 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6842 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6843 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6845 UINT i;
6847 if(!pPresentationParameters->Windowed) {
6848 DisplayModeChanged = TRUE;
6850 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6851 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6853 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6854 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6855 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6857 if(This->auto_depth_stencil_buffer) {
6858 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6862 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6863 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6864 DisplayModeChanged) {
6866 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6868 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
6869 if(swapchain->presentParms.Windowed) {
6870 /* switch from windowed to fs */
6871 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
6872 pPresentationParameters->BackBufferWidth,
6873 pPresentationParameters->BackBufferHeight);
6874 } else {
6875 /* Fullscreen -> fullscreen mode change */
6876 MoveWindow(swapchain->win_handle, 0, 0,
6877 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6878 TRUE);
6880 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
6881 /* Fullscreen -> windowed switch */
6882 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
6884 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6885 } else if(!pPresentationParameters->Windowed) {
6886 DWORD style = This->style, exStyle = This->exStyle;
6887 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6888 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6889 * Reset to clear up their mess. Guild Wars also loses the device during that.
6891 This->style = 0;
6892 This->exStyle = 0;
6893 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
6894 pPresentationParameters->BackBufferWidth,
6895 pPresentationParameters->BackBufferHeight);
6896 This->style = style;
6897 This->exStyle = exStyle;
6900 /* Note: No parent needed for initial internal stateblock */
6901 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6902 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6903 else TRACE("Created stateblock %p\n", This->stateBlock);
6904 This->updateStateBlock = This->stateBlock;
6905 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6907 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6908 if(FAILED(hr)) {
6909 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6912 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6913 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6915 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6916 * first use
6918 return hr;
6921 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6923 /** FIXME: always true at the moment **/
6924 if(!bEnableDialogs) {
6925 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6927 return WINED3D_OK;
6931 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6933 TRACE("(%p) : pParameters %p\n", This, pParameters);
6935 *pParameters = This->createParms;
6936 return WINED3D_OK;
6939 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6940 IWineD3DSwapChain *swapchain;
6942 TRACE("Relaying to swapchain\n");
6944 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6945 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6946 IWineD3DSwapChain_Release(swapchain);
6948 return;
6951 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6952 IWineD3DSwapChain *swapchain;
6954 TRACE("Relaying to swapchain\n");
6956 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6957 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6958 IWineD3DSwapChain_Release(swapchain);
6960 return;
6964 /** ********************************************************
6965 * Notification functions
6966 ** ********************************************************/
6967 /** This function must be called in the release of a resource when ref == 0,
6968 * the contents of resource must still be correct,
6969 * any handles to other resource held by the caller must be closed
6970 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6971 *****************************************************/
6972 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6974 TRACE("(%p) : Adding resource %p\n", This, resource);
6976 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6979 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6981 TRACE("(%p) : Removing resource %p\n", This, resource);
6983 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6986 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6988 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6989 int counter;
6991 TRACE("(%p) : resource %p\n", This, resource);
6993 context_resource_released((IWineD3DDevice *)This, resource, type);
6995 switch (type) {
6996 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6997 case WINED3DRTYPE_SURFACE: {
6998 unsigned int i;
7000 if (This->d3d_initialized)
7002 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
7004 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7005 This->render_targets[i] = NULL;
7008 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7009 This->stencilBufferTarget = NULL;
7013 break;
7015 case WINED3DRTYPE_TEXTURE:
7016 case WINED3DRTYPE_CUBETEXTURE:
7017 case WINED3DRTYPE_VOLUMETEXTURE:
7018 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7019 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7020 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7021 This->stateBlock->textures[counter] = NULL;
7023 if (This->updateStateBlock != This->stateBlock ){
7024 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7025 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7026 This->updateStateBlock->textures[counter] = NULL;
7030 break;
7031 case WINED3DRTYPE_VOLUME:
7032 /* TODO: nothing really? */
7033 break;
7034 case WINED3DRTYPE_BUFFER:
7036 int streamNumber;
7037 TRACE("Cleaning up stream pointers\n");
7039 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7040 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7041 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7043 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7044 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7045 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7046 This->updateStateBlock->streamSource[streamNumber] = 0;
7047 /* Set changed flag? */
7050 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) */
7051 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7052 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7053 This->stateBlock->streamSource[streamNumber] = 0;
7058 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7059 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7060 This->updateStateBlock->pIndexData = NULL;
7063 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7064 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7065 This->stateBlock->pIndexData = NULL;
7069 break;
7071 default:
7072 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7073 break;
7077 /* Remove the resource from the resourceStore */
7078 device_resource_remove(This, resource);
7080 TRACE("Resource released\n");
7084 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7086 IWineD3DResourceImpl *resource, *cursor;
7087 HRESULT ret;
7088 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7090 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7091 TRACE("enumerating resource %p\n", resource);
7092 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7093 ret = pCallback((IWineD3DResource *) resource, pData);
7094 if(ret == S_FALSE) {
7095 TRACE("Canceling enumeration\n");
7096 break;
7099 return WINED3D_OK;
7102 /**********************************************************
7103 * IWineD3DDevice VTbl follows
7104 **********************************************************/
7106 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7108 /*** IUnknown methods ***/
7109 IWineD3DDeviceImpl_QueryInterface,
7110 IWineD3DDeviceImpl_AddRef,
7111 IWineD3DDeviceImpl_Release,
7112 /*** IWineD3DDevice methods ***/
7113 IWineD3DDeviceImpl_GetParent,
7114 /*** Creation methods**/
7115 IWineD3DDeviceImpl_CreateBuffer,
7116 IWineD3DDeviceImpl_CreateVertexBuffer,
7117 IWineD3DDeviceImpl_CreateIndexBuffer,
7118 IWineD3DDeviceImpl_CreateStateBlock,
7119 IWineD3DDeviceImpl_CreateSurface,
7120 IWineD3DDeviceImpl_CreateRendertargetView,
7121 IWineD3DDeviceImpl_CreateTexture,
7122 IWineD3DDeviceImpl_CreateVolumeTexture,
7123 IWineD3DDeviceImpl_CreateVolume,
7124 IWineD3DDeviceImpl_CreateCubeTexture,
7125 IWineD3DDeviceImpl_CreateQuery,
7126 IWineD3DDeviceImpl_CreateSwapChain,
7127 IWineD3DDeviceImpl_CreateVertexDeclaration,
7128 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7129 IWineD3DDeviceImpl_CreateVertexShader,
7130 IWineD3DDeviceImpl_CreatePixelShader,
7131 IWineD3DDeviceImpl_CreatePalette,
7132 /*** Odd functions **/
7133 IWineD3DDeviceImpl_Init3D,
7134 IWineD3DDeviceImpl_InitGDI,
7135 IWineD3DDeviceImpl_Uninit3D,
7136 IWineD3DDeviceImpl_UninitGDI,
7137 IWineD3DDeviceImpl_SetMultithreaded,
7138 IWineD3DDeviceImpl_EvictManagedResources,
7139 IWineD3DDeviceImpl_GetAvailableTextureMem,
7140 IWineD3DDeviceImpl_GetBackBuffer,
7141 IWineD3DDeviceImpl_GetCreationParameters,
7142 IWineD3DDeviceImpl_GetDeviceCaps,
7143 IWineD3DDeviceImpl_GetDirect3D,
7144 IWineD3DDeviceImpl_GetDisplayMode,
7145 IWineD3DDeviceImpl_SetDisplayMode,
7146 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7147 IWineD3DDeviceImpl_GetRasterStatus,
7148 IWineD3DDeviceImpl_GetSwapChain,
7149 IWineD3DDeviceImpl_Reset,
7150 IWineD3DDeviceImpl_SetDialogBoxMode,
7151 IWineD3DDeviceImpl_SetCursorProperties,
7152 IWineD3DDeviceImpl_SetCursorPosition,
7153 IWineD3DDeviceImpl_ShowCursor,
7154 IWineD3DDeviceImpl_TestCooperativeLevel,
7155 /*** Getters and setters **/
7156 IWineD3DDeviceImpl_SetClipPlane,
7157 IWineD3DDeviceImpl_GetClipPlane,
7158 IWineD3DDeviceImpl_SetClipStatus,
7159 IWineD3DDeviceImpl_GetClipStatus,
7160 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7161 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7162 IWineD3DDeviceImpl_SetDepthStencilSurface,
7163 IWineD3DDeviceImpl_GetDepthStencilSurface,
7164 IWineD3DDeviceImpl_SetGammaRamp,
7165 IWineD3DDeviceImpl_GetGammaRamp,
7166 IWineD3DDeviceImpl_SetIndexBuffer,
7167 IWineD3DDeviceImpl_GetIndexBuffer,
7168 IWineD3DDeviceImpl_SetBaseVertexIndex,
7169 IWineD3DDeviceImpl_GetBaseVertexIndex,
7170 IWineD3DDeviceImpl_SetLight,
7171 IWineD3DDeviceImpl_GetLight,
7172 IWineD3DDeviceImpl_SetLightEnable,
7173 IWineD3DDeviceImpl_GetLightEnable,
7174 IWineD3DDeviceImpl_SetMaterial,
7175 IWineD3DDeviceImpl_GetMaterial,
7176 IWineD3DDeviceImpl_SetNPatchMode,
7177 IWineD3DDeviceImpl_GetNPatchMode,
7178 IWineD3DDeviceImpl_SetPaletteEntries,
7179 IWineD3DDeviceImpl_GetPaletteEntries,
7180 IWineD3DDeviceImpl_SetPixelShader,
7181 IWineD3DDeviceImpl_GetPixelShader,
7182 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7183 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7184 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7185 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7186 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7187 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7188 IWineD3DDeviceImpl_SetRenderState,
7189 IWineD3DDeviceImpl_GetRenderState,
7190 IWineD3DDeviceImpl_SetRenderTarget,
7191 IWineD3DDeviceImpl_GetRenderTarget,
7192 IWineD3DDeviceImpl_SetFrontBackBuffers,
7193 IWineD3DDeviceImpl_SetSamplerState,
7194 IWineD3DDeviceImpl_GetSamplerState,
7195 IWineD3DDeviceImpl_SetScissorRect,
7196 IWineD3DDeviceImpl_GetScissorRect,
7197 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7198 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7199 IWineD3DDeviceImpl_SetStreamSource,
7200 IWineD3DDeviceImpl_GetStreamSource,
7201 IWineD3DDeviceImpl_SetStreamSourceFreq,
7202 IWineD3DDeviceImpl_GetStreamSourceFreq,
7203 IWineD3DDeviceImpl_SetTexture,
7204 IWineD3DDeviceImpl_GetTexture,
7205 IWineD3DDeviceImpl_SetTextureStageState,
7206 IWineD3DDeviceImpl_GetTextureStageState,
7207 IWineD3DDeviceImpl_SetTransform,
7208 IWineD3DDeviceImpl_GetTransform,
7209 IWineD3DDeviceImpl_SetVertexDeclaration,
7210 IWineD3DDeviceImpl_GetVertexDeclaration,
7211 IWineD3DDeviceImpl_SetVertexShader,
7212 IWineD3DDeviceImpl_GetVertexShader,
7213 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7214 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7215 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7216 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7217 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7218 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7219 IWineD3DDeviceImpl_SetViewport,
7220 IWineD3DDeviceImpl_GetViewport,
7221 IWineD3DDeviceImpl_MultiplyTransform,
7222 IWineD3DDeviceImpl_ValidateDevice,
7223 IWineD3DDeviceImpl_ProcessVertices,
7224 /*** State block ***/
7225 IWineD3DDeviceImpl_BeginStateBlock,
7226 IWineD3DDeviceImpl_EndStateBlock,
7227 /*** Scene management ***/
7228 IWineD3DDeviceImpl_BeginScene,
7229 IWineD3DDeviceImpl_EndScene,
7230 IWineD3DDeviceImpl_Present,
7231 IWineD3DDeviceImpl_Clear,
7232 IWineD3DDeviceImpl_ClearRendertargetView,
7233 /*** Drawing ***/
7234 IWineD3DDeviceImpl_SetPrimitiveType,
7235 IWineD3DDeviceImpl_GetPrimitiveType,
7236 IWineD3DDeviceImpl_DrawPrimitive,
7237 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7238 IWineD3DDeviceImpl_DrawPrimitiveUP,
7239 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7240 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7241 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7242 IWineD3DDeviceImpl_DrawRectPatch,
7243 IWineD3DDeviceImpl_DrawTriPatch,
7244 IWineD3DDeviceImpl_DeletePatch,
7245 IWineD3DDeviceImpl_ColorFill,
7246 IWineD3DDeviceImpl_UpdateTexture,
7247 IWineD3DDeviceImpl_UpdateSurface,
7248 IWineD3DDeviceImpl_GetFrontBufferData,
7249 /*** object tracking ***/
7250 IWineD3DDeviceImpl_EnumResources
7253 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7254 DWORD rep = This->StateTable[state].representative;
7255 struct wined3d_context *context;
7256 DWORD idx;
7257 BYTE shift;
7258 UINT i;
7260 for(i = 0; i < This->numContexts; i++) {
7261 context = This->contexts[i];
7262 if(isStateDirty(context, rep)) continue;
7264 context->dirtyArray[context->numDirtyEntries++] = rep;
7265 idx = rep >> 5;
7266 shift = rep & 0x1f;
7267 context->isStateDirty[idx] |= (1 << shift);
7271 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7273 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.wineD3DDevice;
7274 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7275 *width = device->pbufferWidth;
7276 *height = device->pbufferHeight;
7279 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7281 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7282 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7283 *width = surface->pow2Width;
7284 *height = surface->pow2Height;
7287 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7289 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7290 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7291 * current context's drawable, which is the size of the back buffer of the swapchain
7292 * the active context belongs to. The back buffer of the swapchain is stored as the
7293 * surface the context belongs to. */
7294 *width = surface->currentDesc.Width;
7295 *height = surface->currentDesc.Height;