winealsa.drv: Fix DSOUND_BufPtrDiff in Kane's Wrath with new audio pathway.
[wine/multimedia.git] / dlls / wined3d / device.c
blobc5b8d971ec86aff2581e7e8fd169712240b8fc19
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "config.h"
30 #include <stdio.h>
31 #ifdef HAVE_FLOAT_H
32 # include <float.h>
33 #endif
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
37 #define GLINFO_LOCATION This->adapter->gl_info
39 /* Define the default light parameters as specified by MSDN */
40 const WINED3DLIGHT WINED3D_default_light = {
42 WINED3DLIGHT_DIRECTIONAL, /* Type */
43 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
45 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
46 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
47 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
48 0.0f, /* Range */
49 0.0f, /* Falloff */
50 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
51 0.0f, /* Theta */
52 0.0f /* Phi */
55 /**********************************************************
56 * Global variable / Constants follow
57 **********************************************************/
58 const float identity[] =
60 1.0f, 0.0f, 0.0f, 0.0f,
61 0.0f, 1.0f, 0.0f, 0.0f,
62 0.0f, 0.0f, 1.0f, 0.0f,
63 0.0f, 0.0f, 0.0f, 1.0f,
64 }; /* When needed for comparisons */
66 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
67 * actually have the same values in GL and D3D. */
68 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
70 switch(primitive_type)
72 case WINED3DPT_POINTLIST:
73 return GL_POINTS;
75 case WINED3DPT_LINELIST:
76 return GL_LINES;
78 case WINED3DPT_LINESTRIP:
79 return GL_LINE_STRIP;
81 case WINED3DPT_TRIANGLELIST:
82 return GL_TRIANGLES;
84 case WINED3DPT_TRIANGLESTRIP:
85 return GL_TRIANGLE_STRIP;
87 case WINED3DPT_TRIANGLEFAN:
88 return GL_TRIANGLE_FAN;
90 case WINED3DPT_LINELIST_ADJ:
91 return GL_LINES_ADJACENCY_ARB;
93 case WINED3DPT_LINESTRIP_ADJ:
94 return GL_LINE_STRIP_ADJACENCY_ARB;
96 case WINED3DPT_TRIANGLELIST_ADJ:
97 return GL_TRIANGLES_ADJACENCY_ARB;
99 case WINED3DPT_TRIANGLESTRIP_ADJ:
100 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
102 default:
103 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
104 return GL_NONE;
108 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
110 switch(primitive_type)
112 case GL_POINTS:
113 return WINED3DPT_POINTLIST;
115 case GL_LINES:
116 return WINED3DPT_LINELIST;
118 case GL_LINE_STRIP:
119 return WINED3DPT_LINESTRIP;
121 case GL_TRIANGLES:
122 return WINED3DPT_TRIANGLELIST;
124 case GL_TRIANGLE_STRIP:
125 return WINED3DPT_TRIANGLESTRIP;
127 case GL_TRIANGLE_FAN:
128 return WINED3DPT_TRIANGLEFAN;
130 case GL_LINES_ADJACENCY_ARB:
131 return WINED3DPT_LINELIST_ADJ;
133 case GL_LINE_STRIP_ADJACENCY_ARB:
134 return WINED3DPT_LINESTRIP_ADJ;
136 case GL_TRIANGLES_ADJACENCY_ARB:
137 return WINED3DPT_TRIANGLELIST_ADJ;
139 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
140 return WINED3DPT_TRIANGLESTRIP_ADJ;
142 default:
143 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
144 return WINED3DPT_UNDEFINED;
148 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
150 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
151 *regnum = WINED3D_FFP_POSITION;
152 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
153 *regnum = WINED3D_FFP_BLENDWEIGHT;
154 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
155 *regnum = WINED3D_FFP_BLENDINDICES;
156 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
157 *regnum = WINED3D_FFP_NORMAL;
158 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
159 *regnum = WINED3D_FFP_PSIZE;
160 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
161 *regnum = WINED3D_FFP_DIFFUSE;
162 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
163 *regnum = WINED3D_FFP_SPECULAR;
164 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
165 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
166 else
168 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
169 *regnum = ~0U;
170 return FALSE;
173 return TRUE;
176 /* Context activation is done by the caller. */
177 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
178 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
180 /* We need to deal with frequency data! */
181 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
182 UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
183 const DWORD *streams = declaration->streams;
184 unsigned int i;
186 stream_info->use_map = 0;
187 stream_info->swizzle_map = 0;
189 /* Check for transformed vertices, disable vertex shader if present. */
190 stream_info->position_transformed = declaration->position_transformed;
191 if (declaration->position_transformed) use_vshader = FALSE;
193 /* Translate the declaration into strided data. */
194 for (i = 0; i < declaration->element_count; ++i)
196 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
197 GLuint buffer_object = 0;
198 const BYTE *data = NULL;
199 BOOL stride_used;
200 unsigned int idx;
201 DWORD stride;
203 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
204 element, i + 1, declaration->element_count);
206 if (!This->stateBlock->streamSource[element->input_slot]) continue;
208 stride = This->stateBlock->streamStride[element->input_slot];
209 if (This->stateBlock->streamIsUP)
211 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
212 buffer_object = 0;
213 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
215 else
217 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
218 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
220 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
221 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
222 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
223 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
224 * not, drawStridedSlow is needed, including a vertex buffer path. */
225 if (This->stateBlock->loadBaseVertexIndex < 0)
227 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
228 buffer_object = 0;
229 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
230 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
232 FIXME("System memory vertex data load offset is negative!\n");
236 if (fixup)
238 if (buffer_object) *fixup = TRUE;
239 else if (*fixup && !use_vshader
240 && (element->usage == WINED3DDECLUSAGE_COLOR
241 || element->usage == WINED3DDECLUSAGE_POSITIONT))
243 static BOOL warned = FALSE;
244 if (!warned)
246 /* This may be bad with the fixed function pipeline. */
247 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
248 warned = TRUE;
253 data += element->offset;
255 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
257 if (use_vshader)
259 if (element->output_slot == ~0U)
261 /* TODO: Assuming vertexdeclarations are usually used with the
262 * same or a similar shader, it might be worth it to store the
263 * last used output slot and try that one first. */
264 stride_used = vshader_get_input(This->stateBlock->vertexShader,
265 element->usage, element->usage_idx, &idx);
267 else
269 idx = element->output_slot;
270 stride_used = TRUE;
273 else
275 if (!element->ffp_valid)
277 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
278 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
279 stride_used = FALSE;
281 else
283 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
287 if (stride_used)
289 TRACE("Load %s array %u [usage %s, usage_idx %u, "
290 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
291 use_vshader ? "shader": "fixed function", idx,
292 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
293 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
295 stream_info->elements[idx].format_desc = element->format_desc;
296 stream_info->elements[idx].stride = stride;
297 stream_info->elements[idx].data = data;
298 stream_info->elements[idx].stream_idx = element->input_slot;
299 stream_info->elements[idx].buffer_object = buffer_object;
301 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && element->format_desc->format == WINED3DFMT_A8R8G8B8)
303 stream_info->swizzle_map |= 1 << idx;
305 stream_info->use_map |= 1 << idx;
309 /* Now call PreLoad on all the vertex buffers. In the very rare case
310 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
311 * The vertex buffer can now use the strided structure in the device instead of finding its
312 * own again.
314 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
315 * once in there. */
316 for (i = 0; i < stream_count; ++i)
318 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
319 if (vb) IWineD3DBuffer_PreLoad(vb);
323 static void stream_info_element_from_strided(IWineD3DDeviceImpl *This,
324 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
326 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, &This->adapter->gl_info);
327 e->format_desc = format_desc;
328 e->stride = strided->dwStride;
329 e->data = strided->lpData;
330 e->stream_idx = 0;
331 e->buffer_object = 0;
334 void device_stream_info_from_strided(IWineD3DDeviceImpl *This,
335 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
337 unsigned int i;
339 memset(stream_info, 0, sizeof(*stream_info));
341 if (strided->position.lpData)
342 stream_info_element_from_strided(This, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
343 if (strided->normal.lpData)
344 stream_info_element_from_strided(This, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
345 if (strided->diffuse.lpData)
346 stream_info_element_from_strided(This, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
347 if (strided->specular.lpData)
348 stream_info_element_from_strided(This, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
350 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
352 if (strided->texCoords[i].lpData)
353 stream_info_element_from_strided(This, &strided->texCoords[i],
354 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
357 stream_info->position_transformed = strided->position_transformed;
359 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
361 if (!stream_info->elements[i].format_desc) continue;
363 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && stream_info->elements[i].format_desc->format == WINED3DFMT_A8R8G8B8)
365 stream_info->swizzle_map |= 1 << i;
367 stream_info->use_map |= 1 << i;
371 /**********************************************************
372 * IUnknown parts follows
373 **********************************************************/
375 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
379 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
380 if (IsEqualGUID(riid, &IID_IUnknown)
381 || IsEqualGUID(riid, &IID_IWineD3DBase)
382 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
383 IUnknown_AddRef(iface);
384 *ppobj = This;
385 return S_OK;
387 *ppobj = NULL;
388 return E_NOINTERFACE;
391 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
393 ULONG refCount = InterlockedIncrement(&This->ref);
395 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
396 return refCount;
399 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
401 ULONG refCount = InterlockedDecrement(&This->ref);
403 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
405 if (!refCount) {
406 UINT i;
408 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
409 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
410 This->multistate_funcs[i] = NULL;
413 /* TODO: Clean up all the surfaces and textures! */
414 /* NOTE: You must release the parent if the object was created via a callback
415 ** ***************************/
417 if (!list_empty(&This->resources)) {
418 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
419 dumpResources(&This->resources);
422 if(This->contexts) ERR("Context array not freed!\n");
423 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
424 This->haveHardwareCursor = FALSE;
426 IWineD3D_Release(This->wineD3D);
427 This->wineD3D = NULL;
428 HeapFree(GetProcessHeap(), 0, This);
429 TRACE("Freed device %p\n", This);
430 This = NULL;
432 return refCount;
435 /**********************************************************
436 * IWineD3DDevice implementation follows
437 **********************************************************/
438 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
440 *pParent = This->parent;
441 IUnknown_AddRef(This->parent);
442 return WINED3D_OK;
445 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface,
446 struct wined3d_buffer_desc *desc, const void *data, IUnknown *parent, IWineD3DBuffer **buffer)
448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
449 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_UNKNOWN, &This->adapter->gl_info);
450 struct wined3d_buffer *object;
451 HRESULT hr;
453 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
455 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
456 if (!object)
458 ERR("Failed to allocate memory\n");
459 return E_OUTOFMEMORY;
462 object->vtbl = &wined3d_buffer_vtbl;
463 object->desc = *desc;
465 FIXME("Ignoring access flags (pool)\n");
467 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, desc->byte_width,
468 desc->usage, format_desc, WINED3DPOOL_MANAGED, parent);
469 if (FAILED(hr))
471 WARN("Failed to initialize resource, returning %#x\n", hr);
472 HeapFree(GetProcessHeap(), 0, object);
473 return hr;
475 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
477 TRACE("Created resource %p\n", object);
479 TRACE("size %#x, usage=%#x, format %s, memory @ %p, iface @ %p\n", object->resource.size, object->resource.usage,
480 debug_d3dformat(object->resource.format_desc->format), object->resource.allocatedMemory, object);
482 if (data)
484 BYTE *ptr;
486 hr = IWineD3DBuffer_Map((IWineD3DBuffer *)object, 0, desc->byte_width, &ptr, 0);
487 if (FAILED(hr))
489 ERR("Failed to map buffer, hr %#x\n", hr);
490 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
491 return hr;
494 memcpy(ptr, data, desc->byte_width);
496 hr = IWineD3DBuffer_Unmap((IWineD3DBuffer *)object);
497 if (FAILED(hr))
499 ERR("Failed to unmap buffer, hr %#x\n", hr);
500 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
501 return hr;
505 *buffer = (IWineD3DBuffer *)object;
507 return WINED3D_OK;
510 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
511 DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer, IUnknown *parent)
513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
514 /* Dummy format for now */
515 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_VERTEXDATA, &This->adapter->gl_info);
516 struct wined3d_buffer *object;
517 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
518 HRESULT hr;
519 BOOL conv;
521 if(Size == 0) {
522 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
523 *ppVertexBuffer = NULL;
524 return WINED3DERR_INVALIDCALL;
525 } else if(Pool == WINED3DPOOL_SCRATCH) {
526 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
527 * anyway, SCRATCH vertex buffers aren't usable anywhere
529 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
530 *ppVertexBuffer = NULL;
531 return WINED3DERR_INVALIDCALL;
534 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
535 if (!object)
537 ERR("Out of memory\n");
538 *ppVertexBuffer = NULL;
539 return WINED3DERR_OUTOFVIDEOMEMORY;
542 object->vtbl = &wined3d_buffer_vtbl;
543 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, Size, Usage, format_desc, Pool, parent);
544 if (FAILED(hr))
546 WARN("Failed to initialize resource, returning %#x\n", hr);
547 HeapFree(GetProcessHeap(), 0, object);
548 *ppVertexBuffer = NULL;
549 return hr;
551 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
553 TRACE("(%p) : Created resource %p\n", This, object);
555 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
556 *ppVertexBuffer = (IWineD3DBuffer *)object;
558 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
559 * drawStridedFast (half-life 2).
561 * Basically converting the vertices in the buffer is quite expensive, and observations
562 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
563 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
565 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
566 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
567 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
568 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
569 * dx7 apps.
570 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
571 * more. In this call we can convert dx7 buffers too.
573 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
574 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
575 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
576 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
577 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
578 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
579 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
580 } else if(dxVersion <= 7 && conv) {
581 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
582 } else {
583 object->flags |= WINED3D_BUFFER_CREATEBO;
585 return WINED3D_OK;
588 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
589 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer, IUnknown *parent)
591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
592 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_UNKNOWN, &This->adapter->gl_info);
593 struct wined3d_buffer *object;
594 HRESULT hr;
596 TRACE("(%p) Creating index buffer\n", This);
598 /* Allocate the storage for the device */
599 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
600 if (!object)
602 ERR("Out of memory\n");
603 *ppIndexBuffer = NULL;
604 return WINED3DERR_OUTOFVIDEOMEMORY;
607 object->vtbl = &wined3d_buffer_vtbl;
608 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, Length, Usage, format_desc, Pool, parent);
609 if (FAILED(hr))
611 WARN("Failed to initialize resource, returning %#x\n", hr);
612 HeapFree(GetProcessHeap(), 0, object);
613 *ppIndexBuffer = NULL;
614 return hr;
616 object->buffer_type_hint = GL_ELEMENT_ARRAY_BUFFER_ARB;
618 TRACE("(%p) : Created resource %p\n", This, object);
620 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
621 object->flags |= WINED3D_BUFFER_CREATEBO;
624 TRACE("(%p) : Len=%d, Use=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage,
625 Pool, object, object->resource.allocatedMemory);
626 *ppIndexBuffer = (IWineD3DBuffer *) object;
628 return WINED3D_OK;
631 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
634 IWineD3DStateBlockImpl *object;
635 unsigned int i, j;
636 HRESULT temp_result;
638 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
639 if(!object)
641 ERR("Out of memory\n");
642 *ppStateBlock = NULL;
643 return WINED3DERR_OUTOFVIDEOMEMORY;
646 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
647 object->wineD3DDevice = This;
648 object->parent = parent;
649 object->ref = 1;
650 object->blockType = Type;
652 *ppStateBlock = (IWineD3DStateBlock *)object;
654 for(i = 0; i < LIGHTMAP_SIZE; i++) {
655 list_init(&object->lightMap[i]);
658 temp_result = allocate_shader_constants(object);
659 if (FAILED(temp_result))
661 HeapFree(GetProcessHeap(), 0, object);
662 return temp_result;
665 /* Special case - Used during initialization to produce a placeholder stateblock
666 so other functions called can update a state block */
667 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
669 /* Don't bother increasing the reference count otherwise a device will never
670 be freed due to circular dependencies */
671 return WINED3D_OK;
674 /* Otherwise, might as well set the whole state block to the appropriate values */
675 if (This->stateBlock != NULL)
676 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
677 else
678 memset(object->streamFreq, 1, sizeof(object->streamFreq));
680 /* Reset the ref and type after kludging it */
681 object->wineD3DDevice = This;
682 object->ref = 1;
683 object->blockType = Type;
685 TRACE("Updating changed flags appropriate for type %d\n", Type);
687 if (Type == WINED3DSBT_ALL) {
689 TRACE("ALL => Pretend everything has changed\n");
690 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
692 /* Lights are not part of the changed / set structure */
693 for(j = 0; j < LIGHTMAP_SIZE; j++) {
694 struct list *e;
695 LIST_FOR_EACH(e, &object->lightMap[j]) {
696 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
697 light->changed = TRUE;
698 light->enabledChanged = TRUE;
701 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
702 object->contained_render_states[j - 1] = j;
704 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
705 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
706 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
707 object->contained_transform_states[j - 1] = j;
709 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
710 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
711 object->contained_vs_consts_f[j] = j;
713 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
714 for(j = 0; j < MAX_CONST_I; j++) {
715 object->contained_vs_consts_i[j] = j;
717 object->num_contained_vs_consts_i = MAX_CONST_I;
718 for(j = 0; j < MAX_CONST_B; j++) {
719 object->contained_vs_consts_b[j] = j;
721 object->num_contained_vs_consts_b = MAX_CONST_B;
722 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
723 object->contained_ps_consts_f[j] = j;
725 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
726 for(j = 0; j < MAX_CONST_I; j++) {
727 object->contained_ps_consts_i[j] = j;
729 object->num_contained_ps_consts_i = MAX_CONST_I;
730 for(j = 0; j < MAX_CONST_B; j++) {
731 object->contained_ps_consts_b[j] = j;
733 object->num_contained_ps_consts_b = MAX_CONST_B;
734 for(i = 0; i < MAX_TEXTURES; i++) {
735 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
737 object->contained_tss_states[object->num_contained_tss_states].stage = i;
738 object->contained_tss_states[object->num_contained_tss_states].state = j;
739 object->num_contained_tss_states++;
742 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
743 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
744 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
745 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
746 object->num_contained_sampler_states++;
750 for(i = 0; i < MAX_STREAMS; i++) {
751 if(object->streamSource[i]) {
752 IWineD3DBuffer_AddRef(object->streamSource[i]);
755 if(object->pIndexData) {
756 IWineD3DBuffer_AddRef(object->pIndexData);
758 if(object->vertexShader) {
759 IWineD3DVertexShader_AddRef(object->vertexShader);
761 if(object->pixelShader) {
762 IWineD3DPixelShader_AddRef(object->pixelShader);
765 } else if (Type == WINED3DSBT_PIXELSTATE) {
767 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
768 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
770 object->changed.pixelShader = TRUE;
772 /* Pixel Shader Constants */
773 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
774 object->contained_ps_consts_f[i] = i;
775 object->changed.pixelShaderConstantsF[i] = TRUE;
777 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
778 for (i = 0; i < MAX_CONST_B; ++i) {
779 object->contained_ps_consts_b[i] = i;
780 object->changed.pixelShaderConstantsB |= (1 << i);
782 object->num_contained_ps_consts_b = MAX_CONST_B;
783 for (i = 0; i < MAX_CONST_I; ++i) {
784 object->contained_ps_consts_i[i] = i;
785 object->changed.pixelShaderConstantsI |= (1 << i);
787 object->num_contained_ps_consts_i = MAX_CONST_I;
789 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
790 DWORD rs = SavedPixelStates_R[i];
791 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
792 object->contained_render_states[i] = rs;
794 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
795 for (j = 0; j < MAX_TEXTURES; j++) {
796 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
797 DWORD state = SavedPixelStates_T[i];
798 object->changed.textureState[j] |= 1 << state;
799 object->contained_tss_states[object->num_contained_tss_states].stage = j;
800 object->contained_tss_states[object->num_contained_tss_states].state = state;
801 object->num_contained_tss_states++;
804 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
805 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
806 DWORD state = SavedPixelStates_S[i];
807 object->changed.samplerState[j] |= 1 << state;
808 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
809 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
810 object->num_contained_sampler_states++;
813 if(object->pixelShader) {
814 IWineD3DPixelShader_AddRef(object->pixelShader);
817 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
818 * on them. This makes releasing the buffer easier
820 for(i = 0; i < MAX_STREAMS; i++) {
821 object->streamSource[i] = NULL;
823 object->pIndexData = NULL;
824 object->vertexShader = NULL;
826 } else if (Type == WINED3DSBT_VERTEXSTATE) {
828 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
829 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
831 object->changed.vertexShader = TRUE;
833 /* Vertex Shader Constants */
834 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
835 object->changed.vertexShaderConstantsF[i] = TRUE;
836 object->contained_vs_consts_f[i] = i;
838 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
839 for (i = 0; i < MAX_CONST_B; ++i) {
840 object->contained_vs_consts_b[i] = i;
841 object->changed.vertexShaderConstantsB |= (1 << i);
843 object->num_contained_vs_consts_b = MAX_CONST_B;
844 for (i = 0; i < MAX_CONST_I; ++i) {
845 object->contained_vs_consts_i[i] = i;
846 object->changed.vertexShaderConstantsI |= (1 << i);
848 object->num_contained_vs_consts_i = MAX_CONST_I;
849 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
850 DWORD rs = SavedVertexStates_R[i];
851 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
852 object->contained_render_states[i] = rs;
854 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
855 for (j = 0; j < MAX_TEXTURES; j++) {
856 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
857 DWORD state = SavedVertexStates_T[i];
858 object->changed.textureState[j] |= 1 << state;
859 object->contained_tss_states[object->num_contained_tss_states].stage = j;
860 object->contained_tss_states[object->num_contained_tss_states].state = state;
861 object->num_contained_tss_states++;
864 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
865 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
866 DWORD state = SavedVertexStates_S[i];
867 object->changed.samplerState[j] |= 1 << state;
868 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
869 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
870 object->num_contained_sampler_states++;
874 for(j = 0; j < LIGHTMAP_SIZE; j++) {
875 struct list *e;
876 LIST_FOR_EACH(e, &object->lightMap[j]) {
877 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
878 light->changed = TRUE;
879 light->enabledChanged = TRUE;
883 for(i = 0; i < MAX_STREAMS; i++) {
884 if(object->streamSource[i]) {
885 IWineD3DBuffer_AddRef(object->streamSource[i]);
888 if(object->vertexShader) {
889 IWineD3DVertexShader_AddRef(object->vertexShader);
891 object->pIndexData = NULL;
892 object->pixelShader = NULL;
893 } else {
894 FIXME("Unrecognized state block type %d\n", Type);
897 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
898 return WINED3D_OK;
901 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
902 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
903 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
904 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
907 IWineD3DSurfaceImpl *object;
908 HRESULT hr;
910 TRACE("(%p) Create surface\n",This);
912 if (Impl == SURFACE_OPENGL && !This->adapter)
914 ERR("OpenGL surfaces are not available without OpenGL.\n");
915 return WINED3DERR_NOTAVAILABLE;
918 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
919 if (!object)
921 ERR("Failed to allocate surface memory.\n");
922 *ppSurface = NULL;
923 return WINED3DERR_OUTOFVIDEOMEMORY;
926 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
927 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
928 if (FAILED(hr))
930 WARN("Failed to initialize surface, returning %#x.\n", hr);
931 HeapFree(GetProcessHeap(), 0, object);
932 *ppSurface = NULL;
933 return hr;
936 TRACE("(%p) : Created surface %p\n", This, object);
938 *ppSurface = (IWineD3DSurface *)object;
940 return hr;
943 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
944 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
946 struct wined3d_rendertarget_view *object;
948 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
949 if (!object)
951 ERR("Failed to allocate memory\n");
952 return E_OUTOFMEMORY;
955 object->vtbl = &wined3d_rendertarget_view_vtbl;
956 object->refcount = 1;
957 IWineD3DResource_AddRef(resource);
958 object->resource = resource;
959 object->parent = parent;
961 *rendertarget_view = (IWineD3DRendertargetView *)object;
963 return WINED3D_OK;
966 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
967 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
968 WINED3DPOOL Pool, IWineD3DTexture **ppTexture, IUnknown *parent)
970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
971 IWineD3DTextureImpl *object;
972 HRESULT hr;
974 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
975 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
976 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
978 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
979 if (!object)
981 ERR("Out of memory\n");
982 *ppTexture = NULL;
983 return WINED3DERR_OUTOFVIDEOMEMORY;
986 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent);
987 if (FAILED(hr))
989 WARN("Failed to initialize texture, returning %#x\n", hr);
990 HeapFree(GetProcessHeap(), 0, object);
991 *ppTexture = NULL;
992 return hr;
995 *ppTexture = (IWineD3DTexture *)object;
997 TRACE("(%p) : Created texture %p\n", This, object);
999 return WINED3D_OK;
1002 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1003 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1004 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1007 IWineD3DVolumeTextureImpl *object;
1008 HRESULT hr;
1010 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1011 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1013 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1014 if (!object)
1016 ERR("Out of memory\n");
1017 *ppVolumeTexture = NULL;
1018 return WINED3DERR_OUTOFVIDEOMEMORY;
1021 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1022 if (FAILED(hr))
1024 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1025 HeapFree(GetProcessHeap(), 0, object);
1026 *ppVolumeTexture = NULL;
1027 return hr;
1030 TRACE("(%p) : Created volume texture %p.\n", This, object);
1031 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1033 return WINED3D_OK;
1036 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1037 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
1038 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1041 IWineD3DVolumeImpl *object;
1042 HRESULT hr;
1044 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1045 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1047 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1048 if (!object)
1050 ERR("Out of memory\n");
1051 *ppVolume = NULL;
1052 return WINED3DERR_OUTOFVIDEOMEMORY;
1055 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1056 if (FAILED(hr))
1058 WARN("Failed to initialize volume, returning %#x.\n", hr);
1059 HeapFree(GetProcessHeap(), 0, object);
1060 return hr;
1063 TRACE("(%p) : Created volume %p.\n", This, object);
1064 *ppVolume = (IWineD3DVolume *)object;
1066 return WINED3D_OK;
1069 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1070 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1071 WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture, IUnknown *parent)
1073 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1074 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1075 HRESULT hr;
1077 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1078 if (!object)
1080 ERR("Out of memory\n");
1081 *ppCubeTexture = NULL;
1082 return WINED3DERR_OUTOFVIDEOMEMORY;
1085 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent);
1086 if (FAILED(hr))
1088 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1089 HeapFree(GetProcessHeap(), 0, object);
1090 *ppCubeTexture = NULL;
1091 return hr;
1094 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1095 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1097 return WINED3D_OK;
1100 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1102 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1103 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1104 const IWineD3DQueryVtbl *vtable;
1106 /* Just a check to see if we support this type of query */
1107 switch(Type) {
1108 case WINED3DQUERYTYPE_OCCLUSION:
1109 TRACE("(%p) occlusion query\n", This);
1110 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1111 hr = WINED3D_OK;
1112 else
1113 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1115 vtable = &IWineD3DOcclusionQuery_Vtbl;
1116 break;
1118 case WINED3DQUERYTYPE_EVENT:
1119 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1120 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1121 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1123 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1125 vtable = &IWineD3DEventQuery_Vtbl;
1126 hr = WINED3D_OK;
1127 break;
1129 case WINED3DQUERYTYPE_VCACHE:
1130 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1131 case WINED3DQUERYTYPE_VERTEXSTATS:
1132 case WINED3DQUERYTYPE_TIMESTAMP:
1133 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1134 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1135 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1136 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1137 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1138 case WINED3DQUERYTYPE_PIXELTIMINGS:
1139 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1140 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1141 default:
1142 /* Use the base Query vtable until we have a special one for each query */
1143 vtable = &IWineD3DQuery_Vtbl;
1144 FIXME("(%p) Unhandled query type %d\n", This, Type);
1146 if(NULL == ppQuery || hr != WINED3D_OK) {
1147 return hr;
1150 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1151 if(!object)
1153 ERR("Out of memory\n");
1154 *ppQuery = NULL;
1155 return WINED3DERR_OUTOFVIDEOMEMORY;
1158 object->lpVtbl = vtable;
1159 object->type = Type;
1160 object->state = QUERY_CREATED;
1161 object->wineD3DDevice = This;
1162 object->parent = parent;
1163 object->ref = 1;
1165 *ppQuery = (IWineD3DQuery *)object;
1167 /* allocated the 'extended' data based on the type of query requested */
1168 switch(Type){
1169 case WINED3DQUERYTYPE_OCCLUSION:
1170 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
1171 ((struct wined3d_occlusion_query *)object->extendedData)->context = NULL;
1172 break;
1174 case WINED3DQUERYTYPE_EVENT:
1175 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query));
1176 ((struct wined3d_event_query *)object->extendedData)->context = NULL;
1177 break;
1179 case WINED3DQUERYTYPE_VCACHE:
1180 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1181 case WINED3DQUERYTYPE_VERTEXSTATS:
1182 case WINED3DQUERYTYPE_TIMESTAMP:
1183 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1184 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1185 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1186 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1187 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1188 case WINED3DQUERYTYPE_PIXELTIMINGS:
1189 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1190 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1191 default:
1192 object->extendedData = 0;
1193 FIXME("(%p) Unhandled query type %d\n",This , Type);
1195 TRACE("(%p) : Created Query %p\n", This, object);
1196 return WINED3D_OK;
1199 /*****************************************************************************
1200 * IWineD3DDeviceImpl_SetupFullscreenWindow
1202 * Helper function that modifies a HWND's Style and ExStyle for proper
1203 * fullscreen use.
1205 * Params:
1206 * iface: Pointer to the IWineD3DDevice interface
1207 * window: Window to setup
1209 *****************************************************************************/
1210 static LONG fullscreen_style(LONG orig_style) {
1211 LONG style = orig_style;
1212 style &= ~WS_CAPTION;
1213 style &= ~WS_THICKFRAME;
1215 /* Make sure the window is managed, otherwise we won't get keyboard input */
1216 style |= WS_POPUP | WS_SYSMENU;
1218 return style;
1221 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1222 LONG exStyle = orig_exStyle;
1224 /* Filter out window decorations */
1225 exStyle &= ~WS_EX_WINDOWEDGE;
1226 exStyle &= ~WS_EX_CLIENTEDGE;
1228 return exStyle;
1231 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1234 LONG style, exStyle;
1235 /* Don't do anything if an original style is stored.
1236 * That shouldn't happen
1238 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1239 if (This->style || This->exStyle) {
1240 ERR("(%p): Want to change the window parameters of HWND %p, but "
1241 "another style is stored for restoration afterwards\n", This, window);
1244 /* Get the parameters and save them */
1245 style = GetWindowLongW(window, GWL_STYLE);
1246 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1247 This->style = style;
1248 This->exStyle = exStyle;
1250 style = fullscreen_style(style);
1251 exStyle = fullscreen_exStyle(exStyle);
1253 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1254 This->style, This->exStyle, style, exStyle);
1256 SetWindowLongW(window, GWL_STYLE, style);
1257 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1259 /* Inform the window about the update. */
1260 SetWindowPos(window, HWND_TOP, 0, 0,
1261 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1264 /*****************************************************************************
1265 * IWineD3DDeviceImpl_RestoreWindow
1267 * Helper function that restores a windows' properties when taking it out
1268 * of fullscreen mode
1270 * Params:
1271 * iface: Pointer to the IWineD3DDevice interface
1272 * window: Window to setup
1274 *****************************************************************************/
1275 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1277 LONG style, exStyle;
1279 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1280 * switch, do nothing
1282 if (!This->style && !This->exStyle) return;
1284 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1285 This, window, This->style, This->exStyle);
1287 style = GetWindowLongW(window, GWL_STYLE);
1288 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1290 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1291 * Some applications change it before calling Reset() when switching between windowed and
1292 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1294 if(style == fullscreen_style(This->style) &&
1295 exStyle == fullscreen_style(This->exStyle)) {
1296 SetWindowLongW(window, GWL_STYLE, This->style);
1297 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1300 /* Delete the old values */
1301 This->style = 0;
1302 This->exStyle = 0;
1304 /* Inform the window about the update */
1305 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1306 0, 0, 0, 0, /* Pos, Size, ignored */
1307 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1310 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1311 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1312 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1313 IUnknown *parent, WINED3DSURFTYPE surface_type)
1315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1317 HDC hDc;
1318 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1319 HRESULT hr;
1320 BOOL displaymode_set = FALSE;
1321 WINED3DDISPLAYMODE Mode;
1322 const struct GlPixelFormatDesc *format_desc;
1324 TRACE("(%p) : Created Additional Swap Chain\n", This);
1326 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1327 * does a device hold a reference to a swap chain giving them a lifetime of the device
1328 * or does the swap chain notify the device of its destruction.
1329 *******************************/
1331 /* Check the params */
1332 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1333 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1334 return WINED3DERR_INVALIDCALL;
1335 } else if (pPresentationParameters->BackBufferCount > 1) {
1336 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");
1339 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1340 if(!object)
1342 ERR("Out of memory\n");
1343 *ppSwapChain = NULL;
1344 return WINED3DERR_OUTOFVIDEOMEMORY;
1347 switch(surface_type) {
1348 case SURFACE_GDI:
1349 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1350 break;
1351 case SURFACE_OPENGL:
1352 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1353 break;
1354 case SURFACE_UNKNOWN:
1355 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1356 HeapFree(GetProcessHeap(), 0, object);
1357 return WINED3DERR_INVALIDCALL;
1359 object->wineD3DDevice = This;
1360 object->parent = parent;
1361 object->ref = 1;
1363 *ppSwapChain = (IWineD3DSwapChain *)object;
1365 /*********************
1366 * Lookup the window Handle and the relating X window handle
1367 ********************/
1369 /* Setup hwnd we are using, plus which display this equates to */
1370 object->win_handle = pPresentationParameters->hDeviceWindow;
1371 if (!object->win_handle) {
1372 object->win_handle = This->createParms.hFocusWindow;
1374 if(!pPresentationParameters->Windowed && object->win_handle) {
1375 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1376 pPresentationParameters->BackBufferWidth,
1377 pPresentationParameters->BackBufferHeight);
1380 hDc = GetDC(object->win_handle);
1381 TRACE("Using hDc %p\n", hDc);
1383 if (NULL == hDc) {
1384 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1385 return WINED3DERR_NOTAVAILABLE;
1388 /* Get info on the current display setup */
1389 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1390 object->orig_width = Mode.Width;
1391 object->orig_height = Mode.Height;
1392 object->orig_fmt = Mode.Format;
1393 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1395 if (pPresentationParameters->Windowed &&
1396 ((pPresentationParameters->BackBufferWidth == 0) ||
1397 (pPresentationParameters->BackBufferHeight == 0) ||
1398 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1400 RECT Rect;
1401 GetClientRect(object->win_handle, &Rect);
1403 if (pPresentationParameters->BackBufferWidth == 0) {
1404 pPresentationParameters->BackBufferWidth = Rect.right;
1405 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1407 if (pPresentationParameters->BackBufferHeight == 0) {
1408 pPresentationParameters->BackBufferHeight = Rect.bottom;
1409 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1411 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1412 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1413 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1417 /* Put the correct figures in the presentation parameters */
1418 TRACE("Copying across presentation parameters\n");
1419 object->presentParms = *pPresentationParameters;
1421 TRACE("calling rendertarget CB\n");
1422 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1423 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1424 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1425 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1426 if (SUCCEEDED(hr)) {
1427 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1428 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1429 if(surface_type == SURFACE_OPENGL) {
1430 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1432 } else {
1433 ERR("Failed to create the front buffer\n");
1434 goto error;
1437 /*********************
1438 * Windowed / Fullscreen
1439 *******************/
1442 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1443 * so we should really check to see if there is a fullscreen swapchain already
1444 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1445 **************************************/
1447 if (!pPresentationParameters->Windowed) {
1448 WINED3DDISPLAYMODE mode;
1451 /* Change the display settings */
1452 mode.Width = pPresentationParameters->BackBufferWidth;
1453 mode.Height = pPresentationParameters->BackBufferHeight;
1454 mode.Format = pPresentationParameters->BackBufferFormat;
1455 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1457 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1458 displaymode_set = TRUE;
1462 * Create an opengl context for the display visual
1463 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1464 * use different properties after that point in time. FIXME: How to handle when requested format
1465 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1466 * it chooses is identical to the one already being used!
1467 **********************************/
1468 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1470 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1471 if(!object->context) {
1472 ERR("Failed to create the context array\n");
1473 hr = E_OUTOFMEMORY;
1474 goto error;
1476 object->num_contexts = 1;
1478 if(surface_type == SURFACE_OPENGL) {
1479 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1480 if (!object->context[0]) {
1481 ERR("Failed to create a new context\n");
1482 hr = WINED3DERR_NOTAVAILABLE;
1483 goto error;
1484 } else {
1485 TRACE("Context created (HWND=%p, glContext=%p)\n",
1486 object->win_handle, object->context[0]->glCtx);
1490 /*********************
1491 * Create the back, front and stencil buffers
1492 *******************/
1493 if(object->presentParms.BackBufferCount > 0) {
1494 UINT i;
1496 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1497 if(!object->backBuffer) {
1498 ERR("Out of memory\n");
1499 hr = E_OUTOFMEMORY;
1500 goto error;
1503 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1504 TRACE("calling rendertarget CB\n");
1505 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1506 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1507 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1508 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1509 if(SUCCEEDED(hr)) {
1510 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1511 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1512 } else {
1513 ERR("Cannot create new back buffer\n");
1514 goto error;
1516 if(surface_type == SURFACE_OPENGL) {
1517 ENTER_GL();
1518 glDrawBuffer(GL_BACK);
1519 checkGLcall("glDrawBuffer(GL_BACK)");
1520 LEAVE_GL();
1523 } else {
1524 object->backBuffer = NULL;
1526 /* Single buffering - draw to front buffer */
1527 if(surface_type == SURFACE_OPENGL) {
1528 ENTER_GL();
1529 glDrawBuffer(GL_FRONT);
1530 checkGLcall("glDrawBuffer(GL_FRONT)");
1531 LEAVE_GL();
1535 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1536 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1537 TRACE("Creating depth stencil buffer\n");
1538 if (This->auto_depth_stencil_buffer == NULL ) {
1539 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1540 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1541 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1542 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1543 &This->auto_depth_stencil_buffer);
1544 if (SUCCEEDED(hr)) {
1545 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1546 } else {
1547 ERR("Failed to create the auto depth stencil\n");
1548 goto error;
1553 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1555 TRACE("Created swapchain %p\n", object);
1556 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1557 return WINED3D_OK;
1559 error:
1560 if (displaymode_set) {
1561 DEVMODEW devmode;
1562 RECT clip_rc;
1564 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1565 ClipCursor(NULL);
1567 /* Change the display settings */
1568 memset(&devmode, 0, sizeof(devmode));
1569 devmode.dmSize = sizeof(devmode);
1570 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1571 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1572 devmode.dmPelsWidth = object->orig_width;
1573 devmode.dmPelsHeight = object->orig_height;
1574 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1577 if (object->backBuffer) {
1578 UINT i;
1579 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1580 if (object->backBuffer[i]) IWineD3DSurface_Release(object->backBuffer[i]);
1582 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1583 object->backBuffer = NULL;
1585 if(object->context && object->context[0])
1586 DestroyContext(This, object->context[0]);
1587 if (object->frontBuffer) IWineD3DSurface_Release(object->frontBuffer);
1588 HeapFree(GetProcessHeap(), 0, object);
1589 return hr;
1592 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1593 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1595 TRACE("(%p)\n", This);
1597 return This->NumberOfSwapChains;
1600 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1602 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1604 if(iSwapChain < This->NumberOfSwapChains) {
1605 *pSwapChain = This->swapchains[iSwapChain];
1606 IWineD3DSwapChain_AddRef(*pSwapChain);
1607 TRACE("(%p) returning %p\n", This, *pSwapChain);
1608 return WINED3D_OK;
1609 } else {
1610 TRACE("Swapchain out of range\n");
1611 *pSwapChain = NULL;
1612 return WINED3DERR_INVALIDCALL;
1616 /*****
1617 * Vertex Declaration
1618 *****/
1619 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1620 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1622 IWineD3DVertexDeclarationImpl *object = NULL;
1623 HRESULT hr = WINED3D_OK;
1625 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1626 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1628 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1629 if(!object)
1631 ERR("Out of memory\n");
1632 *ppVertexDeclaration = NULL;
1633 return WINED3DERR_OUTOFVIDEOMEMORY;
1636 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
1637 object->wineD3DDevice = This;
1638 object->parent = parent;
1639 object->ref = 1;
1641 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1643 hr = vertexdeclaration_init(object, elements, element_count);
1645 if(FAILED(hr)) {
1646 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1647 *ppVertexDeclaration = NULL;
1650 return hr;
1653 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1654 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1656 unsigned int idx, idx2;
1657 unsigned int offset;
1658 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1659 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1660 BOOL has_blend_idx = has_blend &&
1661 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1662 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1663 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1664 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1665 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1666 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1667 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1669 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1670 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1671 WINED3DVERTEXELEMENT *elements = NULL;
1673 unsigned int size;
1674 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1675 if (has_blend_idx) num_blends--;
1677 /* Compute declaration size */
1678 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1679 has_psize + has_diffuse + has_specular + num_textures;
1681 /* convert the declaration */
1682 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1683 if (!elements) return ~0U;
1685 idx = 0;
1686 if (has_pos) {
1687 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1688 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1689 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1691 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1692 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1693 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1695 else {
1696 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1697 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1699 elements[idx].usage_idx = 0;
1700 idx++;
1702 if (has_blend && (num_blends > 0)) {
1703 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1704 elements[idx].format = WINED3DFMT_A8R8G8B8;
1705 else {
1706 switch(num_blends) {
1707 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1708 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1709 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1710 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1711 default:
1712 ERR("Unexpected amount of blend values: %u\n", num_blends);
1715 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1716 elements[idx].usage_idx = 0;
1717 idx++;
1719 if (has_blend_idx) {
1720 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1721 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1722 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1723 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1724 elements[idx].format = WINED3DFMT_A8R8G8B8;
1725 else
1726 elements[idx].format = WINED3DFMT_R32_FLOAT;
1727 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1728 elements[idx].usage_idx = 0;
1729 idx++;
1731 if (has_normal) {
1732 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1733 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1734 elements[idx].usage_idx = 0;
1735 idx++;
1737 if (has_psize) {
1738 elements[idx].format = WINED3DFMT_R32_FLOAT;
1739 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1740 elements[idx].usage_idx = 0;
1741 idx++;
1743 if (has_diffuse) {
1744 elements[idx].format = WINED3DFMT_A8R8G8B8;
1745 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1746 elements[idx].usage_idx = 0;
1747 idx++;
1749 if (has_specular) {
1750 elements[idx].format = WINED3DFMT_A8R8G8B8;
1751 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1752 elements[idx].usage_idx = 1;
1753 idx++;
1755 for (idx2 = 0; idx2 < num_textures; idx2++) {
1756 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1757 switch (numcoords) {
1758 case WINED3DFVF_TEXTUREFORMAT1:
1759 elements[idx].format = WINED3DFMT_R32_FLOAT;
1760 break;
1761 case WINED3DFVF_TEXTUREFORMAT2:
1762 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1763 break;
1764 case WINED3DFVF_TEXTUREFORMAT3:
1765 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1766 break;
1767 case WINED3DFVF_TEXTUREFORMAT4:
1768 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1769 break;
1771 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1772 elements[idx].usage_idx = idx2;
1773 idx++;
1776 /* Now compute offsets, and initialize the rest of the fields */
1777 for (idx = 0, offset = 0; idx < size; ++idx)
1779 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1780 elements[idx].input_slot = 0;
1781 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1782 elements[idx].offset = offset;
1783 offset += format_desc->component_count * format_desc->component_size;
1786 *ppVertexElements = elements;
1787 return size;
1790 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1791 WINED3DVERTEXELEMENT* elements = NULL;
1792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1793 unsigned int size;
1794 DWORD hr;
1796 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1797 if (size == ~0U) return WINED3DERR_OUTOFVIDEOMEMORY;
1799 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1800 HeapFree(GetProcessHeap(), 0, elements);
1801 if (hr != S_OK) return hr;
1803 return WINED3D_OK;
1806 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1807 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1808 IWineD3DVertexShader **ppVertexShader, IUnknown *parent)
1810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1811 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1812 HRESULT hr = WINED3D_OK;
1814 if (!pFunction) return WINED3DERR_INVALIDCALL;
1816 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1817 if (!object)
1819 ERR("Out of memory\n");
1820 *ppVertexShader = NULL;
1821 return WINED3DERR_OUTOFVIDEOMEMORY;
1824 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
1825 object->parent = parent;
1826 shader_init(&object->baseShader, iface);
1827 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1828 *ppVertexShader = (IWineD3DVertexShader *)object;
1830 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
1832 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction, output_signature);
1833 if (FAILED(hr))
1835 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
1836 IWineD3DVertexShader_Release(*ppVertexShader);
1837 *ppVertexShader = NULL;
1838 return hr;
1841 return hr;
1844 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1845 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1846 IWineD3DPixelShader **ppPixelShader, IUnknown *parent)
1848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1849 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1850 HRESULT hr = WINED3D_OK;
1852 if (!pFunction) return WINED3DERR_INVALIDCALL;
1854 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1855 if (!object)
1857 ERR("Out of memory\n");
1858 *ppPixelShader = NULL;
1859 return WINED3DERR_OUTOFVIDEOMEMORY;
1862 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
1863 object->parent = parent;
1864 shader_init(&object->baseShader, iface);
1865 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1866 *ppPixelShader = (IWineD3DPixelShader *)object;
1868 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
1870 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction, output_signature);
1871 if (FAILED(hr))
1873 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
1874 IWineD3DPixelShader_Release(*ppPixelShader);
1875 *ppPixelShader = NULL;
1876 return hr;
1879 return hr;
1882 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1883 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1886 IWineD3DPaletteImpl *object;
1887 HRESULT hr;
1888 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1890 /* Create the new object */
1891 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1892 if(!object) {
1893 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1894 return E_OUTOFMEMORY;
1897 object->lpVtbl = &IWineD3DPalette_Vtbl;
1898 object->ref = 1;
1899 object->Flags = Flags;
1900 object->parent = Parent;
1901 object->wineD3DDevice = This;
1902 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1903 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1905 if(!object->hpal) {
1906 HeapFree( GetProcessHeap(), 0, object);
1907 return E_OUTOFMEMORY;
1910 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1911 if(FAILED(hr)) {
1912 IWineD3DPalette_Release((IWineD3DPalette *) object);
1913 return hr;
1916 *Palette = (IWineD3DPalette *) object;
1918 return WINED3D_OK;
1921 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1922 HBITMAP hbm;
1923 BITMAP bm;
1924 HRESULT hr;
1925 HDC dcb = NULL, dcs = NULL;
1926 WINEDDCOLORKEY colorkey;
1928 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1929 if(hbm)
1931 GetObjectA(hbm, sizeof(BITMAP), &bm);
1932 dcb = CreateCompatibleDC(NULL);
1933 if(!dcb) goto out;
1934 SelectObject(dcb, hbm);
1936 else
1938 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1939 * couldn't be loaded
1941 memset(&bm, 0, sizeof(bm));
1942 bm.bmWidth = 32;
1943 bm.bmHeight = 32;
1946 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5, TRUE,
1947 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1948 NULL, &wined3d_null_parent_ops);
1949 if(FAILED(hr)) {
1950 ERR("Wine logo requested, but failed to create surface\n");
1951 goto out;
1954 if(dcb) {
1955 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1956 if(FAILED(hr)) goto out;
1957 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1958 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1960 colorkey.dwColorSpaceLowValue = 0;
1961 colorkey.dwColorSpaceHighValue = 0;
1962 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1963 } else {
1964 /* Fill the surface with a white color to show that wined3d is there */
1965 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1968 out:
1969 if(dcb) {
1970 DeleteDC(dcb);
1972 if(hbm) {
1973 DeleteObject(hbm);
1975 return;
1978 /* Context activation is done by the caller. */
1979 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1980 unsigned int i;
1981 /* Under DirectX you can have texture stage operations even if no texture is
1982 bound, whereas opengl will only do texture operations when a valid texture is
1983 bound. We emulate this by creating dummy textures and binding them to each
1984 texture stage, but disable all stages by default. Hence if a stage is enabled
1985 then the default texture will kick in until replaced by a SetTexture call */
1986 ENTER_GL();
1988 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1989 /* The dummy texture does not have client storage backing */
1990 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1991 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1993 for (i = 0; i < GL_LIMITS(textures); i++) {
1994 GLubyte white = 255;
1996 /* Make appropriate texture active */
1997 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1998 checkGLcall("glActiveTextureARB");
2000 /* Generate an opengl texture name */
2001 glGenTextures(1, &This->dummyTextureName[i]);
2002 checkGLcall("glGenTextures");
2003 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2005 /* Generate a dummy 2d texture (not using 1d because they cause many
2006 * DRI drivers fall back to sw) */
2007 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2008 checkGLcall("glBindTexture");
2010 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2011 checkGLcall("glTexImage2D");
2013 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2014 /* Reenable because if supported it is enabled by default */
2015 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2016 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2019 LEAVE_GL();
2022 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2023 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2026 IWineD3DSwapChainImpl *swapchain = NULL;
2027 HRESULT hr;
2028 DWORD state;
2029 unsigned int i;
2031 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2033 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2034 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2036 /* TODO: Test if OpenGL is compiled in and loaded */
2038 TRACE("(%p) : Creating stateblock\n", This);
2039 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2040 hr = IWineD3DDevice_CreateStateBlock(iface,
2041 WINED3DSBT_INIT,
2042 (IWineD3DStateBlock **)&This->stateBlock,
2043 NULL);
2044 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2045 WARN("Failed to create stateblock\n");
2046 goto err_out;
2048 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2049 This->updateStateBlock = This->stateBlock;
2050 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2052 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2053 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2055 This->NumberOfPalettes = 1;
2056 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2057 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2058 ERR("Out of memory!\n");
2059 goto err_out;
2061 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2062 if(!This->palettes[0]) {
2063 ERR("Out of memory!\n");
2064 goto err_out;
2066 for (i = 0; i < 256; ++i) {
2067 This->palettes[0][i].peRed = 0xFF;
2068 This->palettes[0][i].peGreen = 0xFF;
2069 This->palettes[0][i].peBlue = 0xFF;
2070 This->palettes[0][i].peFlags = 0xFF;
2072 This->currentPalette = 0;
2074 /* Initialize the texture unit mapping to a 1:1 mapping */
2075 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2076 if (state < GL_LIMITS(fragment_samplers)) {
2077 This->texUnitMap[state] = state;
2078 This->rev_tex_unit_map[state] = state;
2079 } else {
2080 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
2081 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
2085 /* Setup the implicit swapchain. This also initializes a context. */
2086 TRACE("Creating implicit swapchain\n");
2087 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2088 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2089 if (FAILED(hr))
2091 WARN("Failed to create implicit swapchain\n");
2092 goto err_out;
2095 This->NumberOfSwapChains = 1;
2096 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2097 if(!This->swapchains) {
2098 ERR("Out of memory!\n");
2099 goto err_out;
2101 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2103 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2104 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2105 This->render_targets[0] = swapchain->backBuffer[0];
2107 else {
2108 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2109 This->render_targets[0] = swapchain->frontBuffer;
2111 IWineD3DSurface_AddRef(This->render_targets[0]);
2113 /* Depth Stencil support */
2114 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2115 if (NULL != This->stencilBufferTarget) {
2116 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2119 hr = This->shader_backend->shader_alloc_private(iface);
2120 if(FAILED(hr)) {
2121 TRACE("Shader private data couldn't be allocated\n");
2122 goto err_out;
2124 hr = This->frag_pipe->alloc_private(iface);
2125 if(FAILED(hr)) {
2126 TRACE("Fragment pipeline private data couldn't be allocated\n");
2127 goto err_out;
2129 hr = This->blitter->alloc_private(iface);
2130 if(FAILED(hr)) {
2131 TRACE("Blitter private data couldn't be allocated\n");
2132 goto err_out;
2135 /* Set up some starting GL setup */
2137 /* Setup all the devices defaults */
2138 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2139 create_dummy_textures(This);
2141 ENTER_GL();
2143 /* Initialize the current view state */
2144 This->view_ident = 1;
2145 This->contexts[0]->last_was_rhw = 0;
2146 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2147 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2149 switch(wined3d_settings.offscreen_rendering_mode) {
2150 case ORM_FBO:
2151 case ORM_PBUFFER:
2152 This->offscreenBuffer = GL_BACK;
2153 break;
2155 case ORM_BACKBUFFER:
2157 if (context_get_current()->aux_buffers > 0)
2159 TRACE("Using auxilliary buffer for offscreen rendering\n");
2160 This->offscreenBuffer = GL_AUX0;
2161 } else {
2162 TRACE("Using back buffer for offscreen rendering\n");
2163 This->offscreenBuffer = GL_BACK;
2168 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2169 LEAVE_GL();
2171 /* Clear the screen */
2172 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2173 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2174 0x00, 1.0f, 0);
2176 This->d3d_initialized = TRUE;
2178 if(wined3d_settings.logo) {
2179 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2181 This->highest_dirty_ps_const = 0;
2182 This->highest_dirty_vs_const = 0;
2183 return WINED3D_OK;
2185 err_out:
2186 HeapFree(GetProcessHeap(), 0, This->render_targets);
2187 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2188 HeapFree(GetProcessHeap(), 0, This->swapchains);
2189 This->NumberOfSwapChains = 0;
2190 if(This->palettes) {
2191 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2192 HeapFree(GetProcessHeap(), 0, This->palettes);
2194 This->NumberOfPalettes = 0;
2195 if(swapchain) {
2196 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2198 if(This->stateBlock) {
2199 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2200 This->stateBlock = NULL;
2202 if (This->blit_priv) {
2203 This->blitter->free_private(iface);
2205 if (This->fragment_priv) {
2206 This->frag_pipe->free_private(iface);
2208 if (This->shader_priv) {
2209 This->shader_backend->shader_free_private(iface);
2211 return hr;
2214 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2215 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2218 IWineD3DSwapChainImpl *swapchain = NULL;
2219 HRESULT hr;
2221 /* Setup the implicit swapchain */
2222 TRACE("Creating implicit swapchain\n");
2223 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2224 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2225 if (FAILED(hr))
2227 WARN("Failed to create implicit swapchain\n");
2228 goto err_out;
2231 This->NumberOfSwapChains = 1;
2232 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2233 if(!This->swapchains) {
2234 ERR("Out of memory!\n");
2235 goto err_out;
2237 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2238 return WINED3D_OK;
2240 err_out:
2241 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2242 return hr;
2245 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2247 IWineD3DResource_UnLoad(resource);
2248 IWineD3DResource_Release(resource);
2249 return WINED3D_OK;
2252 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2253 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2256 int sampler;
2257 UINT i;
2258 TRACE("(%p)\n", This);
2260 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2262 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2263 * it was created. Thus make sure a context is active for the glDelete* calls
2265 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
2267 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2269 /* Unload resources */
2270 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2272 TRACE("Deleting high order patches\n");
2273 for(i = 0; i < PATCHMAP_SIZE; i++) {
2274 struct list *e1, *e2;
2275 struct WineD3DRectPatch *patch;
2276 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2277 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2278 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2282 /* Delete the palette conversion shader if it is around */
2283 if(This->paletteConversionShader) {
2284 ENTER_GL();
2285 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2286 LEAVE_GL();
2287 This->paletteConversionShader = 0;
2290 /* Delete the pbuffer context if there is any */
2291 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2293 /* Delete the mouse cursor texture */
2294 if(This->cursorTexture) {
2295 ENTER_GL();
2296 glDeleteTextures(1, &This->cursorTexture);
2297 LEAVE_GL();
2298 This->cursorTexture = 0;
2301 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2302 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2304 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2305 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2308 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2309 * private data, it might contain opengl pointers
2311 if(This->depth_blt_texture) {
2312 ENTER_GL();
2313 glDeleteTextures(1, &This->depth_blt_texture);
2314 LEAVE_GL();
2315 This->depth_blt_texture = 0;
2317 if (This->depth_blt_rb) {
2318 ENTER_GL();
2319 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2320 LEAVE_GL();
2321 This->depth_blt_rb = 0;
2322 This->depth_blt_rb_w = 0;
2323 This->depth_blt_rb_h = 0;
2326 /* Release the update stateblock */
2327 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2328 if(This->updateStateBlock != This->stateBlock)
2329 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2331 This->updateStateBlock = NULL;
2333 { /* because were not doing proper internal refcounts releasing the primary state block
2334 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2335 to set this->stateBlock = NULL; first */
2336 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2337 This->stateBlock = NULL;
2339 /* Release the stateblock */
2340 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2341 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2345 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2346 This->blitter->free_private(iface);
2347 This->frag_pipe->free_private(iface);
2348 This->shader_backend->shader_free_private(iface);
2350 /* Release the buffers (with sanity checks)*/
2351 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2352 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2353 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2354 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2356 This->stencilBufferTarget = NULL;
2358 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2359 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2360 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2362 TRACE("Setting rendertarget to NULL\n");
2363 This->render_targets[0] = NULL;
2365 if (This->auto_depth_stencil_buffer) {
2366 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
2368 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2370 This->auto_depth_stencil_buffer = NULL;
2373 for(i=0; i < This->NumberOfSwapChains; i++) {
2374 TRACE("Releasing the implicit swapchain %d\n", i);
2375 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2376 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2380 HeapFree(GetProcessHeap(), 0, This->swapchains);
2381 This->swapchains = NULL;
2382 This->NumberOfSwapChains = 0;
2384 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2385 HeapFree(GetProcessHeap(), 0, This->palettes);
2386 This->palettes = NULL;
2387 This->NumberOfPalettes = 0;
2389 HeapFree(GetProcessHeap(), 0, This->render_targets);
2390 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2391 This->render_targets = NULL;
2392 This->draw_buffers = NULL;
2394 This->d3d_initialized = FALSE;
2395 return WINED3D_OK;
2398 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2400 unsigned int i;
2402 for(i=0; i < This->NumberOfSwapChains; i++) {
2403 TRACE("Releasing the implicit swapchain %d\n", i);
2404 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2405 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2409 HeapFree(GetProcessHeap(), 0, This->swapchains);
2410 This->swapchains = NULL;
2411 This->NumberOfSwapChains = 0;
2412 return WINED3D_OK;
2415 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2416 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2417 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2419 * There is no way to deactivate thread safety once it is enabled.
2421 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2424 /*For now just store the flag(needed in case of ddraw) */
2425 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2427 return;
2430 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2431 const WINED3DDISPLAYMODE* pMode) {
2432 DEVMODEW devmode;
2433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2434 LONG ret;
2435 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2436 RECT clip_rc;
2438 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2440 /* Resize the screen even without a window:
2441 * The app could have unset it with SetCooperativeLevel, but not called
2442 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2443 * but we don't have any hwnd
2446 memset(&devmode, 0, sizeof(devmode));
2447 devmode.dmSize = sizeof(devmode);
2448 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2449 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2450 devmode.dmPelsWidth = pMode->Width;
2451 devmode.dmPelsHeight = pMode->Height;
2453 devmode.dmDisplayFrequency = pMode->RefreshRate;
2454 if (pMode->RefreshRate != 0) {
2455 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2458 /* Only change the mode if necessary */
2459 if( (This->ddraw_width == pMode->Width) &&
2460 (This->ddraw_height == pMode->Height) &&
2461 (This->ddraw_format == pMode->Format) &&
2462 (pMode->RefreshRate == 0) ) {
2463 return WINED3D_OK;
2466 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2467 if (ret != DISP_CHANGE_SUCCESSFUL) {
2468 if(devmode.dmDisplayFrequency != 0) {
2469 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2470 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2471 devmode.dmDisplayFrequency = 0;
2472 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2474 if(ret != DISP_CHANGE_SUCCESSFUL) {
2475 return WINED3DERR_NOTAVAILABLE;
2479 /* Store the new values */
2480 This->ddraw_width = pMode->Width;
2481 This->ddraw_height = pMode->Height;
2482 This->ddraw_format = pMode->Format;
2484 /* And finally clip mouse to our screen */
2485 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2486 ClipCursor(&clip_rc);
2488 return WINED3D_OK;
2491 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2492 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2493 *ppD3D= This->wineD3D;
2494 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2495 IWineD3D_AddRef(*ppD3D);
2496 return WINED3D_OK;
2499 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2500 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2502 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2503 (This->adapter->TextureRam/(1024*1024)),
2504 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2505 /* return simulated texture memory left */
2506 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2509 /*****
2510 * Get / Set Stream Source
2511 *****/
2512 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2513 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2516 IWineD3DBuffer *oldSrc;
2518 if (StreamNumber >= MAX_STREAMS) {
2519 WARN("Stream out of range %d\n", StreamNumber);
2520 return WINED3DERR_INVALIDCALL;
2521 } else if(OffsetInBytes & 0x3) {
2522 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2523 return WINED3DERR_INVALIDCALL;
2526 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2527 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2529 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2531 if(oldSrc == pStreamData &&
2532 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2533 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2534 TRACE("Application is setting the old values over, nothing to do\n");
2535 return WINED3D_OK;
2538 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2539 if (pStreamData) {
2540 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2541 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2544 /* Handle recording of state blocks */
2545 if (This->isRecordingState) {
2546 TRACE("Recording... not performing anything\n");
2547 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2548 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2549 return WINED3D_OK;
2552 if (pStreamData != NULL) {
2553 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2554 IWineD3DBuffer_AddRef(pStreamData);
2556 if (oldSrc != NULL) {
2557 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2558 IWineD3DBuffer_Release(oldSrc);
2561 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2563 return WINED3D_OK;
2566 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2567 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2571 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2572 This->stateBlock->streamSource[StreamNumber],
2573 This->stateBlock->streamOffset[StreamNumber],
2574 This->stateBlock->streamStride[StreamNumber]);
2576 if (StreamNumber >= MAX_STREAMS) {
2577 WARN("Stream out of range %d\n", StreamNumber);
2578 return WINED3DERR_INVALIDCALL;
2580 *pStream = This->stateBlock->streamSource[StreamNumber];
2581 *pStride = This->stateBlock->streamStride[StreamNumber];
2582 if (pOffset) {
2583 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2586 if (*pStream != NULL) {
2587 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2589 return WINED3D_OK;
2592 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2594 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2595 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2597 /* Verify input at least in d3d9 this is invalid*/
2598 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2599 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2600 return WINED3DERR_INVALIDCALL;
2602 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2603 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2604 return WINED3DERR_INVALIDCALL;
2606 if( Divider == 0 ){
2607 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2608 return WINED3DERR_INVALIDCALL;
2611 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2612 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2614 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2615 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2617 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2618 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2619 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2622 return WINED3D_OK;
2625 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2628 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2629 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2631 TRACE("(%p) : returning %d\n", This, *Divider);
2633 return WINED3D_OK;
2636 /*****
2637 * Get / Set & Multiply Transform
2638 *****/
2639 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2642 /* Most of this routine, comments included copied from ddraw tree initially: */
2643 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2645 /* Handle recording of state blocks */
2646 if (This->isRecordingState) {
2647 TRACE("Recording... not performing anything\n");
2648 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2649 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2650 return WINED3D_OK;
2654 * If the new matrix is the same as the current one,
2655 * we cut off any further processing. this seems to be a reasonable
2656 * optimization because as was noticed, some apps (warcraft3 for example)
2657 * tend towards setting the same matrix repeatedly for some reason.
2659 * From here on we assume that the new matrix is different, wherever it matters.
2661 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2662 TRACE("The app is setting the same matrix over again\n");
2663 return WINED3D_OK;
2664 } else {
2665 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2669 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2670 where ViewMat = Camera space, WorldMat = world space.
2672 In OpenGL, camera and world space is combined into GL_MODELVIEW
2673 matrix. The Projection matrix stay projection matrix.
2676 /* Capture the times we can just ignore the change for now */
2677 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2678 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2679 /* Handled by the state manager */
2682 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2683 return WINED3D_OK;
2686 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2688 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2689 *pMatrix = This->stateBlock->transforms[State];
2690 return WINED3D_OK;
2693 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2694 const WINED3DMATRIX *mat = NULL;
2695 WINED3DMATRIX temp;
2697 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2698 * below means it will be recorded in a state block change, but it
2699 * works regardless where it is recorded.
2700 * If this is found to be wrong, change to StateBlock.
2702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2703 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2705 if (State <= HIGHEST_TRANSFORMSTATE)
2707 mat = &This->updateStateBlock->transforms[State];
2708 } else {
2709 FIXME("Unhandled transform state!!\n");
2712 multiply_matrix(&temp, mat, pMatrix);
2714 /* Apply change via set transform - will reapply to eg. lights this way */
2715 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2718 /*****
2719 * Get / Set Light
2720 *****/
2721 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2722 you can reference any indexes you want as long as that number max are enabled at any
2723 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2724 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2725 but when recording, just build a chain pretty much of commands to be replayed. */
2727 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2728 float rho;
2729 PLIGHTINFOEL *object = NULL;
2730 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2731 struct list *e;
2733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2734 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2736 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2737 * the gl driver.
2739 if(!pLight) {
2740 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2741 return WINED3DERR_INVALIDCALL;
2744 switch(pLight->Type) {
2745 case WINED3DLIGHT_POINT:
2746 case WINED3DLIGHT_SPOT:
2747 case WINED3DLIGHT_PARALLELPOINT:
2748 case WINED3DLIGHT_GLSPOT:
2749 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2750 * most wanted
2752 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2754 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2755 return WINED3DERR_INVALIDCALL;
2757 break;
2759 case WINED3DLIGHT_DIRECTIONAL:
2760 /* Ignores attenuation */
2761 break;
2763 default:
2764 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2765 return WINED3DERR_INVALIDCALL;
2768 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2769 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2770 if(object->OriginalIndex == Index) break;
2771 object = NULL;
2774 if(!object) {
2775 TRACE("Adding new light\n");
2776 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2777 if(!object) {
2778 ERR("Out of memory error when allocating a light\n");
2779 return E_OUTOFMEMORY;
2781 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2782 object->glIndex = -1;
2783 object->OriginalIndex = Index;
2784 object->changed = TRUE;
2787 /* Initialize the object */
2788 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,
2789 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2790 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2791 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2792 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2793 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2794 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2796 /* Save away the information */
2797 object->OriginalParms = *pLight;
2799 switch (pLight->Type) {
2800 case WINED3DLIGHT_POINT:
2801 /* Position */
2802 object->lightPosn[0] = pLight->Position.x;
2803 object->lightPosn[1] = pLight->Position.y;
2804 object->lightPosn[2] = pLight->Position.z;
2805 object->lightPosn[3] = 1.0f;
2806 object->cutoff = 180.0f;
2807 /* FIXME: Range */
2808 break;
2810 case WINED3DLIGHT_DIRECTIONAL:
2811 /* Direction */
2812 object->lightPosn[0] = -pLight->Direction.x;
2813 object->lightPosn[1] = -pLight->Direction.y;
2814 object->lightPosn[2] = -pLight->Direction.z;
2815 object->lightPosn[3] = 0.0f;
2816 object->exponent = 0.0f;
2817 object->cutoff = 180.0f;
2818 break;
2820 case WINED3DLIGHT_SPOT:
2821 /* Position */
2822 object->lightPosn[0] = pLight->Position.x;
2823 object->lightPosn[1] = pLight->Position.y;
2824 object->lightPosn[2] = pLight->Position.z;
2825 object->lightPosn[3] = 1.0f;
2827 /* Direction */
2828 object->lightDirn[0] = pLight->Direction.x;
2829 object->lightDirn[1] = pLight->Direction.y;
2830 object->lightDirn[2] = pLight->Direction.z;
2831 object->lightDirn[3] = 1.0f;
2834 * opengl-ish and d3d-ish spot lights use too different models for the
2835 * light "intensity" as a function of the angle towards the main light direction,
2836 * so we only can approximate very roughly.
2837 * however spot lights are rather rarely used in games (if ever used at all).
2838 * furthermore if still used, probably nobody pays attention to such details.
2840 if (pLight->Falloff == 0) {
2841 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2842 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2843 * will always be 1.0 for both of them, and we don't have to care for the
2844 * rest of the rather complex calculation
2846 object->exponent = 0.0f;
2847 } else {
2848 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2849 if (rho < 0.0001f) rho = 0.0001f;
2850 object->exponent = -0.3f/logf(cosf(rho/2));
2852 if (object->exponent > 128.0f)
2854 object->exponent = 128.0f;
2856 object->cutoff = pLight->Phi*90/M_PI;
2858 /* FIXME: Range */
2859 break;
2861 default:
2862 FIXME("Unrecognized light type %d\n", pLight->Type);
2865 /* Update the live definitions if the light is currently assigned a glIndex */
2866 if (object->glIndex != -1 && !This->isRecordingState) {
2867 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2869 return WINED3D_OK;
2872 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2873 PLIGHTINFOEL *lightInfo = NULL;
2874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2875 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2876 struct list *e;
2877 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2879 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2880 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2881 if(lightInfo->OriginalIndex == Index) break;
2882 lightInfo = NULL;
2885 if (lightInfo == NULL) {
2886 TRACE("Light information requested but light not defined\n");
2887 return WINED3DERR_INVALIDCALL;
2890 *pLight = lightInfo->OriginalParms;
2891 return WINED3D_OK;
2894 /*****
2895 * Get / Set Light Enable
2896 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2897 *****/
2898 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2899 PLIGHTINFOEL *lightInfo = NULL;
2900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2901 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2902 struct list *e;
2903 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2905 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2906 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2907 if(lightInfo->OriginalIndex == Index) break;
2908 lightInfo = NULL;
2910 TRACE("Found light: %p\n", lightInfo);
2912 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2913 if (lightInfo == NULL) {
2915 TRACE("Light enabled requested but light not defined, so defining one!\n");
2916 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2918 /* Search for it again! Should be fairly quick as near head of list */
2919 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2920 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2921 if(lightInfo->OriginalIndex == Index) break;
2922 lightInfo = NULL;
2924 if (lightInfo == NULL) {
2925 FIXME("Adding default lights has failed dismally\n");
2926 return WINED3DERR_INVALIDCALL;
2930 lightInfo->enabledChanged = TRUE;
2931 if(!Enable) {
2932 if(lightInfo->glIndex != -1) {
2933 if(!This->isRecordingState) {
2934 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2937 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2938 lightInfo->glIndex = -1;
2939 } else {
2940 TRACE("Light already disabled, nothing to do\n");
2942 lightInfo->enabled = FALSE;
2943 } else {
2944 lightInfo->enabled = TRUE;
2945 if (lightInfo->glIndex != -1) {
2946 /* nop */
2947 TRACE("Nothing to do as light was enabled\n");
2948 } else {
2949 int i;
2950 /* Find a free gl light */
2951 for(i = 0; i < This->maxConcurrentLights; i++) {
2952 if(This->updateStateBlock->activeLights[i] == NULL) {
2953 This->updateStateBlock->activeLights[i] = lightInfo;
2954 lightInfo->glIndex = i;
2955 break;
2958 if(lightInfo->glIndex == -1) {
2959 /* Our tests show that Windows returns D3D_OK in this situation, even with
2960 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2961 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2962 * as well for those lights.
2964 * TODO: Test how this affects rendering
2966 WARN("Too many concurrently active lights\n");
2967 return WINED3D_OK;
2970 /* i == lightInfo->glIndex */
2971 if(!This->isRecordingState) {
2972 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2977 return WINED3D_OK;
2980 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2982 PLIGHTINFOEL *lightInfo = NULL;
2983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2984 struct list *e;
2985 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2986 TRACE("(%p) : for idx(%d)\n", This, Index);
2988 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2989 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2990 if(lightInfo->OriginalIndex == Index) break;
2991 lightInfo = NULL;
2994 if (lightInfo == NULL) {
2995 TRACE("Light enabled state requested but light not defined\n");
2996 return WINED3DERR_INVALIDCALL;
2998 /* true is 128 according to SetLightEnable */
2999 *pEnable = lightInfo->enabled ? 128 : 0;
3000 return WINED3D_OK;
3003 /*****
3004 * Get / Set Clip Planes
3005 *****/
3006 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3008 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3010 /* Validate Index */
3011 if (Index >= GL_LIMITS(clipplanes)) {
3012 TRACE("Application has requested clipplane this device doesn't support\n");
3013 return WINED3DERR_INVALIDCALL;
3016 This->updateStateBlock->changed.clipplane |= 1 << Index;
3018 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3019 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3020 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3021 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3022 TRACE("Application is setting old values over, nothing to do\n");
3023 return WINED3D_OK;
3026 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3027 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3028 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3029 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3031 /* Handle recording of state blocks */
3032 if (This->isRecordingState) {
3033 TRACE("Recording... not performing anything\n");
3034 return WINED3D_OK;
3037 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3039 return WINED3D_OK;
3042 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3044 TRACE("(%p) : for idx %d\n", This, Index);
3046 /* Validate Index */
3047 if (Index >= GL_LIMITS(clipplanes)) {
3048 TRACE("Application has requested clipplane this device doesn't support\n");
3049 return WINED3DERR_INVALIDCALL;
3052 pPlane[0] = This->stateBlock->clipplane[Index][0];
3053 pPlane[1] = This->stateBlock->clipplane[Index][1];
3054 pPlane[2] = This->stateBlock->clipplane[Index][2];
3055 pPlane[3] = This->stateBlock->clipplane[Index][3];
3056 return WINED3D_OK;
3059 /*****
3060 * Get / Set Clip Plane Status
3061 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3062 *****/
3063 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3065 FIXME("(%p) : stub\n", This);
3066 if (NULL == pClipStatus) {
3067 return WINED3DERR_INVALIDCALL;
3069 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3070 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3071 return WINED3D_OK;
3074 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3076 FIXME("(%p) : stub\n", This);
3077 if (NULL == pClipStatus) {
3078 return WINED3DERR_INVALIDCALL;
3080 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3081 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3082 return WINED3D_OK;
3085 /*****
3086 * Get / Set Material
3087 *****/
3088 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3091 This->updateStateBlock->changed.material = TRUE;
3092 This->updateStateBlock->material = *pMaterial;
3094 /* Handle recording of state blocks */
3095 if (This->isRecordingState) {
3096 TRACE("Recording... not performing anything\n");
3097 return WINED3D_OK;
3100 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3101 return WINED3D_OK;
3104 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3106 *pMaterial = This->updateStateBlock->material;
3107 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3108 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3109 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3110 pMaterial->Ambient.b, pMaterial->Ambient.a);
3111 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3112 pMaterial->Specular.b, pMaterial->Specular.a);
3113 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3114 pMaterial->Emissive.b, pMaterial->Emissive.a);
3115 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3117 return WINED3D_OK;
3120 /*****
3121 * Get / Set Indices
3122 *****/
3123 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DBuffer* pIndexData, WINED3DFORMAT fmt) {
3124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3125 IWineD3DBuffer *oldIdxs;
3127 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3128 oldIdxs = This->updateStateBlock->pIndexData;
3130 This->updateStateBlock->changed.indices = TRUE;
3131 This->updateStateBlock->pIndexData = pIndexData;
3132 This->updateStateBlock->IndexFmt = fmt;
3134 /* Handle recording of state blocks */
3135 if (This->isRecordingState) {
3136 TRACE("Recording... not performing anything\n");
3137 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3138 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3139 return WINED3D_OK;
3142 if(oldIdxs != pIndexData) {
3143 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3144 if(pIndexData) {
3145 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3146 IWineD3DBuffer_AddRef(pIndexData);
3148 if(oldIdxs) {
3149 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3150 IWineD3DBuffer_Release(oldIdxs);
3154 return WINED3D_OK;
3157 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DBuffer** ppIndexData) {
3158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3160 *ppIndexData = This->stateBlock->pIndexData;
3162 /* up ref count on ppindexdata */
3163 if (*ppIndexData) {
3164 IWineD3DBuffer_AddRef(*ppIndexData);
3165 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3166 }else{
3167 TRACE("(%p) No index data set\n", This);
3169 TRACE("Returning %p\n", *ppIndexData);
3171 return WINED3D_OK;
3174 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3175 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3177 TRACE("(%p)->(%d)\n", This, BaseIndex);
3179 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3180 TRACE("Application is setting the old value over, nothing to do\n");
3181 return WINED3D_OK;
3184 This->updateStateBlock->baseVertexIndex = BaseIndex;
3186 if (This->isRecordingState) {
3187 TRACE("Recording... not performing anything\n");
3188 return WINED3D_OK;
3190 /* The base vertex index affects the stream sources */
3191 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3192 return WINED3D_OK;
3195 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3197 TRACE("(%p) : base_index %p\n", This, base_index);
3199 *base_index = This->stateBlock->baseVertexIndex;
3201 TRACE("Returning %u\n", *base_index);
3203 return WINED3D_OK;
3206 /*****
3207 * Get / Set Viewports
3208 *****/
3209 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3212 TRACE("(%p)\n", This);
3213 This->updateStateBlock->changed.viewport = TRUE;
3214 This->updateStateBlock->viewport = *pViewport;
3216 /* Handle recording of state blocks */
3217 if (This->isRecordingState) {
3218 TRACE("Recording... not performing anything\n");
3219 return WINED3D_OK;
3222 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3223 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3225 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3226 return WINED3D_OK;
3230 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3232 TRACE("(%p)\n", This);
3233 *pViewport = This->stateBlock->viewport;
3234 return WINED3D_OK;
3237 /*****
3238 * Get / Set Render States
3239 * TODO: Verify against dx9 definitions
3240 *****/
3241 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3244 DWORD oldValue = This->stateBlock->renderState[State];
3246 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3248 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3249 This->updateStateBlock->renderState[State] = Value;
3251 /* Handle recording of state blocks */
3252 if (This->isRecordingState) {
3253 TRACE("Recording... not performing anything\n");
3254 return WINED3D_OK;
3257 /* Compared here and not before the assignment to allow proper stateblock recording */
3258 if(Value == oldValue) {
3259 TRACE("Application is setting the old value over, nothing to do\n");
3260 } else {
3261 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3264 return WINED3D_OK;
3267 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3269 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3270 *pValue = This->stateBlock->renderState[State];
3271 return WINED3D_OK;
3274 /*****
3275 * Get / Set Sampler States
3276 * TODO: Verify against dx9 definitions
3277 *****/
3279 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3281 DWORD oldValue;
3283 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3284 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3286 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3287 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3290 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3291 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3292 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3295 * SetSampler is designed to allow for more than the standard up to 8 textures
3296 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3297 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3299 * http://developer.nvidia.com/object/General_FAQ.html#t6
3301 * There are two new settings for GForce
3302 * the sampler one:
3303 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3304 * and the texture one:
3305 * GL_MAX_TEXTURE_COORDS_ARB.
3306 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3307 ******************/
3309 oldValue = This->stateBlock->samplerState[Sampler][Type];
3310 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3311 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3313 /* Handle recording of state blocks */
3314 if (This->isRecordingState) {
3315 TRACE("Recording... not performing anything\n");
3316 return WINED3D_OK;
3319 if(oldValue == Value) {
3320 TRACE("Application is setting the old value over, nothing to do\n");
3321 return WINED3D_OK;
3324 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3326 return WINED3D_OK;
3329 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3332 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3333 This, Sampler, debug_d3dsamplerstate(Type), Type);
3335 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3336 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3339 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3340 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3341 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3343 *Value = This->stateBlock->samplerState[Sampler][Type];
3344 TRACE("(%p) : Returning %#x\n", This, *Value);
3346 return WINED3D_OK;
3349 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3352 This->updateStateBlock->changed.scissorRect = TRUE;
3353 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3354 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3355 return WINED3D_OK;
3357 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3359 if(This->isRecordingState) {
3360 TRACE("Recording... not performing anything\n");
3361 return WINED3D_OK;
3364 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3366 return WINED3D_OK;
3369 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3370 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3372 *pRect = This->updateStateBlock->scissorRect;
3373 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3374 return WINED3D_OK;
3377 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3379 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3381 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3383 This->updateStateBlock->vertexDecl = pDecl;
3384 This->updateStateBlock->changed.vertexDecl = TRUE;
3386 if (This->isRecordingState) {
3387 TRACE("Recording... not performing anything\n");
3388 return WINED3D_OK;
3389 } else if(pDecl == oldDecl) {
3390 /* Checked after the assignment to allow proper stateblock recording */
3391 TRACE("Application is setting the old declaration over, nothing to do\n");
3392 return WINED3D_OK;
3395 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3396 return WINED3D_OK;
3399 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3402 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3404 *ppDecl = This->stateBlock->vertexDecl;
3405 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3406 return WINED3D_OK;
3409 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3410 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3411 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3413 This->updateStateBlock->vertexShader = pShader;
3414 This->updateStateBlock->changed.vertexShader = TRUE;
3416 if (This->isRecordingState) {
3417 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3418 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3419 TRACE("Recording... not performing anything\n");
3420 return WINED3D_OK;
3421 } else if(oldShader == pShader) {
3422 /* Checked here to allow proper stateblock recording */
3423 TRACE("App is setting the old shader over, nothing to do\n");
3424 return WINED3D_OK;
3427 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3428 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3429 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3431 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3433 return WINED3D_OK;
3436 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3439 if (NULL == ppShader) {
3440 return WINED3DERR_INVALIDCALL;
3442 *ppShader = This->stateBlock->vertexShader;
3443 if( NULL != *ppShader)
3444 IWineD3DVertexShader_AddRef(*ppShader);
3446 TRACE("(%p) : returning %p\n", This, *ppShader);
3447 return WINED3D_OK;
3450 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3451 IWineD3DDevice *iface,
3452 UINT start,
3453 CONST BOOL *srcData,
3454 UINT count) {
3456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3457 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3459 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3460 iface, srcData, start, count);
3462 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3464 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3465 for (i = 0; i < cnt; i++)
3466 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3468 for (i = start; i < cnt + start; ++i) {
3469 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3472 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3474 return WINED3D_OK;
3477 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3478 IWineD3DDevice *iface,
3479 UINT start,
3480 BOOL *dstData,
3481 UINT count) {
3483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3484 int cnt = min(count, MAX_CONST_B - start);
3486 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3487 iface, dstData, start, count);
3489 if (dstData == NULL || cnt < 0)
3490 return WINED3DERR_INVALIDCALL;
3492 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3493 return WINED3D_OK;
3496 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3497 IWineD3DDevice *iface,
3498 UINT start,
3499 CONST int *srcData,
3500 UINT count) {
3502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3503 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3505 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3506 iface, srcData, start, count);
3508 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3510 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3511 for (i = 0; i < cnt; i++)
3512 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3513 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3515 for (i = start; i < cnt + start; ++i) {
3516 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3519 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3521 return WINED3D_OK;
3524 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3525 IWineD3DDevice *iface,
3526 UINT start,
3527 int *dstData,
3528 UINT count) {
3530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3531 int cnt = min(count, MAX_CONST_I - start);
3533 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3534 iface, dstData, start, count);
3536 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3537 return WINED3DERR_INVALIDCALL;
3539 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3540 return WINED3D_OK;
3543 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3544 IWineD3DDevice *iface,
3545 UINT start,
3546 CONST float *srcData,
3547 UINT count) {
3549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3550 UINT i;
3552 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3553 iface, srcData, start, count);
3555 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3556 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3557 return WINED3DERR_INVALIDCALL;
3559 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3560 if(TRACE_ON(d3d)) {
3561 for (i = 0; i < count; i++)
3562 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3563 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3566 if (!This->isRecordingState)
3568 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3569 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3572 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3573 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3575 return WINED3D_OK;
3578 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3579 IWineD3DDevice *iface,
3580 UINT start,
3581 float *dstData,
3582 UINT count) {
3584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3585 int cnt = min(count, This->d3d_vshader_constantF - start);
3587 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3588 iface, dstData, start, count);
3590 if (dstData == NULL || cnt < 0)
3591 return WINED3DERR_INVALIDCALL;
3593 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3594 return WINED3D_OK;
3597 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3598 DWORD i;
3599 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3601 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3605 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3607 DWORD i = This->rev_tex_unit_map[unit];
3608 DWORD j = This->texUnitMap[stage];
3610 This->texUnitMap[stage] = unit;
3611 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3613 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3616 This->rev_tex_unit_map[unit] = stage;
3617 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3619 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3623 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3624 int i;
3626 This->fixed_function_usage_map = 0;
3627 for (i = 0; i < MAX_TEXTURES; ++i) {
3628 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3629 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3630 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3631 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3632 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3633 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3634 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3635 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3637 if (color_op == WINED3DTOP_DISABLE) {
3638 /* Not used, and disable higher stages */
3639 break;
3642 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3643 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3644 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3645 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3646 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3647 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3648 This->fixed_function_usage_map |= (1 << i);
3651 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3652 This->fixed_function_usage_map |= (1 << (i + 1));
3657 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3658 unsigned int i, tex;
3659 WORD ffu_map;
3661 device_update_fixed_function_usage_map(This);
3662 ffu_map = This->fixed_function_usage_map;
3664 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3665 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3666 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3668 if (!(ffu_map & 1)) continue;
3670 if (This->texUnitMap[i] != i) {
3671 device_map_stage(This, i, i);
3672 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3673 markTextureStagesDirty(This, i);
3676 return;
3679 /* Now work out the mapping */
3680 tex = 0;
3681 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3683 if (!(ffu_map & 1)) continue;
3685 if (This->texUnitMap[i] != tex) {
3686 device_map_stage(This, i, tex);
3687 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3688 markTextureStagesDirty(This, i);
3691 ++tex;
3695 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3696 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3697 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3698 unsigned int i;
3700 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3701 if (sampler_type[i] && This->texUnitMap[i] != i)
3703 device_map_stage(This, i, i);
3704 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3705 if (i < MAX_TEXTURES) {
3706 markTextureStagesDirty(This, i);
3712 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3713 const DWORD *vshader_sampler_tokens, DWORD unit)
3715 DWORD current_mapping = This->rev_tex_unit_map[unit];
3717 /* Not currently used */
3718 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3720 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3721 /* Used by a fragment sampler */
3723 if (!pshader_sampler_tokens) {
3724 /* No pixel shader, check fixed function */
3725 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3728 /* Pixel shader, check the shader's sampler map */
3729 return !pshader_sampler_tokens[current_mapping];
3732 /* Used by a vertex sampler */
3733 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3736 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3737 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3738 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3739 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3740 int start = min(MAX_COMBINED_SAMPLERS, GL_LIMITS(combined_samplers)) - 1;
3741 int i;
3743 if (ps) {
3744 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3746 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3747 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3748 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3751 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3752 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3753 if (vshader_sampler_type[i])
3755 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3757 /* Already mapped somewhere */
3758 continue;
3761 while (start >= 0) {
3762 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3764 device_map_stage(This, vsampler_idx, start);
3765 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3767 --start;
3768 break;
3771 --start;
3777 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3778 BOOL vs = use_vs(This->stateBlock);
3779 BOOL ps = use_ps(This->stateBlock);
3781 * Rules are:
3782 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3783 * that would be really messy and require shader recompilation
3784 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3785 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3787 if (ps) {
3788 device_map_psamplers(This);
3789 } else {
3790 device_map_fixed_function_samplers(This);
3793 if (vs) {
3794 device_map_vsamplers(This, ps);
3798 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3800 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3801 This->updateStateBlock->pixelShader = pShader;
3802 This->updateStateBlock->changed.pixelShader = TRUE;
3804 /* Handle recording of state blocks */
3805 if (This->isRecordingState) {
3806 TRACE("Recording... not performing anything\n");
3809 if (This->isRecordingState) {
3810 TRACE("Recording... not performing anything\n");
3811 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3812 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3813 return WINED3D_OK;
3816 if(pShader == oldShader) {
3817 TRACE("App is setting the old pixel shader over, nothing to do\n");
3818 return WINED3D_OK;
3821 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3822 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3824 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3825 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3827 return WINED3D_OK;
3830 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3833 if (NULL == ppShader) {
3834 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3835 return WINED3DERR_INVALIDCALL;
3838 *ppShader = This->stateBlock->pixelShader;
3839 if (NULL != *ppShader) {
3840 IWineD3DPixelShader_AddRef(*ppShader);
3842 TRACE("(%p) : returning %p\n", This, *ppShader);
3843 return WINED3D_OK;
3846 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3847 IWineD3DDevice *iface,
3848 UINT start,
3849 CONST BOOL *srcData,
3850 UINT count) {
3852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3853 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3855 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3856 iface, srcData, start, count);
3858 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3860 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3861 for (i = 0; i < cnt; i++)
3862 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3864 for (i = start; i < cnt + start; ++i) {
3865 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3868 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3870 return WINED3D_OK;
3873 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3874 IWineD3DDevice *iface,
3875 UINT start,
3876 BOOL *dstData,
3877 UINT count) {
3879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3880 int cnt = min(count, MAX_CONST_B - start);
3882 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3883 iface, dstData, start, count);
3885 if (dstData == NULL || cnt < 0)
3886 return WINED3DERR_INVALIDCALL;
3888 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3889 return WINED3D_OK;
3892 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3893 IWineD3DDevice *iface,
3894 UINT start,
3895 CONST int *srcData,
3896 UINT count) {
3898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3899 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3901 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3902 iface, srcData, start, count);
3904 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3906 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3907 for (i = 0; i < cnt; i++)
3908 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3909 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3911 for (i = start; i < cnt + start; ++i) {
3912 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3915 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3917 return WINED3D_OK;
3920 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3921 IWineD3DDevice *iface,
3922 UINT start,
3923 int *dstData,
3924 UINT count) {
3926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3927 int cnt = min(count, MAX_CONST_I - start);
3929 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3930 iface, dstData, start, count);
3932 if (dstData == NULL || cnt < 0)
3933 return WINED3DERR_INVALIDCALL;
3935 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3936 return WINED3D_OK;
3939 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3940 IWineD3DDevice *iface,
3941 UINT start,
3942 CONST float *srcData,
3943 UINT count) {
3945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3946 UINT i;
3948 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3949 iface, srcData, start, count);
3951 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3952 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3953 return WINED3DERR_INVALIDCALL;
3955 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3956 if(TRACE_ON(d3d)) {
3957 for (i = 0; i < count; i++)
3958 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3959 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3962 if (!This->isRecordingState)
3964 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3965 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3968 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3969 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3971 return WINED3D_OK;
3974 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3975 IWineD3DDevice *iface,
3976 UINT start,
3977 float *dstData,
3978 UINT count) {
3980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3981 int cnt = min(count, This->d3d_pshader_constantF - start);
3983 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3984 iface, dstData, start, count);
3986 if (dstData == NULL || cnt < 0)
3987 return WINED3DERR_INVALIDCALL;
3989 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3990 return WINED3D_OK;
3993 /* Context activation is done by the caller. */
3994 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3995 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3996 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3997 DWORD DestFVF)
3999 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4000 unsigned int i;
4001 WINED3DVIEWPORT vp;
4002 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4003 BOOL doClip;
4004 DWORD numTextures;
4006 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
4008 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4011 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
4013 ERR("Source has no position mask\n");
4014 return WINED3DERR_INVALIDCALL;
4017 /* We might access VBOs from this code, so hold the lock */
4018 ENTER_GL();
4020 if (dest->resource.allocatedMemory == NULL) {
4021 buffer_get_sysmem(dest);
4024 /* Get a pointer into the destination vbo(create one if none exists) and
4025 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4027 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4029 dest->flags |= WINED3D_BUFFER_CREATEBO;
4030 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4033 if (dest->buffer_object)
4035 unsigned char extrabytes = 0;
4036 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4037 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4038 * this may write 4 extra bytes beyond the area that should be written
4040 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4041 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4042 if(!dest_conv_addr) {
4043 ERR("Out of memory\n");
4044 /* Continue without storing converted vertices */
4046 dest_conv = dest_conv_addr;
4049 /* Should I clip?
4050 * a) WINED3DRS_CLIPPING is enabled
4051 * b) WINED3DVOP_CLIP is passed
4053 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4054 static BOOL warned = FALSE;
4056 * The clipping code is not quite correct. Some things need
4057 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4058 * so disable clipping for now.
4059 * (The graphics in Half-Life are broken, and my processvertices
4060 * test crashes with IDirect3DDevice3)
4061 doClip = TRUE;
4063 doClip = FALSE;
4064 if(!warned) {
4065 warned = TRUE;
4066 FIXME("Clipping is broken and disabled for now\n");
4068 } else doClip = FALSE;
4069 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4071 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4072 WINED3DTS_VIEW,
4073 &view_mat);
4074 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4075 WINED3DTS_PROJECTION,
4076 &proj_mat);
4077 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4078 WINED3DTS_WORLDMATRIX(0),
4079 &world_mat);
4081 TRACE("View mat:\n");
4082 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);
4083 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);
4084 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);
4085 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);
4087 TRACE("Proj mat:\n");
4088 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);
4089 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);
4090 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);
4091 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);
4093 TRACE("World mat:\n");
4094 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);
4095 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);
4096 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);
4097 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);
4099 /* Get the viewport */
4100 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4101 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4102 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4104 multiply_matrix(&mat,&view_mat,&world_mat);
4105 multiply_matrix(&mat,&proj_mat,&mat);
4107 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4109 for (i = 0; i < dwCount; i+= 1) {
4110 unsigned int tex_index;
4112 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4113 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4114 /* The position first */
4115 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4116 const float *p = (const float *)(element->data + i * element->stride);
4117 float x, y, z, rhw;
4118 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4120 /* Multiplication with world, view and projection matrix */
4121 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);
4122 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);
4123 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);
4124 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);
4126 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4128 /* WARNING: The following things are taken from d3d7 and were not yet checked
4129 * against d3d8 or d3d9!
4132 /* Clipping conditions: From msdn
4134 * A vertex is clipped if it does not match the following requirements
4135 * -rhw < x <= rhw
4136 * -rhw < y <= rhw
4137 * 0 < z <= rhw
4138 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4140 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4141 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4145 if( !doClip ||
4146 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4147 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4148 ( rhw > eps ) ) ) {
4150 /* "Normal" viewport transformation (not clipped)
4151 * 1) The values are divided by rhw
4152 * 2) The y axis is negative, so multiply it with -1
4153 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4154 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4155 * 4) Multiply x with Width/2 and add Width/2
4156 * 5) The same for the height
4157 * 6) Add the viewpoint X and Y to the 2D coordinates and
4158 * The minimum Z value to z
4159 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4161 * Well, basically it's simply a linear transformation into viewport
4162 * coordinates
4165 x /= rhw;
4166 y /= rhw;
4167 z /= rhw;
4169 y *= -1;
4171 x *= vp.Width / 2;
4172 y *= vp.Height / 2;
4173 z *= vp.MaxZ - vp.MinZ;
4175 x += vp.Width / 2 + vp.X;
4176 y += vp.Height / 2 + vp.Y;
4177 z += vp.MinZ;
4179 rhw = 1 / rhw;
4180 } else {
4181 /* That vertex got clipped
4182 * Contrary to OpenGL it is not dropped completely, it just
4183 * undergoes a different calculation.
4185 TRACE("Vertex got clipped\n");
4186 x += rhw;
4187 y += rhw;
4189 x /= 2;
4190 y /= 2;
4192 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4193 * outside of the main vertex buffer memory. That needs some more
4194 * investigation...
4198 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4201 ( (float *) dest_ptr)[0] = x;
4202 ( (float *) dest_ptr)[1] = y;
4203 ( (float *) dest_ptr)[2] = z;
4204 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4206 dest_ptr += 3 * sizeof(float);
4208 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4209 dest_ptr += sizeof(float);
4212 if(dest_conv) {
4213 float w = 1 / rhw;
4214 ( (float *) dest_conv)[0] = x * w;
4215 ( (float *) dest_conv)[1] = y * w;
4216 ( (float *) dest_conv)[2] = z * w;
4217 ( (float *) dest_conv)[3] = w;
4219 dest_conv += 3 * sizeof(float);
4221 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4222 dest_conv += sizeof(float);
4226 if (DestFVF & WINED3DFVF_PSIZE) {
4227 dest_ptr += sizeof(DWORD);
4228 if(dest_conv) dest_conv += sizeof(DWORD);
4230 if (DestFVF & WINED3DFVF_NORMAL) {
4231 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4232 const float *normal = (const float *)(element->data + i * element->stride);
4233 /* AFAIK this should go into the lighting information */
4234 FIXME("Didn't expect the destination to have a normal\n");
4235 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4236 if(dest_conv) {
4237 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4241 if (DestFVF & WINED3DFVF_DIFFUSE) {
4242 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4243 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4244 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4246 static BOOL warned = FALSE;
4248 if(!warned) {
4249 ERR("No diffuse color in source, but destination has one\n");
4250 warned = TRUE;
4253 *( (DWORD *) dest_ptr) = 0xffffffff;
4254 dest_ptr += sizeof(DWORD);
4256 if(dest_conv) {
4257 *( (DWORD *) dest_conv) = 0xffffffff;
4258 dest_conv += sizeof(DWORD);
4261 else {
4262 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4263 if(dest_conv) {
4264 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4265 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4266 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4267 dest_conv += sizeof(DWORD);
4272 if (DestFVF & WINED3DFVF_SPECULAR)
4274 /* What's the color value in the feedback buffer? */
4275 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4276 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4277 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4279 static BOOL warned = FALSE;
4281 if(!warned) {
4282 ERR("No specular color in source, but destination has one\n");
4283 warned = TRUE;
4286 *( (DWORD *) dest_ptr) = 0xFF000000;
4287 dest_ptr += sizeof(DWORD);
4289 if(dest_conv) {
4290 *( (DWORD *) dest_conv) = 0xFF000000;
4291 dest_conv += sizeof(DWORD);
4294 else {
4295 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4296 if(dest_conv) {
4297 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4298 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4299 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4300 dest_conv += sizeof(DWORD);
4305 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4306 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4307 const float *tex_coord = (const float *)(element->data + i * element->stride);
4308 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4310 ERR("No source texture, but destination requests one\n");
4311 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4312 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4314 else {
4315 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4316 if(dest_conv) {
4317 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4323 if(dest_conv) {
4324 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4325 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4326 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4327 dwCount * get_flexible_vertex_size(DestFVF),
4328 dest_conv_addr));
4329 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4330 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4333 LEAVE_GL();
4335 return WINED3D_OK;
4337 #undef copy_and_next
4339 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4340 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4341 DWORD DestFVF)
4343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4344 struct wined3d_stream_info stream_info;
4345 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4346 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4348 if(pVertexDecl) {
4349 ERR("Output vertex declaration not implemented yet\n");
4352 /* Need any context to write to the vbo. */
4353 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4355 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4356 * control the streamIsUP flag, thus restore it afterwards.
4358 This->stateBlock->streamIsUP = FALSE;
4359 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4360 This->stateBlock->streamIsUP = streamWasUP;
4362 if(vbo || SrcStartIndex) {
4363 unsigned int i;
4364 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4365 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4367 * Also get the start index in, but only loop over all elements if there's something to add at all.
4369 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4371 struct wined3d_stream_info_element *e;
4373 if (!(stream_info.use_map & (1 << i))) continue;
4375 e = &stream_info.elements[i];
4376 if (e->buffer_object)
4378 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4379 e->buffer_object = 0;
4380 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4381 ENTER_GL();
4382 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4383 vb->buffer_object = 0;
4384 LEAVE_GL();
4386 if (e->data) e->data += e->stride * SrcStartIndex;
4390 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4391 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4394 /*****
4395 * Get / Set Texture Stage States
4396 * TODO: Verify against dx9 definitions
4397 *****/
4398 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4400 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4402 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4404 if (Stage >= MAX_TEXTURES) {
4405 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4406 return WINED3D_OK;
4409 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4410 This->updateStateBlock->textureState[Stage][Type] = Value;
4412 if (This->isRecordingState) {
4413 TRACE("Recording... not performing anything\n");
4414 return WINED3D_OK;
4417 /* Checked after the assignments to allow proper stateblock recording */
4418 if(oldValue == Value) {
4419 TRACE("App is setting the old value over, nothing to do\n");
4420 return WINED3D_OK;
4423 if(Stage > This->stateBlock->lowest_disabled_stage &&
4424 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4425 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4426 * Changes in other states are important on disabled stages too
4428 return WINED3D_OK;
4431 if(Type == WINED3DTSS_COLOROP) {
4432 unsigned int i;
4434 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4435 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4436 * they have to be disabled
4438 * The current stage is dirtified below.
4440 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4441 TRACE("Additionally dirtifying stage %u\n", i);
4442 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4444 This->stateBlock->lowest_disabled_stage = Stage;
4445 TRACE("New lowest disabled: %u\n", Stage);
4446 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4447 /* Previously disabled stage enabled. Stages above it may need enabling
4448 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4449 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4451 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4454 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4455 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4456 break;
4458 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4459 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4461 This->stateBlock->lowest_disabled_stage = i;
4462 TRACE("New lowest disabled: %u\n", i);
4466 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4468 return WINED3D_OK;
4471 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4473 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4474 *pValue = This->updateStateBlock->textureState[Stage][Type];
4475 return WINED3D_OK;
4478 /*****
4479 * Get / Set Texture
4480 *****/
4481 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4483 IWineD3DBaseTexture *oldTexture;
4485 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4487 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4488 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4491 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4492 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4493 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4496 oldTexture = This->updateStateBlock->textures[Stage];
4498 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4499 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4501 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4502 return WINED3DERR_INVALIDCALL;
4505 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4506 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4508 This->updateStateBlock->changed.textures |= 1 << Stage;
4509 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4510 This->updateStateBlock->textures[Stage] = pTexture;
4512 /* Handle recording of state blocks */
4513 if (This->isRecordingState) {
4514 TRACE("Recording... not performing anything\n");
4515 return WINED3D_OK;
4518 if(oldTexture == pTexture) {
4519 TRACE("App is setting the same texture again, nothing to do\n");
4520 return WINED3D_OK;
4523 /** NOTE: MSDN says that setTexture increases the reference count,
4524 * and that the application must set the texture back to null (or have a leaky application),
4525 * This means we should pass the refcount up to the parent
4526 *******************************/
4527 if (NULL != This->updateStateBlock->textures[Stage]) {
4528 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4529 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4530 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4532 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4534 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4536 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4539 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4540 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4541 * so the COLOROP and ALPHAOP have to be dirtified.
4543 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4544 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4546 if(bindCount == 1) {
4547 new->baseTexture.sampler = Stage;
4549 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4553 if (NULL != oldTexture) {
4554 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4555 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4557 IWineD3DBaseTexture_Release(oldTexture);
4558 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4559 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4560 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4563 if(bindCount && old->baseTexture.sampler == Stage) {
4564 int i;
4565 /* Have to do a search for the other sampler(s) where the texture is bound to
4566 * Shouldn't happen as long as apps bind a texture only to one stage
4568 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4569 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4570 if(This->updateStateBlock->textures[i] == oldTexture) {
4571 old->baseTexture.sampler = i;
4572 break;
4578 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4580 return WINED3D_OK;
4583 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4586 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4588 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4589 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4592 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4593 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4594 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4597 *ppTexture=This->stateBlock->textures[Stage];
4598 if (*ppTexture)
4599 IWineD3DBaseTexture_AddRef(*ppTexture);
4601 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4603 return WINED3D_OK;
4606 /*****
4607 * Get Back Buffer
4608 *****/
4609 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4610 IWineD3DSurface **ppBackBuffer) {
4611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4612 IWineD3DSwapChain *swapChain;
4613 HRESULT hr;
4615 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4617 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4618 if (hr == WINED3D_OK) {
4619 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4620 IWineD3DSwapChain_Release(swapChain);
4621 } else {
4622 *ppBackBuffer = NULL;
4624 return hr;
4627 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4629 WARN("(%p) : stub, calling idirect3d for now\n", This);
4630 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4633 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4635 IWineD3DSwapChain *swapChain;
4636 HRESULT hr;
4638 if(iSwapChain > 0) {
4639 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4640 if (hr == WINED3D_OK) {
4641 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4642 IWineD3DSwapChain_Release(swapChain);
4643 } else {
4644 FIXME("(%p) Error getting display mode\n", This);
4646 } else {
4647 /* Don't read the real display mode,
4648 but return the stored mode instead. X11 can't change the color
4649 depth, and some apps are pretty angry if they SetDisplayMode from
4650 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4652 Also don't relay to the swapchain because with ddraw it's possible
4653 that there isn't a swapchain at all */
4654 pMode->Width = This->ddraw_width;
4655 pMode->Height = This->ddraw_height;
4656 pMode->Format = This->ddraw_format;
4657 pMode->RefreshRate = 0;
4658 hr = WINED3D_OK;
4661 return hr;
4664 /*****
4665 * Stateblock related functions
4666 *****/
4668 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4670 IWineD3DStateBlock *stateblock;
4671 HRESULT hr;
4673 TRACE("(%p)\n", This);
4675 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4677 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4678 if (FAILED(hr)) return hr;
4680 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4681 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4682 This->isRecordingState = TRUE;
4684 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4686 return WINED3D_OK;
4689 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4691 unsigned int i, j;
4692 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4694 if (!This->isRecordingState) {
4695 WARN("(%p) not recording! returning error\n", This);
4696 *ppStateBlock = NULL;
4697 return WINED3DERR_INVALIDCALL;
4700 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
4702 DWORD map = object->changed.renderState[i];
4703 for (j = 0; map; map >>= 1, ++j)
4705 if (!(map & 1)) continue;
4707 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
4711 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
4713 DWORD map = object->changed.transform[i];
4714 for (j = 0; map; map >>= 1, ++j)
4716 if (!(map & 1)) continue;
4718 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
4721 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4722 if(object->changed.vertexShaderConstantsF[i]) {
4723 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4724 object->num_contained_vs_consts_f++;
4727 for(i = 0; i < MAX_CONST_I; i++) {
4728 if (object->changed.vertexShaderConstantsI & (1 << i))
4730 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4731 object->num_contained_vs_consts_i++;
4734 for(i = 0; i < MAX_CONST_B; i++) {
4735 if (object->changed.vertexShaderConstantsB & (1 << i))
4737 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4738 object->num_contained_vs_consts_b++;
4741 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4743 if (object->changed.pixelShaderConstantsF[i])
4745 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4746 ++object->num_contained_ps_consts_f;
4749 for(i = 0; i < MAX_CONST_I; i++) {
4750 if (object->changed.pixelShaderConstantsI & (1 << i))
4752 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4753 object->num_contained_ps_consts_i++;
4756 for(i = 0; i < MAX_CONST_B; i++) {
4757 if (object->changed.pixelShaderConstantsB & (1 << i))
4759 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4760 object->num_contained_ps_consts_b++;
4763 for(i = 0; i < MAX_TEXTURES; i++) {
4764 DWORD map = object->changed.textureState[i];
4766 for(j = 0; map; map >>= 1, ++j)
4768 if (!(map & 1)) continue;
4770 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4771 object->contained_tss_states[object->num_contained_tss_states].state = j;
4772 ++object->num_contained_tss_states;
4775 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4776 DWORD map = object->changed.samplerState[i];
4778 for (j = 0; map; map >>= 1, ++j)
4780 if (!(map & 1)) continue;
4782 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4783 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4784 ++object->num_contained_sampler_states;
4788 *ppStateBlock = (IWineD3DStateBlock*) object;
4789 This->isRecordingState = FALSE;
4790 This->updateStateBlock = This->stateBlock;
4791 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4792 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4793 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4794 return WINED3D_OK;
4797 /*****
4798 * Scene related functions
4799 *****/
4800 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4801 /* At the moment we have no need for any functionality at the beginning
4802 of a scene */
4803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4804 TRACE("(%p)\n", This);
4806 if(This->inScene) {
4807 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4808 return WINED3DERR_INVALIDCALL;
4810 This->inScene = TRUE;
4811 return WINED3D_OK;
4814 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4816 TRACE("(%p)\n", This);
4818 if(!This->inScene) {
4819 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4820 return WINED3DERR_INVALIDCALL;
4823 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4824 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4825 wglFlush();
4826 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4827 * fails
4830 This->inScene = FALSE;
4831 return WINED3D_OK;
4834 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4835 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4836 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4838 IWineD3DSwapChain *swapChain = NULL;
4839 int i;
4840 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4842 TRACE("(%p) Presenting the frame\n", This);
4844 for(i = 0 ; i < swapchains ; i ++) {
4846 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4847 TRACE("presentinng chain %d, %p\n", i, swapChain);
4848 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4849 IWineD3DSwapChain_Release(swapChain);
4852 return WINED3D_OK;
4855 /* Not called from the VTable (internal subroutine) */
4856 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4857 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4858 float Z, DWORD Stencil) {
4859 GLbitfield glMask = 0;
4860 unsigned int i;
4861 WINED3DRECT curRect;
4862 RECT vp_rect;
4863 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4864 UINT drawable_width, drawable_height;
4865 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4866 IWineD3DSwapChainImpl *swapchain = NULL;
4867 struct wined3d_context *context;
4869 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4870 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4871 * for the cleared parts, and the untouched parts.
4873 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4874 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4875 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4876 * checking all this if the dest surface is in the drawable anyway.
4878 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4879 while(1) {
4880 if(vp->X != 0 || vp->Y != 0 ||
4881 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4882 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4883 break;
4885 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4886 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4887 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4888 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4889 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4890 break;
4892 if(Count > 0 && pRects && (
4893 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4894 pRects[0].x2 < target->currentDesc.Width ||
4895 pRects[0].y2 < target->currentDesc.Height)) {
4896 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4897 break;
4899 break;
4903 context = ActivateContext(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4905 target->get_drawable_size(context, &drawable_width, &drawable_height);
4907 ENTER_GL();
4909 /* Only set the values up once, as they are not changing */
4910 if (Flags & WINED3DCLEAR_STENCIL) {
4911 glClearStencil(Stencil);
4912 checkGLcall("glClearStencil");
4913 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4914 glStencilMask(0xFFFFFFFF);
4917 if (Flags & WINED3DCLEAR_ZBUFFER) {
4918 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4919 glDepthMask(GL_TRUE);
4920 glClearDepth(Z);
4921 checkGLcall("glClearDepth");
4922 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4923 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4925 if (vp->X != 0 || vp->Y != 0 ||
4926 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4927 surface_load_ds_location(This->stencilBufferTarget, context, location);
4929 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4930 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4931 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4932 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4933 surface_load_ds_location(This->stencilBufferTarget, context, location);
4935 else if (Count > 0 && pRects && (
4936 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4937 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4938 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4939 surface_load_ds_location(This->stencilBufferTarget, context, location);
4943 if (Flags & WINED3DCLEAR_TARGET) {
4944 TRACE("Clearing screen with glClear to color %x\n", Color);
4945 glClearColor(D3DCOLOR_R(Color),
4946 D3DCOLOR_G(Color),
4947 D3DCOLOR_B(Color),
4948 D3DCOLOR_A(Color));
4949 checkGLcall("glClearColor");
4951 /* Clear ALL colors! */
4952 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4953 glMask = glMask | GL_COLOR_BUFFER_BIT;
4956 vp_rect.left = vp->X;
4957 vp_rect.top = vp->Y;
4958 vp_rect.right = vp->X + vp->Width;
4959 vp_rect.bottom = vp->Y + vp->Height;
4960 if (!(Count > 0 && pRects)) {
4961 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4962 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4964 if (context->render_offscreen)
4966 glScissor(vp_rect.left, vp_rect.top,
4967 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4968 } else {
4969 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4970 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4972 checkGLcall("glScissor");
4973 glClear(glMask);
4974 checkGLcall("glClear");
4975 } else {
4976 /* Now process each rect in turn */
4977 for (i = 0; i < Count; i++) {
4978 /* Note gl uses lower left, width/height */
4979 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4980 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4981 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4983 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4984 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4985 curRect.x1, (target->currentDesc.Height - curRect.y2),
4986 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4988 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4989 * The rectangle is not cleared, no error is returned, but further rectanlges are
4990 * still cleared if they are valid
4992 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4993 TRACE("Rectangle with negative dimensions, ignoring\n");
4994 continue;
4997 if (context->render_offscreen)
4999 glScissor(curRect.x1, curRect.y1,
5000 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5001 } else {
5002 glScissor(curRect.x1, drawable_height - curRect.y2,
5003 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5005 checkGLcall("glScissor");
5007 glClear(glMask);
5008 checkGLcall("glClear");
5012 /* Restore the old values (why..?) */
5013 if (Flags & WINED3DCLEAR_STENCIL) {
5014 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5016 if (Flags & WINED3DCLEAR_TARGET) {
5017 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5018 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5019 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5020 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5021 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5023 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5024 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5026 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
5028 if (Flags & WINED3DCLEAR_ZBUFFER) {
5029 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5030 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5031 surface_modify_ds_location(This->stencilBufferTarget, location);
5034 LEAVE_GL();
5036 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5037 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5038 wglFlush();
5040 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5043 return WINED3D_OK;
5046 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5047 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5048 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5049 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5051 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5052 Count, pRects, Flags, Color, Z, Stencil);
5054 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5055 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5056 /* TODO: What about depth stencil buffers without stencil bits? */
5057 return WINED3DERR_INVALIDCALL;
5060 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5063 /*****
5064 * Drawing functions
5065 *****/
5067 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5068 WINED3DPRIMITIVETYPE primitive_type)
5070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5072 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5074 This->updateStateBlock->changed.primitive_type = TRUE;
5075 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5078 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5079 WINED3DPRIMITIVETYPE *primitive_type)
5081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5083 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5085 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5087 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5090 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5092 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5094 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5096 if(!This->stateBlock->vertexDecl) {
5097 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5098 return WINED3DERR_INVALIDCALL;
5101 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5102 if(This->stateBlock->streamIsUP) {
5103 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5104 This->stateBlock->streamIsUP = FALSE;
5107 if(This->stateBlock->loadBaseVertexIndex != 0) {
5108 This->stateBlock->loadBaseVertexIndex = 0;
5109 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5111 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5112 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
5113 return WINED3D_OK;
5116 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
5118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5119 UINT idxStride = 2;
5120 IWineD3DBuffer *pIB;
5121 GLuint vbo;
5123 pIB = This->stateBlock->pIndexData;
5124 if (!pIB) {
5125 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5126 * without an index buffer set. (The first time at least...)
5127 * D3D8 simply dies, but I doubt it can do much harm to return
5128 * D3DERR_INVALIDCALL there as well. */
5129 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5130 return WINED3DERR_INVALIDCALL;
5133 if(!This->stateBlock->vertexDecl) {
5134 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5135 return WINED3DERR_INVALIDCALL;
5138 if(This->stateBlock->streamIsUP) {
5139 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5140 This->stateBlock->streamIsUP = FALSE;
5142 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
5144 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
5146 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
5147 idxStride = 2;
5148 } else {
5149 idxStride = 4;
5152 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5153 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5154 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5157 drawPrimitive(iface, index_count, startIndex, idxStride,
5158 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
5160 return WINED3D_OK;
5163 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5164 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5167 IWineD3DBuffer *vb;
5169 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5170 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5172 if(!This->stateBlock->vertexDecl) {
5173 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5174 return WINED3DERR_INVALIDCALL;
5177 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5178 vb = This->stateBlock->streamSource[0];
5179 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5180 if (vb) IWineD3DBuffer_Release(vb);
5181 This->stateBlock->streamOffset[0] = 0;
5182 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5183 This->stateBlock->streamIsUP = TRUE;
5184 This->stateBlock->loadBaseVertexIndex = 0;
5186 /* TODO: Only mark dirty if drawing from a different UP address */
5187 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5189 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
5191 /* MSDN specifies stream zero settings must be set to NULL */
5192 This->stateBlock->streamStride[0] = 0;
5193 This->stateBlock->streamSource[0] = NULL;
5195 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5196 * the new stream sources or use UP drawing again
5198 return WINED3D_OK;
5201 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
5202 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5203 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5205 int idxStride;
5206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5207 IWineD3DBuffer *vb;
5208 IWineD3DBuffer *ib;
5210 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
5211 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5213 if(!This->stateBlock->vertexDecl) {
5214 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5215 return WINED3DERR_INVALIDCALL;
5218 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5219 idxStride = 2;
5220 } else {
5221 idxStride = 4;
5224 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5225 vb = This->stateBlock->streamSource[0];
5226 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5227 if (vb) IWineD3DBuffer_Release(vb);
5228 This->stateBlock->streamIsUP = TRUE;
5229 This->stateBlock->streamOffset[0] = 0;
5230 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5232 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5233 This->stateBlock->baseVertexIndex = 0;
5234 This->stateBlock->loadBaseVertexIndex = 0;
5235 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5236 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5237 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5239 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
5241 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5242 This->stateBlock->streamSource[0] = NULL;
5243 This->stateBlock->streamStride[0] = 0;
5244 ib = This->stateBlock->pIndexData;
5245 if(ib) {
5246 IWineD3DBuffer_Release(ib);
5247 This->stateBlock->pIndexData = NULL;
5249 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5250 * SetStreamSource to specify a vertex buffer
5253 return WINED3D_OK;
5256 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5257 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5261 /* Mark the state dirty until we have nicer tracking
5262 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5263 * that value.
5265 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5266 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5267 This->stateBlock->baseVertexIndex = 0;
5268 This->up_strided = DrawPrimStrideData;
5269 drawPrimitive(iface, vertex_count, 0, 0, NULL);
5270 This->up_strided = NULL;
5271 return WINED3D_OK;
5274 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5275 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5276 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5279 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5281 /* Mark the state dirty until we have nicer tracking
5282 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5283 * that value.
5285 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5286 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5287 This->stateBlock->streamIsUP = TRUE;
5288 This->stateBlock->baseVertexIndex = 0;
5289 This->up_strided = DrawPrimStrideData;
5290 drawPrimitive(iface, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData);
5291 This->up_strided = NULL;
5292 return WINED3D_OK;
5295 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5296 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5297 * not callable by the app directly no parameter validation checks are needed here.
5299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5300 WINED3DLOCKED_BOX src;
5301 WINED3DLOCKED_BOX dst;
5302 HRESULT hr;
5303 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5305 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5306 * dirtification to improve loading performance.
5308 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5309 if(FAILED(hr)) return hr;
5310 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5311 if(FAILED(hr)) {
5312 IWineD3DVolume_UnlockBox(pSourceVolume);
5313 return hr;
5316 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5318 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5319 if(FAILED(hr)) {
5320 IWineD3DVolume_UnlockBox(pSourceVolume);
5321 } else {
5322 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5324 return hr;
5327 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5328 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5330 HRESULT hr = WINED3D_OK;
5331 WINED3DRESOURCETYPE sourceType;
5332 WINED3DRESOURCETYPE destinationType;
5333 int i ,levels;
5335 /* TODO: think about moving the code into IWineD3DBaseTexture */
5337 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5339 /* verify that the source and destination textures aren't NULL */
5340 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5341 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5342 This, pSourceTexture, pDestinationTexture);
5343 hr = WINED3DERR_INVALIDCALL;
5346 if (pSourceTexture == pDestinationTexture) {
5347 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5348 This, pSourceTexture, pDestinationTexture);
5349 hr = WINED3DERR_INVALIDCALL;
5351 /* Verify that the source and destination textures are the same type */
5352 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5353 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5355 if (sourceType != destinationType) {
5356 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5357 This);
5358 hr = WINED3DERR_INVALIDCALL;
5361 /* check that both textures have the identical numbers of levels */
5362 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5363 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5364 hr = WINED3DERR_INVALIDCALL;
5367 if (WINED3D_OK == hr) {
5368 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5370 /* Make sure that the destination texture is loaded */
5371 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5373 /* Update every surface level of the texture */
5374 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5376 switch (sourceType) {
5377 case WINED3DRTYPE_TEXTURE:
5379 IWineD3DSurface *srcSurface;
5380 IWineD3DSurface *destSurface;
5382 for (i = 0 ; i < levels ; ++i) {
5383 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5384 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5385 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5386 IWineD3DSurface_Release(srcSurface);
5387 IWineD3DSurface_Release(destSurface);
5388 if (WINED3D_OK != hr) {
5389 WARN("(%p) : Call to update surface failed\n", This);
5390 return hr;
5394 break;
5395 case WINED3DRTYPE_CUBETEXTURE:
5397 IWineD3DSurface *srcSurface;
5398 IWineD3DSurface *destSurface;
5399 WINED3DCUBEMAP_FACES faceType;
5401 for (i = 0 ; i < levels ; ++i) {
5402 /* Update each cube face */
5403 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5404 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5405 if (WINED3D_OK != hr) {
5406 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5407 } else {
5408 TRACE("Got srcSurface %p\n", srcSurface);
5410 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5411 if (WINED3D_OK != hr) {
5412 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5413 } else {
5414 TRACE("Got desrSurface %p\n", destSurface);
5416 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5417 IWineD3DSurface_Release(srcSurface);
5418 IWineD3DSurface_Release(destSurface);
5419 if (WINED3D_OK != hr) {
5420 WARN("(%p) : Call to update surface failed\n", This);
5421 return hr;
5426 break;
5428 case WINED3DRTYPE_VOLUMETEXTURE:
5430 IWineD3DVolume *srcVolume = NULL;
5431 IWineD3DVolume *destVolume = NULL;
5433 for (i = 0 ; i < levels ; ++i) {
5434 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5435 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5436 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5437 IWineD3DVolume_Release(srcVolume);
5438 IWineD3DVolume_Release(destVolume);
5439 if (WINED3D_OK != hr) {
5440 WARN("(%p) : Call to update volume failed\n", This);
5441 return hr;
5445 break;
5447 default:
5448 FIXME("(%p) : Unsupported source and destination type\n", This);
5449 hr = WINED3DERR_INVALIDCALL;
5453 return hr;
5456 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5457 IWineD3DSwapChain *swapChain;
5458 HRESULT hr;
5459 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5460 if(hr == WINED3D_OK) {
5461 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5462 IWineD3DSwapChain_Release(swapChain);
5464 return hr;
5467 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5469 IWineD3DBaseTextureImpl *texture;
5470 DWORD i;
5472 TRACE("(%p) : %p\n", This, pNumPasses);
5474 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5475 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5476 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5477 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5479 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5480 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5481 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5484 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5485 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5487 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5488 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5489 return E_FAIL;
5491 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5492 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5493 return E_FAIL;
5495 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5496 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5497 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5498 return E_FAIL;
5502 /* return a sensible default */
5503 *pNumPasses = 1;
5505 TRACE("returning D3D_OK\n");
5506 return WINED3D_OK;
5509 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5511 int i;
5513 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5514 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5515 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
5516 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
5518 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5523 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5525 int j;
5526 UINT NewSize;
5527 PALETTEENTRY **palettes;
5529 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5531 if (PaletteNumber >= MAX_PALETTES) {
5532 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5533 return WINED3DERR_INVALIDCALL;
5536 if (PaletteNumber >= This->NumberOfPalettes) {
5537 NewSize = This->NumberOfPalettes;
5538 do {
5539 NewSize *= 2;
5540 } while(PaletteNumber >= NewSize);
5541 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5542 if (!palettes) {
5543 ERR("Out of memory!\n");
5544 return E_OUTOFMEMORY;
5546 This->palettes = palettes;
5547 This->NumberOfPalettes = NewSize;
5550 if (!This->palettes[PaletteNumber]) {
5551 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5552 if (!This->palettes[PaletteNumber]) {
5553 ERR("Out of memory!\n");
5554 return E_OUTOFMEMORY;
5558 for (j = 0; j < 256; ++j) {
5559 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5560 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5561 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5562 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5564 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5565 TRACE("(%p) : returning\n", This);
5566 return WINED3D_OK;
5569 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5571 int j;
5572 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5573 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5574 /* What happens in such situation isn't documented; Native seems to silently abort
5575 on such conditions. Return Invalid Call. */
5576 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5577 return WINED3DERR_INVALIDCALL;
5579 for (j = 0; j < 256; ++j) {
5580 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5581 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5582 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5583 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5585 TRACE("(%p) : returning\n", This);
5586 return WINED3D_OK;
5589 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5591 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5592 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5593 (tested with reference rasterizer). Return Invalid Call. */
5594 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5595 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5596 return WINED3DERR_INVALIDCALL;
5598 /*TODO: stateblocks */
5599 if (This->currentPalette != PaletteNumber) {
5600 This->currentPalette = PaletteNumber;
5601 dirtify_p8_texture_samplers(This);
5603 TRACE("(%p) : returning\n", This);
5604 return WINED3D_OK;
5607 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5609 if (PaletteNumber == NULL) {
5610 WARN("(%p) : returning Invalid Call\n", This);
5611 return WINED3DERR_INVALIDCALL;
5613 /*TODO: stateblocks */
5614 *PaletteNumber = This->currentPalette;
5615 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5616 return WINED3D_OK;
5619 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5621 static BOOL warned;
5622 if (!warned)
5624 FIXME("(%p) : stub\n", This);
5625 warned = TRUE;
5628 This->softwareVertexProcessing = bSoftware;
5629 return WINED3D_OK;
5633 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5635 static BOOL warned;
5636 if (!warned)
5638 FIXME("(%p) : stub\n", This);
5639 warned = TRUE;
5641 return This->softwareVertexProcessing;
5645 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5647 IWineD3DSwapChain *swapChain;
5648 HRESULT hr;
5650 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5652 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5653 if(hr == WINED3D_OK){
5654 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5655 IWineD3DSwapChain_Release(swapChain);
5656 }else{
5657 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5659 return hr;
5663 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5665 static BOOL warned;
5666 if(nSegments != 0.0f) {
5667 if (!warned)
5669 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5670 warned = TRUE;
5673 return WINED3D_OK;
5676 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5678 static BOOL warned;
5679 if (!warned)
5681 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5682 warned = TRUE;
5684 return 0.0f;
5687 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5689 /** TODO: remove casts to IWineD3DSurfaceImpl
5690 * NOTE: move code to surface to accomplish this
5691 ****************************************/
5692 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5693 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5694 int srcWidth, srcHeight;
5695 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5696 WINED3DFORMAT destFormat, srcFormat;
5697 UINT destSize;
5698 int srcLeft, destLeft, destTop;
5699 WINED3DPOOL srcPool, destPool;
5700 int offset = 0;
5701 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5702 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5703 GLenum dummy;
5704 DWORD sampler;
5705 int bpp;
5706 CONVERT_TYPES convert = NO_CONVERSION;
5708 WINED3DSURFACE_DESC winedesc;
5710 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5712 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5713 srcSurfaceWidth = winedesc.width;
5714 srcSurfaceHeight = winedesc.height;
5715 srcPool = winedesc.pool;
5716 srcFormat = winedesc.format;
5718 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5719 destSurfaceWidth = winedesc.width;
5720 destSurfaceHeight = winedesc.height;
5721 destPool = winedesc.pool;
5722 destFormat = winedesc.format;
5723 destSize = winedesc.size;
5725 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5726 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5727 return WINED3DERR_INVALIDCALL;
5730 /* This call loads the opengl surface directly, instead of copying the surface to the
5731 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5732 * copy in sysmem and use regular surface loading.
5734 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5735 if(convert != NO_CONVERSION) {
5736 return IWineD3DSurface_BltFast(pDestinationSurface,
5737 pDestPoint ? pDestPoint->x : 0,
5738 pDestPoint ? pDestPoint->y : 0,
5739 pSourceSurface, pSourceRect, 0);
5742 if (destFormat == WINED3DFMT_UNKNOWN) {
5743 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5744 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5746 /* Get the update surface description */
5747 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5750 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
5752 ENTER_GL();
5753 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5754 checkGLcall("glActiveTextureARB");
5755 LEAVE_GL();
5757 /* Make sure the surface is loaded and up to date */
5758 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5759 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5761 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5762 dst_format_desc = dst_impl->resource.format_desc;
5764 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5765 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5766 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5767 srcLeft = pSourceRect ? pSourceRect->left : 0;
5768 destLeft = pDestPoint ? pDestPoint->x : 0;
5769 destTop = pDestPoint ? pDestPoint->y : 0;
5772 /* This function doesn't support compressed textures
5773 the pitch is just bytesPerPixel * width */
5774 if(srcWidth != srcSurfaceWidth || srcLeft ){
5775 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5776 offset += srcLeft * src_format_desc->byte_count;
5777 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5779 /* TODO DXT formats */
5781 if(pSourceRect != NULL && pSourceRect->top != 0){
5782 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5784 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5785 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5786 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5788 /* Sanity check */
5789 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5791 /* need to lock the surface to get the data */
5792 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5795 ENTER_GL();
5797 /* TODO: Cube and volume support */
5798 if(rowoffset != 0){
5799 /* not a whole row so we have to do it a line at a time */
5800 int j;
5802 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5803 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5805 for (j = destTop; j < (srcHeight + destTop); ++j)
5807 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5808 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5809 data += rowoffset;
5812 } else { /* Full width, so just write out the whole texture */
5813 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5815 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5817 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5819 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5820 FIXME("Updating part of a compressed texture is not supported.\n");
5822 if (destFormat != srcFormat)
5824 FIXME("Updating mixed format compressed textures is not supported.\n");
5826 else
5828 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5829 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5832 else
5834 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5835 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5838 checkGLcall("glTexSubImage2D");
5840 LEAVE_GL();
5842 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5843 sampler = This->rev_tex_unit_map[0];
5844 if (sampler != WINED3D_UNMAPPED_STAGE)
5846 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5849 return WINED3D_OK;
5852 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5854 struct WineD3DRectPatch *patch;
5855 GLenum old_primitive_type;
5856 unsigned int i;
5857 struct list *e;
5858 BOOL found;
5859 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5861 if(!(Handle || pRectPatchInfo)) {
5862 /* TODO: Write a test for the return value, thus the FIXME */
5863 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5864 return WINED3DERR_INVALIDCALL;
5867 if(Handle) {
5868 i = PATCHMAP_HASHFUNC(Handle);
5869 found = FALSE;
5870 LIST_FOR_EACH(e, &This->patches[i]) {
5871 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5872 if(patch->Handle == Handle) {
5873 found = TRUE;
5874 break;
5878 if(!found) {
5879 TRACE("Patch does not exist. Creating a new one\n");
5880 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5881 patch->Handle = Handle;
5882 list_add_head(&This->patches[i], &patch->entry);
5883 } else {
5884 TRACE("Found existing patch %p\n", patch);
5886 } else {
5887 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5888 * attributes we have to tesselate, read back, and draw. This needs a patch
5889 * management structure instance. Create one.
5891 * A possible improvement is to check if a vertex shader is used, and if not directly
5892 * draw the patch.
5894 FIXME("Drawing an uncached patch. This is slow\n");
5895 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5898 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5899 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5900 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5901 HRESULT hr;
5902 TRACE("Tesselation density or patch info changed, retesselating\n");
5904 if(pRectPatchInfo) {
5905 patch->RectPatchInfo = *pRectPatchInfo;
5907 patch->numSegs[0] = pNumSegs[0];
5908 patch->numSegs[1] = pNumSegs[1];
5909 patch->numSegs[2] = pNumSegs[2];
5910 patch->numSegs[3] = pNumSegs[3];
5912 hr = tesselate_rectpatch(This, patch);
5913 if(FAILED(hr)) {
5914 WARN("Patch tesselation failed\n");
5916 /* Do not release the handle to store the params of the patch */
5917 if(!Handle) {
5918 HeapFree(GetProcessHeap(), 0, patch);
5920 return hr;
5924 This->currentPatch = patch;
5925 old_primitive_type = This->stateBlock->gl_primitive_type;
5926 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5927 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5928 This->stateBlock->gl_primitive_type = old_primitive_type;
5929 This->currentPatch = NULL;
5931 /* Destroy uncached patches */
5932 if(!Handle) {
5933 HeapFree(GetProcessHeap(), 0, patch->mem);
5934 HeapFree(GetProcessHeap(), 0, patch);
5936 return WINED3D_OK;
5939 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5941 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5942 FIXME("(%p) : Stub\n", This);
5943 return WINED3D_OK;
5946 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5948 int i;
5949 struct WineD3DRectPatch *patch;
5950 struct list *e;
5951 TRACE("(%p) Handle(%d)\n", This, Handle);
5953 i = PATCHMAP_HASHFUNC(Handle);
5954 LIST_FOR_EACH(e, &This->patches[i]) {
5955 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5956 if(patch->Handle == Handle) {
5957 TRACE("Deleting patch %p\n", patch);
5958 list_remove(&patch->entry);
5959 HeapFree(GetProcessHeap(), 0, patch->mem);
5960 HeapFree(GetProcessHeap(), 0, patch);
5961 return WINED3D_OK;
5965 /* TODO: Write a test for the return value */
5966 FIXME("Attempt to destroy nonexistent patch\n");
5967 return WINED3DERR_INVALIDCALL;
5970 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5971 HRESULT hr;
5972 IWineD3DSwapChain *swapchain;
5974 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5975 if (SUCCEEDED(hr)) {
5976 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5977 return swapchain;
5980 return NULL;
5983 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5984 const WINED3DRECT *rect, const float color[4])
5986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5987 struct wined3d_context *context;
5988 IWineD3DSwapChain *swapchain;
5990 swapchain = get_swapchain(surface);
5991 if (swapchain) {
5992 GLenum buffer;
5994 TRACE("Surface %p is onscreen\n", surface);
5996 context = ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
5997 ENTER_GL();
5998 context_bind_fbo(context, GL_FRAMEBUFFER_EXT, NULL);
5999 buffer = surface_get_gl_buffer(surface, swapchain);
6000 glDrawBuffer(buffer);
6001 checkGLcall("glDrawBuffer()");
6002 } else {
6003 TRACE("Surface %p is offscreen\n", surface);
6005 context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6006 ENTER_GL();
6007 context_bind_fbo(context, GL_FRAMEBUFFER_EXT, &context->dst_fbo);
6008 context_attach_surface_fbo(context, GL_FRAMEBUFFER_EXT, 0, surface);
6009 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER_EXT, NULL, FALSE);
6012 if (rect) {
6013 glEnable(GL_SCISSOR_TEST);
6014 if(!swapchain) {
6015 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6016 } else {
6017 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6018 rect->x2 - rect->x1, rect->y2 - rect->y1);
6020 checkGLcall("glScissor");
6021 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6022 } else {
6023 glDisable(GL_SCISSOR_TEST);
6025 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6027 glDisable(GL_BLEND);
6028 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6030 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6031 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6033 glClearColor(color[0], color[1], color[2], color[3]);
6034 glClear(GL_COLOR_BUFFER_BIT);
6035 checkGLcall("glClear");
6037 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6038 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6039 glDrawBuffer(GL_BACK);
6040 checkGLcall("glDrawBuffer()");
6043 LEAVE_GL();
6046 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6047 unsigned int r, g, b, a;
6048 DWORD ret;
6050 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6051 destfmt == WINED3DFMT_R8G8B8)
6052 return color;
6054 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6056 a = (color & 0xff000000) >> 24;
6057 r = (color & 0x00ff0000) >> 16;
6058 g = (color & 0x0000ff00) >> 8;
6059 b = (color & 0x000000ff) >> 0;
6061 switch(destfmt)
6063 case WINED3DFMT_R5G6B5:
6064 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6065 r = (r * 32) / 256;
6066 g = (g * 64) / 256;
6067 b = (b * 32) / 256;
6068 ret = r << 11;
6069 ret |= g << 5;
6070 ret |= b;
6071 TRACE("Returning %08x\n", ret);
6072 return ret;
6074 case WINED3DFMT_X1R5G5B5:
6075 case WINED3DFMT_A1R5G5B5:
6076 a = (a * 2) / 256;
6077 r = (r * 32) / 256;
6078 g = (g * 32) / 256;
6079 b = (b * 32) / 256;
6080 ret = a << 15;
6081 ret |= r << 10;
6082 ret |= g << 5;
6083 ret |= b << 0;
6084 TRACE("Returning %08x\n", ret);
6085 return ret;
6087 case WINED3DFMT_A8_UNORM:
6088 TRACE("Returning %08x\n", a);
6089 return a;
6091 case WINED3DFMT_X4R4G4B4:
6092 case WINED3DFMT_A4R4G4B4:
6093 a = (a * 16) / 256;
6094 r = (r * 16) / 256;
6095 g = (g * 16) / 256;
6096 b = (b * 16) / 256;
6097 ret = a << 12;
6098 ret |= r << 8;
6099 ret |= g << 4;
6100 ret |= b << 0;
6101 TRACE("Returning %08x\n", ret);
6102 return ret;
6104 case WINED3DFMT_R3G3B2:
6105 r = (r * 8) / 256;
6106 g = (g * 8) / 256;
6107 b = (b * 4) / 256;
6108 ret = r << 5;
6109 ret |= g << 2;
6110 ret |= b << 0;
6111 TRACE("Returning %08x\n", ret);
6112 return ret;
6114 case WINED3DFMT_X8B8G8R8:
6115 case WINED3DFMT_R8G8B8A8_UNORM:
6116 ret = a << 24;
6117 ret |= b << 16;
6118 ret |= g << 8;
6119 ret |= r << 0;
6120 TRACE("Returning %08x\n", ret);
6121 return ret;
6123 case WINED3DFMT_A2R10G10B10:
6124 a = (a * 4) / 256;
6125 r = (r * 1024) / 256;
6126 g = (g * 1024) / 256;
6127 b = (b * 1024) / 256;
6128 ret = a << 30;
6129 ret |= r << 20;
6130 ret |= g << 10;
6131 ret |= b << 0;
6132 TRACE("Returning %08x\n", ret);
6133 return ret;
6135 case WINED3DFMT_R10G10B10A2_UNORM:
6136 a = (a * 4) / 256;
6137 r = (r * 1024) / 256;
6138 g = (g * 1024) / 256;
6139 b = (b * 1024) / 256;
6140 ret = a << 30;
6141 ret |= b << 20;
6142 ret |= g << 10;
6143 ret |= r << 0;
6144 TRACE("Returning %08x\n", ret);
6145 return ret;
6147 default:
6148 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6149 return 0;
6153 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6155 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6156 WINEDDBLTFX BltFx;
6157 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6159 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6160 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6161 return WINED3DERR_INVALIDCALL;
6164 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6165 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6166 color_fill_fbo(iface, pSurface, pRect, c);
6167 return WINED3D_OK;
6168 } else {
6169 /* Just forward this to the DirectDraw blitting engine */
6170 memset(&BltFx, 0, sizeof(BltFx));
6171 BltFx.dwSize = sizeof(BltFx);
6172 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6173 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6174 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
6178 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6179 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6181 IWineD3DResource *resource;
6182 IWineD3DSurface *surface;
6183 HRESULT hr;
6185 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6186 if (FAILED(hr))
6188 ERR("Failed to get resource, hr %#x\n", hr);
6189 return;
6192 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6194 FIXME("Only supported on surface resources\n");
6195 IWineD3DResource_Release(resource);
6196 return;
6199 surface = (IWineD3DSurface *)resource;
6201 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6203 color_fill_fbo(iface, surface, NULL, color);
6205 else
6207 WINEDDBLTFX BltFx;
6208 WINED3DCOLOR c;
6210 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6212 c = ((DWORD)(color[2] * 255.0f));
6213 c |= ((DWORD)(color[1] * 255.0f)) << 8;
6214 c |= ((DWORD)(color[0] * 255.0f)) << 16;
6215 c |= ((DWORD)(color[3] * 255.0f)) << 24;
6217 /* Just forward this to the DirectDraw blitting engine */
6218 memset(&BltFx, 0, sizeof(BltFx));
6219 BltFx.dwSize = sizeof(BltFx);
6220 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6221 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
6222 if (FAILED(hr))
6224 ERR("Blt failed, hr %#x\n", hr);
6228 IWineD3DResource_Release(resource);
6231 /* rendertarget and depth stencil functions */
6232 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6235 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6236 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6237 return WINED3DERR_INVALIDCALL;
6240 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6241 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6242 /* Note inc ref on returned surface */
6243 if(*ppRenderTarget != NULL)
6244 IWineD3DSurface_AddRef(*ppRenderTarget);
6245 return WINED3D_OK;
6248 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6250 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6251 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6252 IWineD3DSwapChainImpl *Swapchain;
6253 HRESULT hr;
6255 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6257 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6258 if(hr != WINED3D_OK) {
6259 ERR("Can't get the swapchain\n");
6260 return hr;
6263 /* Make sure to release the swapchain */
6264 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6266 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6267 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6268 return WINED3DERR_INVALIDCALL;
6270 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6271 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6272 return WINED3DERR_INVALIDCALL;
6275 if(Swapchain->frontBuffer != Front) {
6276 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6278 if(Swapchain->frontBuffer)
6280 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6281 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6283 Swapchain->frontBuffer = Front;
6285 if(Swapchain->frontBuffer) {
6286 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6287 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6291 if(Back && !Swapchain->backBuffer) {
6292 /* We need memory for the back buffer array - only one back buffer this way */
6293 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6294 if(!Swapchain->backBuffer) {
6295 ERR("Out of memory\n");
6296 return E_OUTOFMEMORY;
6300 if(Swapchain->backBuffer[0] != Back) {
6301 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6303 /* What to do about the context here in the case of multithreading? Not sure.
6304 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6306 WARN("No active context?\n");
6308 ENTER_GL();
6309 if(!Swapchain->backBuffer[0]) {
6310 /* GL was told to draw to the front buffer at creation,
6311 * undo that
6313 glDrawBuffer(GL_BACK);
6314 checkGLcall("glDrawBuffer(GL_BACK)");
6315 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6316 Swapchain->presentParms.BackBufferCount = 1;
6317 } else if (!Back) {
6318 /* That makes problems - disable for now */
6319 /* glDrawBuffer(GL_FRONT); */
6320 checkGLcall("glDrawBuffer(GL_FRONT)");
6321 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6322 Swapchain->presentParms.BackBufferCount = 0;
6324 LEAVE_GL();
6326 if(Swapchain->backBuffer[0])
6328 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6329 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6331 Swapchain->backBuffer[0] = Back;
6333 if(Swapchain->backBuffer[0]) {
6334 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6335 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6336 } else {
6337 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6338 Swapchain->backBuffer = NULL;
6343 return WINED3D_OK;
6346 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6347 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6348 *ppZStencilSurface = This->stencilBufferTarget;
6349 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6351 if(*ppZStencilSurface != NULL) {
6352 /* Note inc ref on returned surface */
6353 IWineD3DSurface_AddRef(*ppZStencilSurface);
6354 return WINED3D_OK;
6355 } else {
6356 return WINED3DERR_NOTFOUND;
6360 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6361 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6364 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6365 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6366 struct wined3d_context *context;
6367 GLenum gl_filter;
6368 POINT offset = {0, 0};
6370 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6371 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6372 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6373 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6375 switch (filter) {
6376 case WINED3DTEXF_LINEAR:
6377 gl_filter = GL_LINEAR;
6378 break;
6380 default:
6381 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6382 case WINED3DTEXF_NONE:
6383 case WINED3DTEXF_POINT:
6384 gl_filter = GL_NEAREST;
6385 break;
6388 /* Attach src surface to src fbo */
6389 src_swapchain = get_swapchain(src_surface);
6390 dst_swapchain = get_swapchain(dst_surface);
6392 if (src_swapchain) context = ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6393 else if (dst_swapchain) context = ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6394 else context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6396 if (src_swapchain) {
6397 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6399 TRACE("Source surface %p is onscreen\n", src_surface);
6400 /* Make sure the drawable is up to date. In the offscreen case
6401 * attach_surface_fbo() implicitly takes care of this. */
6402 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6404 if(buffer == GL_FRONT) {
6405 RECT windowsize;
6406 UINT h;
6407 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6408 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6409 h = windowsize.bottom - windowsize.top;
6410 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6411 src_rect->y1 = offset.y + h - src_rect->y1;
6412 src_rect->y2 = offset.y + h - src_rect->y2;
6413 } else {
6414 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6415 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6418 ENTER_GL();
6419 context_bind_fbo(context, GL_READ_FRAMEBUFFER_EXT, NULL);
6420 glReadBuffer(buffer);
6421 checkGLcall("glReadBuffer()");
6422 } else {
6423 TRACE("Source surface %p is offscreen\n", src_surface);
6424 ENTER_GL();
6425 context_bind_fbo(context, GL_READ_FRAMEBUFFER_EXT, &context->src_fbo);
6426 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6427 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6428 checkGLcall("glReadBuffer()");
6429 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER_EXT, NULL, FALSE);
6431 LEAVE_GL();
6433 /* Attach dst surface to dst fbo */
6434 if (dst_swapchain) {
6435 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6437 TRACE("Destination surface %p is onscreen\n", dst_surface);
6438 /* Make sure the drawable is up to date. In the offscreen case
6439 * attach_surface_fbo() implicitly takes care of this. */
6440 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6442 if(buffer == GL_FRONT) {
6443 RECT windowsize;
6444 UINT h;
6445 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6446 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6447 h = windowsize.bottom - windowsize.top;
6448 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6449 dst_rect->y1 = offset.y + h - dst_rect->y1;
6450 dst_rect->y2 = offset.y + h - dst_rect->y2;
6451 } else {
6452 /* Screen coords = window coords, surface height = window height */
6453 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6454 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6457 ENTER_GL();
6458 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER_EXT, NULL);
6459 glDrawBuffer(buffer);
6460 checkGLcall("glDrawBuffer()");
6461 } else {
6462 TRACE("Destination surface %p is offscreen\n", dst_surface);
6464 ENTER_GL();
6465 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER_EXT, &context->dst_fbo);
6466 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6467 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6468 checkGLcall("glDrawBuffer()");
6469 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER_EXT, NULL, FALSE);
6471 glDisable(GL_SCISSOR_TEST);
6472 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6474 if (flip) {
6475 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6476 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6477 checkGLcall("glBlitFramebuffer()");
6478 } else {
6479 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6480 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6481 checkGLcall("glBlitFramebuffer()");
6484 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6486 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6487 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6488 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6489 glDrawBuffer(GL_BACK);
6490 checkGLcall("glDrawBuffer()");
6492 LEAVE_GL();
6495 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6497 WINED3DVIEWPORT viewport;
6499 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6501 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6502 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6503 This, RenderTargetIndex, GL_LIMITS(buffers));
6504 return WINED3DERR_INVALIDCALL;
6507 /* MSDN says that null disables the render target
6508 but a device must always be associated with a render target
6509 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6511 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6512 FIXME("Trying to set render target 0 to NULL\n");
6513 return WINED3DERR_INVALIDCALL;
6515 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6516 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);
6517 return WINED3DERR_INVALIDCALL;
6520 /* If we are trying to set what we already have, don't bother */
6521 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6522 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6523 return WINED3D_OK;
6525 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6526 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6527 This->render_targets[RenderTargetIndex] = pRenderTarget;
6529 /* Render target 0 is special */
6530 if(RenderTargetIndex == 0) {
6531 /* Finally, reset the viewport as the MSDN states. */
6532 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6533 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6534 viewport.X = 0;
6535 viewport.Y = 0;
6536 viewport.MaxZ = 1.0f;
6537 viewport.MinZ = 0.0f;
6538 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6540 return WINED3D_OK;
6543 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6545 HRESULT hr = WINED3D_OK;
6546 IWineD3DSurface *tmp;
6548 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6550 if (pNewZStencil == This->stencilBufferTarget) {
6551 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6552 } else {
6553 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6554 * depending on the renter target implementation being used.
6555 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6556 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6557 * stencil buffer and incur an extra memory overhead
6558 ******************************************************/
6560 if (This->stencilBufferTarget) {
6561 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6562 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6563 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6564 } else {
6565 struct wined3d_context *context = ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6566 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
6567 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6571 tmp = This->stencilBufferTarget;
6572 This->stencilBufferTarget = pNewZStencil;
6573 /* should we be calling the parent or the wined3d surface? */
6574 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6575 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6576 hr = WINED3D_OK;
6578 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6579 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6580 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6581 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6582 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6586 return hr;
6589 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6590 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6592 /* TODO: the use of Impl is deprecated. */
6593 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6594 WINED3DLOCKED_RECT lockedRect;
6596 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6598 /* some basic validation checks */
6599 if(This->cursorTexture) {
6600 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6601 ENTER_GL();
6602 glDeleteTextures(1, &This->cursorTexture);
6603 LEAVE_GL();
6604 This->cursorTexture = 0;
6607 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6608 This->haveHardwareCursor = TRUE;
6609 else
6610 This->haveHardwareCursor = FALSE;
6612 if(pCursorBitmap) {
6613 WINED3DLOCKED_RECT rect;
6615 /* MSDN: Cursor must be A8R8G8B8 */
6616 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
6618 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6619 return WINED3DERR_INVALIDCALL;
6622 /* MSDN: Cursor must be smaller than the display mode */
6623 if(pSur->currentDesc.Width > This->ddraw_width ||
6624 pSur->currentDesc.Height > This->ddraw_height) {
6625 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);
6626 return WINED3DERR_INVALIDCALL;
6629 if (!This->haveHardwareCursor) {
6630 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6632 /* Do not store the surface's pointer because the application may
6633 * release it after setting the cursor image. Windows doesn't
6634 * addref the set surface, so we can't do this either without
6635 * creating circular refcount dependencies. Copy out the gl texture
6636 * instead.
6638 This->cursorWidth = pSur->currentDesc.Width;
6639 This->cursorHeight = pSur->currentDesc.Height;
6640 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6642 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
6643 char *mem, *bits = rect.pBits;
6644 GLint intfmt = glDesc->glInternal;
6645 GLint format = glDesc->glFormat;
6646 GLint type = glDesc->glType;
6647 INT height = This->cursorHeight;
6648 INT width = This->cursorWidth;
6649 INT bpp = glDesc->byte_count;
6650 DWORD sampler;
6651 INT i;
6653 /* Reformat the texture memory (pitch and width can be
6654 * different) */
6655 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6656 for(i = 0; i < height; i++)
6657 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6658 IWineD3DSurface_UnlockRect(pCursorBitmap);
6660 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6662 ENTER_GL();
6664 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6665 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6666 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6669 /* Make sure that a proper texture unit is selected */
6670 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6671 checkGLcall("glActiveTextureARB");
6672 sampler = This->rev_tex_unit_map[0];
6673 if (sampler != WINED3D_UNMAPPED_STAGE)
6675 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6677 /* Create a new cursor texture */
6678 glGenTextures(1, &This->cursorTexture);
6679 checkGLcall("glGenTextures");
6680 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6681 checkGLcall("glBindTexture");
6682 /* Copy the bitmap memory into the cursor texture */
6683 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6684 HeapFree(GetProcessHeap(), 0, mem);
6685 checkGLcall("glTexImage2D");
6687 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6688 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6689 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6692 LEAVE_GL();
6694 else
6696 FIXME("A cursor texture was not returned.\n");
6697 This->cursorTexture = 0;
6700 else
6702 /* Draw a hardware cursor */
6703 ICONINFO cursorInfo;
6704 HCURSOR cursor;
6705 /* Create and clear maskBits because it is not needed for
6706 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6707 * chunks. */
6708 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6709 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6710 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6711 WINED3DLOCK_NO_DIRTY_UPDATE |
6712 WINED3DLOCK_READONLY
6714 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6715 pSur->currentDesc.Height);
6717 cursorInfo.fIcon = FALSE;
6718 cursorInfo.xHotspot = XHotSpot;
6719 cursorInfo.yHotspot = YHotSpot;
6720 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6721 pSur->currentDesc.Height, 1,
6722 1, &maskBits);
6723 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6724 pSur->currentDesc.Height, 1,
6725 32, lockedRect.pBits);
6726 IWineD3DSurface_UnlockRect(pCursorBitmap);
6727 /* Create our cursor and clean up. */
6728 cursor = CreateIconIndirect(&cursorInfo);
6729 SetCursor(cursor);
6730 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6731 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6732 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6733 This->hardwareCursor = cursor;
6734 HeapFree(GetProcessHeap(), 0, maskBits);
6738 This->xHotSpot = XHotSpot;
6739 This->yHotSpot = YHotSpot;
6740 return WINED3D_OK;
6743 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6745 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6747 This->xScreenSpace = XScreenSpace;
6748 This->yScreenSpace = YScreenSpace;
6750 return;
6754 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6756 BOOL oldVisible = This->bCursorVisible;
6757 POINT pt;
6759 TRACE("(%p) : visible(%d)\n", This, bShow);
6762 * When ShowCursor is first called it should make the cursor appear at the OS's last
6763 * known cursor position. Because of this, some applications just repetitively call
6764 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6766 GetCursorPos(&pt);
6767 This->xScreenSpace = pt.x;
6768 This->yScreenSpace = pt.y;
6770 if (This->haveHardwareCursor) {
6771 This->bCursorVisible = bShow;
6772 if (bShow)
6773 SetCursor(This->hardwareCursor);
6774 else
6775 SetCursor(NULL);
6777 else
6779 if (This->cursorTexture)
6780 This->bCursorVisible = bShow;
6783 return oldVisible;
6786 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6788 IWineD3DResourceImpl *resource;
6789 TRACE("(%p) : state (%u)\n", This, This->state);
6791 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6792 switch (This->state) {
6793 case WINED3D_OK:
6794 return WINED3D_OK;
6795 case WINED3DERR_DEVICELOST:
6797 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6798 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6799 return WINED3DERR_DEVICENOTRESET;
6801 return WINED3DERR_DEVICELOST;
6803 case WINED3DERR_DRIVERINTERNALERROR:
6804 return WINED3DERR_DRIVERINTERNALERROR;
6807 /* Unknown state */
6808 return WINED3DERR_DRIVERINTERNALERROR;
6811 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6812 TRACE("checking resource %p for eviction\n", resource);
6813 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6814 TRACE("Evicting %p\n", resource);
6815 IWineD3DResource_UnLoad(resource);
6817 IWineD3DResource_Release(resource);
6818 return S_OK;
6821 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6823 TRACE("(%p)\n", This);
6825 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6826 return WINED3D_OK;
6829 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6831 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6833 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6834 if(surface->Flags & SFLAG_DIBSECTION) {
6835 /* Release the DC */
6836 SelectObject(surface->hDC, surface->dib.holdbitmap);
6837 DeleteDC(surface->hDC);
6838 /* Release the DIB section */
6839 DeleteObject(surface->dib.DIBsection);
6840 surface->dib.bitmap_data = NULL;
6841 surface->resource.allocatedMemory = NULL;
6842 surface->Flags &= ~SFLAG_DIBSECTION;
6844 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6845 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6846 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6847 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6848 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6849 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6850 } else {
6851 surface->pow2Width = surface->pow2Height = 1;
6852 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6853 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6855 surface->glRect.left = 0;
6856 surface->glRect.top = 0;
6857 surface->glRect.right = surface->pow2Width;
6858 surface->glRect.bottom = surface->pow2Height;
6860 if (surface->texture_name)
6862 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6863 ENTER_GL();
6864 glDeleteTextures(1, &surface->texture_name);
6865 LEAVE_GL();
6866 surface->texture_name = 0;
6867 surface->Flags &= ~SFLAG_CLIENT;
6869 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6870 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6871 surface->Flags |= SFLAG_NONPOW2;
6872 } else {
6873 surface->Flags &= ~SFLAG_NONPOW2;
6875 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6876 surface->resource.allocatedMemory = NULL;
6877 surface->resource.heapMemory = NULL;
6878 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6879 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6880 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6881 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6882 } else {
6883 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6887 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6888 TRACE("Unloading resource %p\n", resource);
6889 IWineD3DResource_UnLoad(resource);
6890 IWineD3DResource_Release(resource);
6891 return S_OK;
6894 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6896 UINT i, count;
6897 WINED3DDISPLAYMODE m;
6898 HRESULT hr;
6900 /* All Windowed modes are supported, as is leaving the current mode */
6901 if(pp->Windowed) return TRUE;
6902 if(!pp->BackBufferWidth) return TRUE;
6903 if(!pp->BackBufferHeight) return TRUE;
6905 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6906 for(i = 0; i < count; i++) {
6907 memset(&m, 0, sizeof(m));
6908 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6909 if(FAILED(hr)) {
6910 ERR("EnumAdapterModes failed\n");
6912 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6913 /* Mode found, it is supported */
6914 return TRUE;
6917 /* Mode not found -> not supported */
6918 return FALSE;
6921 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6923 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6924 UINT i;
6925 IWineD3DBaseShaderImpl *shader;
6927 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6929 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6930 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6931 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6934 ENTER_GL();
6935 if(This->depth_blt_texture) {
6936 glDeleteTextures(1, &This->depth_blt_texture);
6937 This->depth_blt_texture = 0;
6939 if (This->depth_blt_rb) {
6940 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
6941 This->depth_blt_rb = 0;
6942 This->depth_blt_rb_w = 0;
6943 This->depth_blt_rb_h = 0;
6945 LEAVE_GL();
6947 This->blitter->free_private(iface);
6948 This->frag_pipe->free_private(iface);
6949 This->shader_backend->shader_free_private(iface);
6951 ENTER_GL();
6952 for (i = 0; i < GL_LIMITS(textures); i++) {
6953 /* Textures are recreated below */
6954 glDeleteTextures(1, &This->dummyTextureName[i]);
6955 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6956 This->dummyTextureName[i] = 0;
6958 LEAVE_GL();
6960 while(This->numContexts) {
6961 DestroyContext(This, This->contexts[0]);
6963 HeapFree(GetProcessHeap(), 0, swapchain->context);
6964 swapchain->context = NULL;
6965 swapchain->num_contexts = 0;
6968 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6970 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6971 HRESULT hr;
6972 IWineD3DSurfaceImpl *target;
6974 /* Recreate the primary swapchain's context */
6975 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6976 if(swapchain->backBuffer) {
6977 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6978 } else {
6979 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6981 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
6982 &swapchain->presentParms);
6983 swapchain->num_contexts = 1;
6985 create_dummy_textures(This);
6987 hr = This->shader_backend->shader_alloc_private(iface);
6988 if(FAILED(hr)) {
6989 ERR("Failed to recreate shader private data\n");
6990 goto err_out;
6992 hr = This->frag_pipe->alloc_private(iface);
6993 if(FAILED(hr)) {
6994 TRACE("Fragment pipeline private data couldn't be allocated\n");
6995 goto err_out;
6997 hr = This->blitter->alloc_private(iface);
6998 if(FAILED(hr)) {
6999 TRACE("Blitter private data couldn't be allocated\n");
7000 goto err_out;
7003 return WINED3D_OK;
7005 err_out:
7006 This->blitter->free_private(iface);
7007 This->frag_pipe->free_private(iface);
7008 This->shader_backend->shader_free_private(iface);
7009 return hr;
7012 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7014 IWineD3DSwapChainImpl *swapchain;
7015 HRESULT hr;
7016 BOOL DisplayModeChanged = FALSE;
7017 WINED3DDISPLAYMODE mode;
7018 TRACE("(%p)\n", This);
7020 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7021 if(FAILED(hr)) {
7022 ERR("Failed to get the first implicit swapchain\n");
7023 return hr;
7026 if(!is_display_mode_supported(This, pPresentationParameters)) {
7027 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7028 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7029 pPresentationParameters->BackBufferHeight);
7030 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7031 return WINED3DERR_INVALIDCALL;
7034 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7035 * on an existing gl context, so there's no real need for recreation.
7037 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7039 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7041 TRACE("New params:\n");
7042 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7043 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7044 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7045 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7046 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7047 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7048 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7049 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7050 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7051 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7052 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7053 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7054 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7056 /* No special treatment of these parameters. Just store them */
7057 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7058 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7059 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7060 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7062 /* What to do about these? */
7063 if(pPresentationParameters->BackBufferCount != 0 &&
7064 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7065 ERR("Cannot change the back buffer count yet\n");
7067 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7068 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7069 ERR("Cannot change the back buffer format yet\n");
7071 if(pPresentationParameters->hDeviceWindow != NULL &&
7072 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7073 ERR("Cannot change the device window yet\n");
7075 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7076 HRESULT hrc;
7078 TRACE("Creating the depth stencil buffer\n");
7080 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
7081 This->parent,
7082 pPresentationParameters->BackBufferWidth,
7083 pPresentationParameters->BackBufferHeight,
7084 pPresentationParameters->AutoDepthStencilFormat,
7085 pPresentationParameters->MultiSampleType,
7086 pPresentationParameters->MultiSampleQuality,
7087 FALSE,
7088 &This->auto_depth_stencil_buffer);
7090 if (FAILED(hrc)) {
7091 ERR("Failed to create the depth stencil buffer\n");
7092 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7093 return WINED3DERR_INVALIDCALL;
7097 /* Reset the depth stencil */
7098 if (pPresentationParameters->EnableAutoDepthStencil)
7099 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7100 else
7101 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7103 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7105 if(pPresentationParameters->Windowed) {
7106 mode.Width = swapchain->orig_width;
7107 mode.Height = swapchain->orig_height;
7108 mode.RefreshRate = 0;
7109 mode.Format = swapchain->presentParms.BackBufferFormat;
7110 } else {
7111 mode.Width = pPresentationParameters->BackBufferWidth;
7112 mode.Height = pPresentationParameters->BackBufferHeight;
7113 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7114 mode.Format = swapchain->presentParms.BackBufferFormat;
7117 /* Should Width == 800 && Height == 0 set 800x600? */
7118 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7119 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7120 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7122 UINT i;
7124 if(!pPresentationParameters->Windowed) {
7125 DisplayModeChanged = TRUE;
7127 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7128 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7130 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7131 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7132 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7134 if(This->auto_depth_stencil_buffer) {
7135 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7139 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7140 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7141 DisplayModeChanged) {
7143 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7145 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7146 if(swapchain->presentParms.Windowed) {
7147 /* switch from windowed to fs */
7148 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7149 pPresentationParameters->BackBufferWidth,
7150 pPresentationParameters->BackBufferHeight);
7151 } else {
7152 /* Fullscreen -> fullscreen mode change */
7153 MoveWindow(swapchain->win_handle, 0, 0,
7154 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7155 TRUE);
7157 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7158 /* Fullscreen -> windowed switch */
7159 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7161 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7162 } else if(!pPresentationParameters->Windowed) {
7163 DWORD style = This->style, exStyle = This->exStyle;
7164 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7165 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7166 * Reset to clear up their mess. Guild Wars also loses the device during that.
7168 This->style = 0;
7169 This->exStyle = 0;
7170 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7171 pPresentationParameters->BackBufferWidth,
7172 pPresentationParameters->BackBufferHeight);
7173 This->style = style;
7174 This->exStyle = exStyle;
7177 TRACE("Resetting stateblock\n");
7178 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7179 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7181 /* Note: No parent needed for initial internal stateblock */
7182 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7183 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7184 else TRACE("Created stateblock %p\n", This->stateBlock);
7185 This->updateStateBlock = This->stateBlock;
7186 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7188 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7189 if(FAILED(hr)) {
7190 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7193 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7194 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7196 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7197 * first use
7199 return hr;
7202 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7204 /** FIXME: always true at the moment **/
7205 if(!bEnableDialogs) {
7206 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7208 return WINED3D_OK;
7212 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7214 TRACE("(%p) : pParameters %p\n", This, pParameters);
7216 *pParameters = This->createParms;
7217 return WINED3D_OK;
7220 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7221 IWineD3DSwapChain *swapchain;
7223 TRACE("Relaying to swapchain\n");
7225 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7226 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7227 IWineD3DSwapChain_Release(swapchain);
7229 return;
7232 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7233 IWineD3DSwapChain *swapchain;
7235 TRACE("Relaying to swapchain\n");
7237 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7238 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7239 IWineD3DSwapChain_Release(swapchain);
7241 return;
7245 /** ********************************************************
7246 * Notification functions
7247 ** ********************************************************/
7248 /** This function must be called in the release of a resource when ref == 0,
7249 * the contents of resource must still be correct,
7250 * any handles to other resource held by the caller must be closed
7251 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7252 *****************************************************/
7253 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7255 TRACE("(%p) : Adding resource %p\n", This, resource);
7257 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7260 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7262 TRACE("(%p) : Removing resource %p\n", This, resource);
7264 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7267 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7269 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7270 int counter;
7272 TRACE("(%p) : resource %p\n", This, resource);
7274 context_resource_released((IWineD3DDevice *)This, resource, type);
7276 switch (type) {
7277 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7278 case WINED3DRTYPE_SURFACE: {
7279 unsigned int i;
7281 if (This->d3d_initialized)
7283 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7284 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7285 This->render_targets[i] = NULL;
7288 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7289 This->stencilBufferTarget = NULL;
7293 break;
7295 case WINED3DRTYPE_TEXTURE:
7296 case WINED3DRTYPE_CUBETEXTURE:
7297 case WINED3DRTYPE_VOLUMETEXTURE:
7298 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7299 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7300 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7301 This->stateBlock->textures[counter] = NULL;
7303 if (This->updateStateBlock != This->stateBlock ){
7304 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7305 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7306 This->updateStateBlock->textures[counter] = NULL;
7310 break;
7311 case WINED3DRTYPE_VOLUME:
7312 /* TODO: nothing really? */
7313 break;
7314 case WINED3DRTYPE_BUFFER:
7316 int streamNumber;
7317 TRACE("Cleaning up stream pointers\n");
7319 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7320 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7321 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7323 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7324 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7325 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7326 This->updateStateBlock->streamSource[streamNumber] = 0;
7327 /* Set changed flag? */
7330 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) */
7331 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7332 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7333 This->stateBlock->streamSource[streamNumber] = 0;
7338 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7339 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7340 This->updateStateBlock->pIndexData = NULL;
7343 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7344 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7345 This->stateBlock->pIndexData = NULL;
7349 break;
7351 default:
7352 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7353 break;
7357 /* Remove the resource from the resourceStore */
7358 device_resource_remove(This, resource);
7360 TRACE("Resource released\n");
7364 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7366 IWineD3DResourceImpl *resource, *cursor;
7367 HRESULT ret;
7368 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7370 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7371 TRACE("enumerating resource %p\n", resource);
7372 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7373 ret = pCallback((IWineD3DResource *) resource, pData);
7374 if(ret == S_FALSE) {
7375 TRACE("Canceling enumeration\n");
7376 break;
7379 return WINED3D_OK;
7382 /**********************************************************
7383 * IWineD3DDevice VTbl follows
7384 **********************************************************/
7386 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7388 /*** IUnknown methods ***/
7389 IWineD3DDeviceImpl_QueryInterface,
7390 IWineD3DDeviceImpl_AddRef,
7391 IWineD3DDeviceImpl_Release,
7392 /*** IWineD3DDevice methods ***/
7393 IWineD3DDeviceImpl_GetParent,
7394 /*** Creation methods**/
7395 IWineD3DDeviceImpl_CreateBuffer,
7396 IWineD3DDeviceImpl_CreateVertexBuffer,
7397 IWineD3DDeviceImpl_CreateIndexBuffer,
7398 IWineD3DDeviceImpl_CreateStateBlock,
7399 IWineD3DDeviceImpl_CreateSurface,
7400 IWineD3DDeviceImpl_CreateRendertargetView,
7401 IWineD3DDeviceImpl_CreateTexture,
7402 IWineD3DDeviceImpl_CreateVolumeTexture,
7403 IWineD3DDeviceImpl_CreateVolume,
7404 IWineD3DDeviceImpl_CreateCubeTexture,
7405 IWineD3DDeviceImpl_CreateQuery,
7406 IWineD3DDeviceImpl_CreateSwapChain,
7407 IWineD3DDeviceImpl_CreateVertexDeclaration,
7408 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7409 IWineD3DDeviceImpl_CreateVertexShader,
7410 IWineD3DDeviceImpl_CreatePixelShader,
7411 IWineD3DDeviceImpl_CreatePalette,
7412 /*** Odd functions **/
7413 IWineD3DDeviceImpl_Init3D,
7414 IWineD3DDeviceImpl_InitGDI,
7415 IWineD3DDeviceImpl_Uninit3D,
7416 IWineD3DDeviceImpl_UninitGDI,
7417 IWineD3DDeviceImpl_SetMultithreaded,
7418 IWineD3DDeviceImpl_EvictManagedResources,
7419 IWineD3DDeviceImpl_GetAvailableTextureMem,
7420 IWineD3DDeviceImpl_GetBackBuffer,
7421 IWineD3DDeviceImpl_GetCreationParameters,
7422 IWineD3DDeviceImpl_GetDeviceCaps,
7423 IWineD3DDeviceImpl_GetDirect3D,
7424 IWineD3DDeviceImpl_GetDisplayMode,
7425 IWineD3DDeviceImpl_SetDisplayMode,
7426 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7427 IWineD3DDeviceImpl_GetRasterStatus,
7428 IWineD3DDeviceImpl_GetSwapChain,
7429 IWineD3DDeviceImpl_Reset,
7430 IWineD3DDeviceImpl_SetDialogBoxMode,
7431 IWineD3DDeviceImpl_SetCursorProperties,
7432 IWineD3DDeviceImpl_SetCursorPosition,
7433 IWineD3DDeviceImpl_ShowCursor,
7434 IWineD3DDeviceImpl_TestCooperativeLevel,
7435 /*** Getters and setters **/
7436 IWineD3DDeviceImpl_SetClipPlane,
7437 IWineD3DDeviceImpl_GetClipPlane,
7438 IWineD3DDeviceImpl_SetClipStatus,
7439 IWineD3DDeviceImpl_GetClipStatus,
7440 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7441 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7442 IWineD3DDeviceImpl_SetDepthStencilSurface,
7443 IWineD3DDeviceImpl_GetDepthStencilSurface,
7444 IWineD3DDeviceImpl_SetGammaRamp,
7445 IWineD3DDeviceImpl_GetGammaRamp,
7446 IWineD3DDeviceImpl_SetIndices,
7447 IWineD3DDeviceImpl_GetIndices,
7448 IWineD3DDeviceImpl_SetBaseVertexIndex,
7449 IWineD3DDeviceImpl_GetBaseVertexIndex,
7450 IWineD3DDeviceImpl_SetLight,
7451 IWineD3DDeviceImpl_GetLight,
7452 IWineD3DDeviceImpl_SetLightEnable,
7453 IWineD3DDeviceImpl_GetLightEnable,
7454 IWineD3DDeviceImpl_SetMaterial,
7455 IWineD3DDeviceImpl_GetMaterial,
7456 IWineD3DDeviceImpl_SetNPatchMode,
7457 IWineD3DDeviceImpl_GetNPatchMode,
7458 IWineD3DDeviceImpl_SetPaletteEntries,
7459 IWineD3DDeviceImpl_GetPaletteEntries,
7460 IWineD3DDeviceImpl_SetPixelShader,
7461 IWineD3DDeviceImpl_GetPixelShader,
7462 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7463 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7464 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7465 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7466 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7467 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7468 IWineD3DDeviceImpl_SetRenderState,
7469 IWineD3DDeviceImpl_GetRenderState,
7470 IWineD3DDeviceImpl_SetRenderTarget,
7471 IWineD3DDeviceImpl_GetRenderTarget,
7472 IWineD3DDeviceImpl_SetFrontBackBuffers,
7473 IWineD3DDeviceImpl_SetSamplerState,
7474 IWineD3DDeviceImpl_GetSamplerState,
7475 IWineD3DDeviceImpl_SetScissorRect,
7476 IWineD3DDeviceImpl_GetScissorRect,
7477 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7478 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7479 IWineD3DDeviceImpl_SetStreamSource,
7480 IWineD3DDeviceImpl_GetStreamSource,
7481 IWineD3DDeviceImpl_SetStreamSourceFreq,
7482 IWineD3DDeviceImpl_GetStreamSourceFreq,
7483 IWineD3DDeviceImpl_SetTexture,
7484 IWineD3DDeviceImpl_GetTexture,
7485 IWineD3DDeviceImpl_SetTextureStageState,
7486 IWineD3DDeviceImpl_GetTextureStageState,
7487 IWineD3DDeviceImpl_SetTransform,
7488 IWineD3DDeviceImpl_GetTransform,
7489 IWineD3DDeviceImpl_SetVertexDeclaration,
7490 IWineD3DDeviceImpl_GetVertexDeclaration,
7491 IWineD3DDeviceImpl_SetVertexShader,
7492 IWineD3DDeviceImpl_GetVertexShader,
7493 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7494 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7495 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7496 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7497 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7498 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7499 IWineD3DDeviceImpl_SetViewport,
7500 IWineD3DDeviceImpl_GetViewport,
7501 IWineD3DDeviceImpl_MultiplyTransform,
7502 IWineD3DDeviceImpl_ValidateDevice,
7503 IWineD3DDeviceImpl_ProcessVertices,
7504 /*** State block ***/
7505 IWineD3DDeviceImpl_BeginStateBlock,
7506 IWineD3DDeviceImpl_EndStateBlock,
7507 /*** Scene management ***/
7508 IWineD3DDeviceImpl_BeginScene,
7509 IWineD3DDeviceImpl_EndScene,
7510 IWineD3DDeviceImpl_Present,
7511 IWineD3DDeviceImpl_Clear,
7512 IWineD3DDeviceImpl_ClearRendertargetView,
7513 /*** Drawing ***/
7514 IWineD3DDeviceImpl_SetPrimitiveType,
7515 IWineD3DDeviceImpl_GetPrimitiveType,
7516 IWineD3DDeviceImpl_DrawPrimitive,
7517 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7518 IWineD3DDeviceImpl_DrawPrimitiveUP,
7519 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7520 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7521 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7522 IWineD3DDeviceImpl_DrawRectPatch,
7523 IWineD3DDeviceImpl_DrawTriPatch,
7524 IWineD3DDeviceImpl_DeletePatch,
7525 IWineD3DDeviceImpl_ColorFill,
7526 IWineD3DDeviceImpl_UpdateTexture,
7527 IWineD3DDeviceImpl_UpdateSurface,
7528 IWineD3DDeviceImpl_GetFrontBufferData,
7529 /*** object tracking ***/
7530 IWineD3DDeviceImpl_EnumResources
7533 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7534 WINED3DRS_ALPHABLENDENABLE ,
7535 WINED3DRS_ALPHAFUNC ,
7536 WINED3DRS_ALPHAREF ,
7537 WINED3DRS_ALPHATESTENABLE ,
7538 WINED3DRS_BLENDOP ,
7539 WINED3DRS_COLORWRITEENABLE ,
7540 WINED3DRS_DESTBLEND ,
7541 WINED3DRS_DITHERENABLE ,
7542 WINED3DRS_FILLMODE ,
7543 WINED3DRS_FOGDENSITY ,
7544 WINED3DRS_FOGEND ,
7545 WINED3DRS_FOGSTART ,
7546 WINED3DRS_LASTPIXEL ,
7547 WINED3DRS_SHADEMODE ,
7548 WINED3DRS_SRCBLEND ,
7549 WINED3DRS_STENCILENABLE ,
7550 WINED3DRS_STENCILFAIL ,
7551 WINED3DRS_STENCILFUNC ,
7552 WINED3DRS_STENCILMASK ,
7553 WINED3DRS_STENCILPASS ,
7554 WINED3DRS_STENCILREF ,
7555 WINED3DRS_STENCILWRITEMASK ,
7556 WINED3DRS_STENCILZFAIL ,
7557 WINED3DRS_TEXTUREFACTOR ,
7558 WINED3DRS_WRAP0 ,
7559 WINED3DRS_WRAP1 ,
7560 WINED3DRS_WRAP2 ,
7561 WINED3DRS_WRAP3 ,
7562 WINED3DRS_WRAP4 ,
7563 WINED3DRS_WRAP5 ,
7564 WINED3DRS_WRAP6 ,
7565 WINED3DRS_WRAP7 ,
7566 WINED3DRS_ZENABLE ,
7567 WINED3DRS_ZFUNC ,
7568 WINED3DRS_ZWRITEENABLE
7571 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7572 WINED3DTSS_ALPHAARG0 ,
7573 WINED3DTSS_ALPHAARG1 ,
7574 WINED3DTSS_ALPHAARG2 ,
7575 WINED3DTSS_ALPHAOP ,
7576 WINED3DTSS_BUMPENVLOFFSET ,
7577 WINED3DTSS_BUMPENVLSCALE ,
7578 WINED3DTSS_BUMPENVMAT00 ,
7579 WINED3DTSS_BUMPENVMAT01 ,
7580 WINED3DTSS_BUMPENVMAT10 ,
7581 WINED3DTSS_BUMPENVMAT11 ,
7582 WINED3DTSS_COLORARG0 ,
7583 WINED3DTSS_COLORARG1 ,
7584 WINED3DTSS_COLORARG2 ,
7585 WINED3DTSS_COLOROP ,
7586 WINED3DTSS_RESULTARG ,
7587 WINED3DTSS_TEXCOORDINDEX ,
7588 WINED3DTSS_TEXTURETRANSFORMFLAGS
7591 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7592 WINED3DSAMP_ADDRESSU ,
7593 WINED3DSAMP_ADDRESSV ,
7594 WINED3DSAMP_ADDRESSW ,
7595 WINED3DSAMP_BORDERCOLOR ,
7596 WINED3DSAMP_MAGFILTER ,
7597 WINED3DSAMP_MINFILTER ,
7598 WINED3DSAMP_MIPFILTER ,
7599 WINED3DSAMP_MIPMAPLODBIAS ,
7600 WINED3DSAMP_MAXMIPLEVEL ,
7601 WINED3DSAMP_MAXANISOTROPY ,
7602 WINED3DSAMP_SRGBTEXTURE ,
7603 WINED3DSAMP_ELEMENTINDEX
7606 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7607 WINED3DRS_AMBIENT ,
7608 WINED3DRS_AMBIENTMATERIALSOURCE ,
7609 WINED3DRS_CLIPPING ,
7610 WINED3DRS_CLIPPLANEENABLE ,
7611 WINED3DRS_COLORVERTEX ,
7612 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7613 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7614 WINED3DRS_FOGDENSITY ,
7615 WINED3DRS_FOGEND ,
7616 WINED3DRS_FOGSTART ,
7617 WINED3DRS_FOGTABLEMODE ,
7618 WINED3DRS_FOGVERTEXMODE ,
7619 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7620 WINED3DRS_LIGHTING ,
7621 WINED3DRS_LOCALVIEWER ,
7622 WINED3DRS_MULTISAMPLEANTIALIAS ,
7623 WINED3DRS_MULTISAMPLEMASK ,
7624 WINED3DRS_NORMALIZENORMALS ,
7625 WINED3DRS_PATCHEDGESTYLE ,
7626 WINED3DRS_POINTSCALE_A ,
7627 WINED3DRS_POINTSCALE_B ,
7628 WINED3DRS_POINTSCALE_C ,
7629 WINED3DRS_POINTSCALEENABLE ,
7630 WINED3DRS_POINTSIZE ,
7631 WINED3DRS_POINTSIZE_MAX ,
7632 WINED3DRS_POINTSIZE_MIN ,
7633 WINED3DRS_POINTSPRITEENABLE ,
7634 WINED3DRS_RANGEFOGENABLE ,
7635 WINED3DRS_SPECULARMATERIALSOURCE ,
7636 WINED3DRS_TWEENFACTOR ,
7637 WINED3DRS_VERTEXBLEND ,
7638 WINED3DRS_CULLMODE ,
7639 WINED3DRS_FOGCOLOR
7642 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7643 WINED3DTSS_TEXCOORDINDEX ,
7644 WINED3DTSS_TEXTURETRANSFORMFLAGS
7647 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7648 WINED3DSAMP_DMAPOFFSET
7651 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7652 DWORD rep = This->StateTable[state].representative;
7653 struct wined3d_context *context;
7654 DWORD idx;
7655 BYTE shift;
7656 UINT i;
7658 for(i = 0; i < This->numContexts; i++) {
7659 context = This->contexts[i];
7660 if(isStateDirty(context, rep)) continue;
7662 context->dirtyArray[context->numDirtyEntries++] = rep;
7663 idx = rep >> 5;
7664 shift = rep & 0x1f;
7665 context->isStateDirty[idx] |= (1 << shift);
7669 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7671 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.wineD3DDevice;
7672 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7673 *width = device->pbufferWidth;
7674 *height = device->pbufferHeight;
7677 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7679 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7680 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7681 *width = surface->pow2Width;
7682 *height = surface->pow2Height;
7685 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7687 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7688 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7689 * current context's drawable, which is the size of the back buffer of the swapchain
7690 * the active context belongs to. The back buffer of the swapchain is stored as the
7691 * surface the context belongs to. */
7692 *width = surface->currentDesc.Width;
7693 *height = surface->currentDesc.Height;