push 87b6981010d7405c33b14cddcceec21b47729eba
[wine/hacks.git] / dlls / wined3d / device.c
blobf10348c1b18647e3388f34766426af2c45f07cf0
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "config.h"
30 #include <stdio.h>
31 #ifdef HAVE_FLOAT_H
32 # include <float.h>
33 #endif
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
37 #define GLINFO_LOCATION This->adapter->gl_info
39 /* Define the default light parameters as specified by MSDN */
40 const WINED3DLIGHT WINED3D_default_light = {
42 WINED3DLIGHT_DIRECTIONAL, /* Type */
43 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
45 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
46 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
47 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
48 0.0f, /* Range */
49 0.0f, /* Falloff */
50 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
51 0.0f, /* Theta */
52 0.0f /* Phi */
55 /**********************************************************
56 * Global variable / Constants follow
57 **********************************************************/
58 const float identity[] =
60 1.0f, 0.0f, 0.0f, 0.0f,
61 0.0f, 1.0f, 0.0f, 0.0f,
62 0.0f, 0.0f, 1.0f, 0.0f,
63 0.0f, 0.0f, 0.0f, 1.0f,
64 }; /* When needed for comparisons */
66 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
67 * actually have the same values in GL and D3D. */
68 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
70 switch(primitive_type)
72 case WINED3DPT_POINTLIST:
73 return GL_POINTS;
75 case WINED3DPT_LINELIST:
76 return GL_LINES;
78 case WINED3DPT_LINESTRIP:
79 return GL_LINE_STRIP;
81 case WINED3DPT_TRIANGLELIST:
82 return GL_TRIANGLES;
84 case WINED3DPT_TRIANGLESTRIP:
85 return GL_TRIANGLE_STRIP;
87 case WINED3DPT_TRIANGLEFAN:
88 return GL_TRIANGLE_FAN;
90 case WINED3DPT_LINELIST_ADJ:
91 return GL_LINES_ADJACENCY_ARB;
93 case WINED3DPT_LINESTRIP_ADJ:
94 return GL_LINE_STRIP_ADJACENCY_ARB;
96 case WINED3DPT_TRIANGLELIST_ADJ:
97 return GL_TRIANGLES_ADJACENCY_ARB;
99 case WINED3DPT_TRIANGLESTRIP_ADJ:
100 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
102 default:
103 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
104 return GL_NONE;
108 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
110 switch(primitive_type)
112 case GL_POINTS:
113 return WINED3DPT_POINTLIST;
115 case GL_LINES:
116 return WINED3DPT_LINELIST;
118 case GL_LINE_STRIP:
119 return WINED3DPT_LINESTRIP;
121 case GL_TRIANGLES:
122 return WINED3DPT_TRIANGLELIST;
124 case GL_TRIANGLE_STRIP:
125 return WINED3DPT_TRIANGLESTRIP;
127 case GL_TRIANGLE_FAN:
128 return WINED3DPT_TRIANGLEFAN;
130 case GL_LINES_ADJACENCY_ARB:
131 return WINED3DPT_LINELIST_ADJ;
133 case GL_LINE_STRIP_ADJACENCY_ARB:
134 return WINED3DPT_LINESTRIP_ADJ;
136 case GL_TRIANGLES_ADJACENCY_ARB:
137 return WINED3DPT_TRIANGLELIST_ADJ;
139 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
140 return WINED3DPT_TRIANGLESTRIP_ADJ;
142 default:
143 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
144 return WINED3DPT_UNDEFINED;
148 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
150 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
151 *regnum = WINED3D_FFP_POSITION;
152 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
153 *regnum = WINED3D_FFP_BLENDWEIGHT;
154 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
155 *regnum = WINED3D_FFP_BLENDINDICES;
156 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
157 *regnum = WINED3D_FFP_NORMAL;
158 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
159 *regnum = WINED3D_FFP_PSIZE;
160 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
161 *regnum = WINED3D_FFP_DIFFUSE;
162 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
163 *regnum = WINED3D_FFP_SPECULAR;
164 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
165 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
166 else
168 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
169 *regnum = ~0U;
170 return FALSE;
173 return TRUE;
176 /* Context activation is done by the caller. */
177 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
178 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
180 /* We need to deal with frequency data! */
181 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
182 UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
183 const DWORD *streams = declaration->streams;
184 unsigned int i;
186 stream_info->use_map = 0;
187 stream_info->swizzle_map = 0;
189 /* Check for transformed vertices, disable vertex shader if present. */
190 stream_info->position_transformed = declaration->position_transformed;
191 if (declaration->position_transformed) use_vshader = FALSE;
193 /* Translate the declaration into strided data. */
194 for (i = 0; i < declaration->element_count; ++i)
196 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
197 GLuint buffer_object = 0;
198 const BYTE *data = NULL;
199 BOOL stride_used;
200 unsigned int idx;
201 DWORD stride;
203 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
204 element, i + 1, declaration->element_count);
206 if (!This->stateBlock->streamSource[element->input_slot]) continue;
208 stride = This->stateBlock->streamStride[element->input_slot];
209 if (This->stateBlock->streamIsUP)
211 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
212 buffer_object = 0;
213 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
215 else
217 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
218 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
220 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
221 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
222 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
223 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
224 * not, drawStridedSlow is needed, including a vertex buffer path. */
225 if (This->stateBlock->loadBaseVertexIndex < 0)
227 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
228 buffer_object = 0;
229 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
230 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
232 FIXME("System memory vertex data load offset is negative!\n");
236 if (fixup)
238 if (buffer_object) *fixup = TRUE;
239 else if (*fixup && !use_vshader
240 && (element->usage == WINED3DDECLUSAGE_COLOR
241 || element->usage == WINED3DDECLUSAGE_POSITIONT))
243 static BOOL warned = FALSE;
244 if (!warned)
246 /* This may be bad with the fixed function pipeline. */
247 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
248 warned = TRUE;
253 data += element->offset;
255 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
257 if (use_vshader)
259 if (element->output_slot == ~0U)
261 /* TODO: Assuming vertexdeclarations are usually used with the
262 * same or a similar shader, it might be worth it to store the
263 * last used output slot and try that one first. */
264 stride_used = vshader_get_input(This->stateBlock->vertexShader,
265 element->usage, element->usage_idx, &idx);
267 else
269 idx = element->output_slot;
270 stride_used = TRUE;
273 else
275 if (!element->ffp_valid)
277 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
278 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
279 stride_used = FALSE;
281 else
283 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
287 if (stride_used)
289 TRACE("Load %s array %u [usage %s, usage_idx %u, "
290 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
291 use_vshader ? "shader": "fixed function", idx,
292 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
293 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
295 stream_info->elements[idx].format_desc = element->format_desc;
296 stream_info->elements[idx].stride = stride;
297 stream_info->elements[idx].data = data;
298 stream_info->elements[idx].stream_idx = element->input_slot;
299 stream_info->elements[idx].buffer_object = buffer_object;
301 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
302 && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
304 stream_info->swizzle_map |= 1 << idx;
306 stream_info->use_map |= 1 << idx;
310 /* Now call PreLoad on all the vertex buffers. In the very rare case
311 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
312 * The vertex buffer can now use the strided structure in the device instead of finding its
313 * own again.
315 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
316 * once in there. */
317 for (i = 0; i < stream_count; ++i)
319 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
320 if (vb) IWineD3DBuffer_PreLoad(vb);
324 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
325 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
327 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, gl_info);
328 e->format_desc = format_desc;
329 e->stride = strided->dwStride;
330 e->data = strided->lpData;
331 e->stream_idx = 0;
332 e->buffer_object = 0;
335 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
336 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
338 unsigned int i;
340 memset(stream_info, 0, sizeof(*stream_info));
342 if (strided->position.lpData)
343 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
344 if (strided->normal.lpData)
345 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
346 if (strided->diffuse.lpData)
347 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
348 if (strided->specular.lpData)
349 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
351 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
353 if (strided->texCoords[i].lpData)
354 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
355 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
358 stream_info->position_transformed = strided->position_transformed;
360 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
362 if (!stream_info->elements[i].format_desc) continue;
364 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
365 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
367 stream_info->swizzle_map |= 1 << i;
369 stream_info->use_map |= 1 << i;
373 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
375 TRACE("Strided Data:\n");
376 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
377 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
378 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
379 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
380 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
381 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
382 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
383 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
384 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
385 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
386 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
387 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
388 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
389 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
390 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
393 /* Context activation is done by the caller. */
394 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
396 struct wined3d_stream_info *stream_info = &device->strided_streams;
397 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
398 BOOL vs = stateblock->vertexShader && device->vs_selected_mode != SHADER_NONE;
399 BOOL fixup = FALSE;
401 if (device->up_strided)
403 /* Note: this is a ddraw fixed-function code path. */
404 TRACE("=============================== Strided Input ================================\n");
405 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
406 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
408 else
410 TRACE("============================= Vertex Declaration =============================\n");
411 device_stream_info_from_declaration(device, vs, stream_info, &fixup);
414 if (vs && !stream_info->position_transformed)
416 if (((IWineD3DVertexDeclarationImpl *)stateblock->vertexDecl)->half_float_conv_needed && !fixup)
418 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
419 device->useDrawStridedSlow = TRUE;
421 else
423 device->useDrawStridedSlow = FALSE;
426 else
428 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
429 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
430 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
432 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
434 device->useDrawStridedSlow = TRUE;
436 else
438 device->useDrawStridedSlow = FALSE;
443 static void device_preload_texture(IWineD3DStateBlockImpl *stateblock, unsigned int idx)
445 IWineD3DBaseTextureImpl *texture;
446 enum WINED3DSRGB srgb;
448 if (!(texture = (IWineD3DBaseTextureImpl *)stateblock->textures[idx])) return;
449 srgb = stateblock->samplerState[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
450 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
453 void device_preload_textures(IWineD3DDeviceImpl *device)
455 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
456 unsigned int i;
458 if (use_vs(stateblock))
460 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
462 if (((IWineD3DBaseShaderImpl *)stateblock->vertexShader)->baseShader.reg_maps.sampler_type[i])
463 device_preload_texture(stateblock, MAX_FRAGMENT_SAMPLERS + i);
467 if (use_ps(stateblock))
469 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
471 if (((IWineD3DBaseShaderImpl *)stateblock->pixelShader)->baseShader.reg_maps.sampler_type[i])
472 device_preload_texture(stateblock, i);
475 else
477 WORD ffu_map = device->fixed_function_usage_map;
479 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
481 if (ffu_map & 1)
482 device_preload_texture(stateblock, i);
487 /**********************************************************
488 * IUnknown parts follows
489 **********************************************************/
491 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
495 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
496 if (IsEqualGUID(riid, &IID_IUnknown)
497 || IsEqualGUID(riid, &IID_IWineD3DBase)
498 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
499 IUnknown_AddRef(iface);
500 *ppobj = This;
501 return S_OK;
503 *ppobj = NULL;
504 return E_NOINTERFACE;
507 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
509 ULONG refCount = InterlockedIncrement(&This->ref);
511 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
512 return refCount;
515 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
517 ULONG refCount = InterlockedDecrement(&This->ref);
519 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
521 if (!refCount) {
522 UINT i;
524 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
525 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
526 This->multistate_funcs[i] = NULL;
529 /* TODO: Clean up all the surfaces and textures! */
530 /* NOTE: You must release the parent if the object was created via a callback
531 ** ***************************/
533 if (!list_empty(&This->resources)) {
534 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
535 dumpResources(&This->resources);
538 if(This->contexts) ERR("Context array not freed!\n");
539 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
540 This->haveHardwareCursor = FALSE;
542 IWineD3D_Release(This->wined3d);
543 This->wined3d = NULL;
544 HeapFree(GetProcessHeap(), 0, This);
545 TRACE("Freed device %p\n", This);
546 This = NULL;
548 return refCount;
551 /**********************************************************
552 * IWineD3DDevice implementation follows
553 **********************************************************/
554 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
555 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
556 *pParent = This->parent;
557 IUnknown_AddRef(This->parent);
558 return WINED3D_OK;
561 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
562 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
565 struct wined3d_buffer *object;
566 HRESULT hr;
568 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
570 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
571 if (!object)
573 ERR("Failed to allocate memory\n");
574 return E_OUTOFMEMORY;
577 FIXME("Ignoring access flags (pool)\n");
579 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
580 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
581 if (FAILED(hr))
583 WARN("Failed to initialize buffer, hr %#x.\n", hr);
584 HeapFree(GetProcessHeap(), 0, object);
585 return hr;
587 object->desc = *desc;
589 TRACE("Created buffer %p.\n", object);
591 *buffer = (IWineD3DBuffer *)object;
593 return WINED3D_OK;
596 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
597 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
598 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
601 struct wined3d_buffer *object;
602 HRESULT hr;
604 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
605 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
607 if (Pool == WINED3DPOOL_SCRATCH)
609 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
610 * anyway, SCRATCH vertex buffers aren't usable anywhere
612 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
613 *ppVertexBuffer = NULL;
614 return WINED3DERR_INVALIDCALL;
617 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
618 if (!object)
620 ERR("Out of memory\n");
621 *ppVertexBuffer = NULL;
622 return WINED3DERR_OUTOFVIDEOMEMORY;
625 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
626 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
627 if (FAILED(hr))
629 WARN("Failed to initialize buffer, hr %#x.\n", hr);
630 HeapFree(GetProcessHeap(), 0, object);
631 return hr;
634 TRACE("Created buffer %p.\n", object);
635 *ppVertexBuffer = (IWineD3DBuffer *)object;
637 return WINED3D_OK;
640 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
641 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
642 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
645 struct wined3d_buffer *object;
646 HRESULT hr;
648 TRACE("(%p) Creating index buffer\n", This);
650 /* Allocate the storage for the device */
651 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
652 if (!object)
654 ERR("Out of memory\n");
655 *ppIndexBuffer = NULL;
656 return WINED3DERR_OUTOFVIDEOMEMORY;
659 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
660 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
661 parent, parent_ops);
662 if (FAILED(hr))
664 WARN("Failed to initialize buffer, hr %#x\n", hr);
665 HeapFree(GetProcessHeap(), 0, object);
666 return hr;
669 TRACE("Created buffer %p.\n", object);
671 *ppIndexBuffer = (IWineD3DBuffer *) object;
673 return WINED3D_OK;
676 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
677 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
680 IWineD3DStateBlockImpl *object;
681 HRESULT hr;
683 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
684 if(!object)
686 ERR("Failed to allocate stateblock memory.\n");
687 return E_OUTOFMEMORY;
690 hr = stateblock_init(object, This, type);
691 if (FAILED(hr))
693 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
694 HeapFree(GetProcessHeap(), 0, object);
695 return hr;
698 TRACE("Created stateblock %p.\n", object);
699 *stateblock = (IWineD3DStateBlock *)object;
701 return WINED3D_OK;
704 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
705 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
706 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
707 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
710 IWineD3DSurfaceImpl *object;
711 HRESULT hr;
713 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
714 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
715 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
716 ppSurface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
717 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
719 if (Impl == SURFACE_OPENGL && !This->adapter)
721 ERR("OpenGL surfaces are not available without OpenGL.\n");
722 return WINED3DERR_NOTAVAILABLE;
725 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
726 if (!object)
728 ERR("Failed to allocate surface memory.\n");
729 return WINED3DERR_OUTOFVIDEOMEMORY;
732 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
733 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
734 if (FAILED(hr))
736 WARN("Failed to initialize surface, returning %#x.\n", hr);
737 HeapFree(GetProcessHeap(), 0, object);
738 return hr;
741 TRACE("(%p) : Created surface %p\n", This, object);
743 *ppSurface = (IWineD3DSurface *)object;
745 return hr;
748 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
749 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
751 struct wined3d_rendertarget_view *object;
753 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
754 if (!object)
756 ERR("Failed to allocate memory\n");
757 return E_OUTOFMEMORY;
760 object->vtbl = &wined3d_rendertarget_view_vtbl;
761 object->refcount = 1;
762 IWineD3DResource_AddRef(resource);
763 object->resource = resource;
764 object->parent = parent;
766 *rendertarget_view = (IWineD3DRendertargetView *)object;
768 return WINED3D_OK;
771 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
772 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
773 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
776 IWineD3DTextureImpl *object;
777 HRESULT hr;
779 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
780 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
781 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
783 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
784 if (!object)
786 ERR("Out of memory\n");
787 *ppTexture = NULL;
788 return WINED3DERR_OUTOFVIDEOMEMORY;
791 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
792 if (FAILED(hr))
794 WARN("Failed to initialize texture, returning %#x\n", hr);
795 HeapFree(GetProcessHeap(), 0, object);
796 *ppTexture = NULL;
797 return hr;
800 *ppTexture = (IWineD3DTexture *)object;
802 TRACE("(%p) : Created texture %p\n", This, object);
804 return WINED3D_OK;
807 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
808 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
809 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
812 IWineD3DVolumeTextureImpl *object;
813 HRESULT hr;
815 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
816 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
818 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
819 if (!object)
821 ERR("Out of memory\n");
822 *ppVolumeTexture = NULL;
823 return WINED3DERR_OUTOFVIDEOMEMORY;
826 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
827 if (FAILED(hr))
829 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
830 HeapFree(GetProcessHeap(), 0, object);
831 *ppVolumeTexture = NULL;
832 return hr;
835 TRACE("(%p) : Created volume texture %p.\n", This, object);
836 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
838 return WINED3D_OK;
841 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
842 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
843 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
846 IWineD3DVolumeImpl *object;
847 HRESULT hr;
849 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
850 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
852 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
853 if (!object)
855 ERR("Out of memory\n");
856 *ppVolume = NULL;
857 return WINED3DERR_OUTOFVIDEOMEMORY;
860 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
861 if (FAILED(hr))
863 WARN("Failed to initialize volume, returning %#x.\n", hr);
864 HeapFree(GetProcessHeap(), 0, object);
865 return hr;
868 TRACE("(%p) : Created volume %p.\n", This, object);
869 *ppVolume = (IWineD3DVolume *)object;
871 return WINED3D_OK;
874 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
875 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
876 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
879 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
880 HRESULT hr;
882 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
883 if (!object)
885 ERR("Out of memory\n");
886 *ppCubeTexture = NULL;
887 return WINED3DERR_OUTOFVIDEOMEMORY;
890 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
891 if (FAILED(hr))
893 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
894 HeapFree(GetProcessHeap(), 0, object);
895 *ppCubeTexture = NULL;
896 return hr;
899 TRACE("(%p) : Created Cube Texture %p\n", This, object);
900 *ppCubeTexture = (IWineD3DCubeTexture *)object;
902 return WINED3D_OK;
905 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
906 WINED3DQUERYTYPE type, IWineD3DQuery **query, IUnknown *parent)
908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
909 IWineD3DQueryImpl *object;
910 HRESULT hr;
912 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface, type, query, parent);
914 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
915 if (!object)
917 ERR("Failed to allocate query memory.\n");
918 return E_OUTOFMEMORY;
921 hr = query_init(object, This, type, parent);
922 if (FAILED(hr))
924 WARN("Failed to initialize query, hr %#x.\n", hr);
925 HeapFree(GetProcessHeap(), 0, object);
926 return hr;
929 TRACE("Created query %p.\n", object);
930 *query = (IWineD3DQuery *)object;
932 return WINED3D_OK;
935 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
936 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
937 IUnknown *parent, WINED3DSURFTYPE surface_type)
939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
940 IWineD3DSwapChainImpl *object;
941 HRESULT hr;
943 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
944 iface, present_parameters, swapchain, parent, surface_type);
946 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
947 if (!object)
949 ERR("Failed to allocate swapchain memory.\n");
950 return E_OUTOFMEMORY;
953 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
954 if (FAILED(hr))
956 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
957 HeapFree(GetProcessHeap(), 0, object);
958 return hr;
961 TRACE("Created swapchain %p.\n", object);
962 *swapchain = (IWineD3DSwapChain *)object;
964 return WINED3D_OK;
967 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
968 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
970 TRACE("(%p)\n", This);
972 return This->NumberOfSwapChains;
975 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
977 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
979 if(iSwapChain < This->NumberOfSwapChains) {
980 *pSwapChain = This->swapchains[iSwapChain];
981 IWineD3DSwapChain_AddRef(*pSwapChain);
982 TRACE("(%p) returning %p\n", This, *pSwapChain);
983 return WINED3D_OK;
984 } else {
985 TRACE("Swapchain out of range\n");
986 *pSwapChain = NULL;
987 return WINED3DERR_INVALIDCALL;
991 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
992 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
993 const WINED3DVERTEXELEMENT *elements, UINT element_count)
995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
996 IWineD3DVertexDeclarationImpl *object = NULL;
997 HRESULT hr;
999 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1000 iface, declaration, parent, elements, element_count);
1002 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1003 if(!object)
1005 ERR("Failed to allocate vertex declaration memory.\n");
1006 return E_OUTOFMEMORY;
1009 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1010 if (FAILED(hr))
1012 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1013 HeapFree(GetProcessHeap(), 0, object);
1014 return hr;
1017 TRACE("Created vertex declaration %p.\n", object);
1018 *declaration = (IWineD3DVertexDeclaration *)object;
1020 return WINED3D_OK;
1023 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1024 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1026 unsigned int idx, idx2;
1027 unsigned int offset;
1028 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1029 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1030 BOOL has_blend_idx = has_blend &&
1031 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1032 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1033 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1034 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1035 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1036 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1037 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1039 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1040 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1041 WINED3DVERTEXELEMENT *elements = NULL;
1043 unsigned int size;
1044 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1045 if (has_blend_idx) num_blends--;
1047 /* Compute declaration size */
1048 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1049 has_psize + has_diffuse + has_specular + num_textures;
1051 /* convert the declaration */
1052 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1053 if (!elements) return ~0U;
1055 idx = 0;
1056 if (has_pos) {
1057 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1058 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1059 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1061 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1062 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1063 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1065 else {
1066 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1067 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1069 elements[idx].usage_idx = 0;
1070 idx++;
1072 if (has_blend && (num_blends > 0)) {
1073 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1074 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1075 else {
1076 switch(num_blends) {
1077 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1078 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1079 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1080 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1081 default:
1082 ERR("Unexpected amount of blend values: %u\n", num_blends);
1085 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1086 elements[idx].usage_idx = 0;
1087 idx++;
1089 if (has_blend_idx) {
1090 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1091 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1092 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1093 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1094 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1095 else
1096 elements[idx].format = WINED3DFMT_R32_FLOAT;
1097 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1098 elements[idx].usage_idx = 0;
1099 idx++;
1101 if (has_normal) {
1102 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1103 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1104 elements[idx].usage_idx = 0;
1105 idx++;
1107 if (has_psize) {
1108 elements[idx].format = WINED3DFMT_R32_FLOAT;
1109 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1110 elements[idx].usage_idx = 0;
1111 idx++;
1113 if (has_diffuse) {
1114 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1115 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1116 elements[idx].usage_idx = 0;
1117 idx++;
1119 if (has_specular) {
1120 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1121 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1122 elements[idx].usage_idx = 1;
1123 idx++;
1125 for (idx2 = 0; idx2 < num_textures; idx2++) {
1126 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1127 switch (numcoords) {
1128 case WINED3DFVF_TEXTUREFORMAT1:
1129 elements[idx].format = WINED3DFMT_R32_FLOAT;
1130 break;
1131 case WINED3DFVF_TEXTUREFORMAT2:
1132 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1133 break;
1134 case WINED3DFVF_TEXTUREFORMAT3:
1135 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1136 break;
1137 case WINED3DFVF_TEXTUREFORMAT4:
1138 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1139 break;
1141 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1142 elements[idx].usage_idx = idx2;
1143 idx++;
1146 /* Now compute offsets, and initialize the rest of the fields */
1147 for (idx = 0, offset = 0; idx < size; ++idx)
1149 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1150 elements[idx].input_slot = 0;
1151 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1152 elements[idx].offset = offset;
1153 offset += format_desc->component_count * format_desc->component_size;
1156 *ppVertexElements = elements;
1157 return size;
1160 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1161 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1162 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1165 WINED3DVERTEXELEMENT *elements;
1166 unsigned int size;
1167 DWORD hr;
1169 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1171 size = ConvertFvfToDeclaration(This, fvf, &elements);
1172 if (size == ~0U) return E_OUTOFMEMORY;
1174 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1175 HeapFree(GetProcessHeap(), 0, elements);
1176 return hr;
1179 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1180 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1181 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1182 const struct wined3d_parent_ops *parent_ops)
1184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1185 IWineD3DVertexShaderImpl *object;
1186 HRESULT hr;
1188 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1189 if (!object)
1191 ERR("Failed to allocate shader memory.\n");
1192 return E_OUTOFMEMORY;
1195 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1196 if (FAILED(hr))
1198 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1199 HeapFree(GetProcessHeap(), 0, object);
1200 return hr;
1203 TRACE("Created vertex shader %p.\n", object);
1204 *ppVertexShader = (IWineD3DVertexShader *)object;
1206 return WINED3D_OK;
1209 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1210 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1211 IWineD3DGeometryShader **shader, IUnknown *parent,
1212 const struct wined3d_parent_ops *parent_ops)
1214 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1215 struct wined3d_geometryshader *object;
1216 HRESULT hr;
1218 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1219 if (!object)
1221 ERR("Failed to allocate shader memory.\n");
1222 return E_OUTOFMEMORY;
1225 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1226 if (FAILED(hr))
1228 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1229 HeapFree(GetProcessHeap(), 0, object);
1230 return hr;
1233 TRACE("Created geometry shader %p.\n", object);
1234 *shader = (IWineD3DGeometryShader *)object;
1236 return WINED3D_OK;
1239 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1240 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1241 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1242 const struct wined3d_parent_ops *parent_ops)
1244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1245 IWineD3DPixelShaderImpl *object;
1246 HRESULT hr;
1248 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1249 if (!object)
1251 ERR("Failed to allocate shader memory.\n");
1252 return E_OUTOFMEMORY;
1255 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1256 if (FAILED(hr))
1258 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1259 HeapFree(GetProcessHeap(), 0, object);
1260 return hr;
1263 TRACE("Created pixel shader %p.\n", object);
1264 *ppPixelShader = (IWineD3DPixelShader *)object;
1266 return WINED3D_OK;
1269 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1270 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1273 IWineD3DPaletteImpl *object;
1274 HRESULT hr;
1275 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1277 /* Create the new object */
1278 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1279 if(!object) {
1280 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1281 return E_OUTOFMEMORY;
1284 object->lpVtbl = &IWineD3DPalette_Vtbl;
1285 object->ref = 1;
1286 object->Flags = Flags;
1287 object->parent = Parent;
1288 object->device = This;
1289 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1290 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1292 if(!object->hpal) {
1293 HeapFree( GetProcessHeap(), 0, object);
1294 return E_OUTOFMEMORY;
1297 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1298 if(FAILED(hr)) {
1299 IWineD3DPalette_Release((IWineD3DPalette *) object);
1300 return hr;
1303 *Palette = (IWineD3DPalette *) object;
1305 return WINED3D_OK;
1308 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1309 HBITMAP hbm;
1310 BITMAP bm;
1311 HRESULT hr;
1312 HDC dcb = NULL, dcs = NULL;
1313 WINEDDCOLORKEY colorkey;
1315 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1316 if(hbm)
1318 GetObjectA(hbm, sizeof(BITMAP), &bm);
1319 dcb = CreateCompatibleDC(NULL);
1320 if(!dcb) goto out;
1321 SelectObject(dcb, hbm);
1323 else
1325 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1326 * couldn't be loaded
1328 memset(&bm, 0, sizeof(bm));
1329 bm.bmWidth = 32;
1330 bm.bmHeight = 32;
1333 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1334 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1335 NULL, &wined3d_null_parent_ops);
1336 if(FAILED(hr)) {
1337 ERR("Wine logo requested, but failed to create surface\n");
1338 goto out;
1341 if(dcb) {
1342 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1343 if(FAILED(hr)) goto out;
1344 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1345 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1347 colorkey.dwColorSpaceLowValue = 0;
1348 colorkey.dwColorSpaceHighValue = 0;
1349 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1350 } else {
1351 /* Fill the surface with a white color to show that wined3d is there */
1352 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1355 out:
1356 if (dcb) DeleteDC(dcb);
1357 if (hbm) DeleteObject(hbm);
1360 /* Context activation is done by the caller. */
1361 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1363 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1364 unsigned int i;
1365 /* Under DirectX you can have texture stage operations even if no texture is
1366 bound, whereas opengl will only do texture operations when a valid texture is
1367 bound. We emulate this by creating dummy textures and binding them to each
1368 texture stage, but disable all stages by default. Hence if a stage is enabled
1369 then the default texture will kick in until replaced by a SetTexture call */
1370 ENTER_GL();
1372 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1374 /* The dummy texture does not have client storage backing */
1375 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1376 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1379 for (i = 0; i < gl_info->limits.textures; ++i)
1381 GLubyte white = 255;
1383 /* Make appropriate texture active */
1384 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1385 checkGLcall("glActiveTextureARB");
1387 /* Generate an opengl texture name */
1388 glGenTextures(1, &This->dummyTextureName[i]);
1389 checkGLcall("glGenTextures");
1390 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1392 /* Generate a dummy 2d texture (not using 1d because they cause many
1393 * DRI drivers fall back to sw) */
1394 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1395 checkGLcall("glBindTexture");
1397 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1398 checkGLcall("glTexImage2D");
1401 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1403 /* Reenable because if supported it is enabled by default */
1404 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1405 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1408 LEAVE_GL();
1411 /* Context activation is done by the caller. */
1412 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1414 ENTER_GL();
1415 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1416 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1417 LEAVE_GL();
1419 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1422 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1423 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1425 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1426 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1427 IWineD3DSwapChainImpl *swapchain = NULL;
1428 struct wined3d_context *context;
1429 HRESULT hr;
1430 DWORD state;
1431 unsigned int i;
1433 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1435 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1436 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1438 if (!pPresentationParameters->Windowed)
1440 This->focus_window = This->createParms.hFocusWindow;
1441 if (!This->focus_window) This->focus_window = pPresentationParameters->hDeviceWindow;
1442 if (!wined3d_register_window(This->focus_window, This))
1444 ERR("Failed to register window %p.\n", This->focus_window);
1445 return E_FAIL;
1449 TRACE("(%p) : Creating stateblock\n", This);
1450 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1451 hr = IWineD3DDevice_CreateStateBlock(iface,
1452 WINED3DSBT_INIT,
1453 (IWineD3DStateBlock **)&This->stateBlock,
1454 NULL);
1455 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1456 WARN("Failed to create stateblock\n");
1457 goto err_out;
1459 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1460 This->updateStateBlock = This->stateBlock;
1461 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1463 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1464 sizeof(IWineD3DSurface *) * gl_info->limits.buffers);
1465 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1466 sizeof(GLenum) * gl_info->limits.buffers);
1468 This->NumberOfPalettes = 1;
1469 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1470 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1471 ERR("Out of memory!\n");
1472 hr = E_OUTOFMEMORY;
1473 goto err_out;
1475 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1476 if(!This->palettes[0]) {
1477 ERR("Out of memory!\n");
1478 hr = E_OUTOFMEMORY;
1479 goto err_out;
1481 for (i = 0; i < 256; ++i) {
1482 This->palettes[0][i].peRed = 0xFF;
1483 This->palettes[0][i].peGreen = 0xFF;
1484 This->palettes[0][i].peBlue = 0xFF;
1485 This->palettes[0][i].peFlags = 0xFF;
1487 This->currentPalette = 0;
1489 /* Initialize the texture unit mapping to a 1:1 mapping */
1490 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1492 if (state < gl_info->limits.fragment_samplers)
1494 This->texUnitMap[state] = state;
1495 This->rev_tex_unit_map[state] = state;
1496 } else {
1497 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1498 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1502 if (This->focus_window) SetFocus(This->focus_window);
1504 /* Setup the implicit swapchain. This also initializes a context. */
1505 TRACE("Creating implicit swapchain\n");
1506 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1507 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1508 if (FAILED(hr))
1510 WARN("Failed to create implicit swapchain\n");
1511 goto err_out;
1514 This->NumberOfSwapChains = 1;
1515 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1516 if(!This->swapchains) {
1517 ERR("Out of memory!\n");
1518 goto err_out;
1520 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1522 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1523 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1524 This->render_targets[0] = swapchain->backBuffer[0];
1526 else {
1527 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1528 This->render_targets[0] = swapchain->frontBuffer;
1530 IWineD3DSurface_AddRef(This->render_targets[0]);
1532 /* Depth Stencil support */
1533 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1534 if (NULL != This->stencilBufferTarget) {
1535 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1538 hr = This->shader_backend->shader_alloc_private(iface);
1539 if(FAILED(hr)) {
1540 TRACE("Shader private data couldn't be allocated\n");
1541 goto err_out;
1543 hr = This->frag_pipe->alloc_private(iface);
1544 if(FAILED(hr)) {
1545 TRACE("Fragment pipeline private data couldn't be allocated\n");
1546 goto err_out;
1548 hr = This->blitter->alloc_private(iface);
1549 if(FAILED(hr)) {
1550 TRACE("Blitter private data couldn't be allocated\n");
1551 goto err_out;
1554 /* Set up some starting GL setup */
1556 /* Setup all the devices defaults */
1557 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1559 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1561 create_dummy_textures(This);
1563 ENTER_GL();
1565 /* Initialize the current view state */
1566 This->view_ident = 1;
1567 This->contexts[0]->last_was_rhw = 0;
1568 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1569 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1571 switch(wined3d_settings.offscreen_rendering_mode) {
1572 case ORM_FBO:
1573 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1574 break;
1576 case ORM_PBUFFER:
1577 This->offscreenBuffer = GL_BACK;
1578 break;
1580 case ORM_BACKBUFFER:
1582 if (context_get_current()->aux_buffers > 0)
1584 TRACE("Using auxilliary buffer for offscreen rendering\n");
1585 This->offscreenBuffer = GL_AUX0;
1586 } else {
1587 TRACE("Using back buffer for offscreen rendering\n");
1588 This->offscreenBuffer = GL_BACK;
1593 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1594 LEAVE_GL();
1596 context_release(context);
1598 /* Clear the screen */
1599 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1600 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1601 0x00, 1.0f, 0);
1603 This->d3d_initialized = TRUE;
1605 if(wined3d_settings.logo) {
1606 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1608 This->highest_dirty_ps_const = 0;
1609 This->highest_dirty_vs_const = 0;
1610 return WINED3D_OK;
1612 err_out:
1613 HeapFree(GetProcessHeap(), 0, This->render_targets);
1614 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1615 HeapFree(GetProcessHeap(), 0, This->swapchains);
1616 This->NumberOfSwapChains = 0;
1617 if(This->palettes) {
1618 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1619 HeapFree(GetProcessHeap(), 0, This->palettes);
1621 This->NumberOfPalettes = 0;
1622 if(swapchain) {
1623 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1625 if(This->stateBlock) {
1626 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1627 This->stateBlock = NULL;
1629 if (This->blit_priv) {
1630 This->blitter->free_private(iface);
1632 if (This->fragment_priv) {
1633 This->frag_pipe->free_private(iface);
1635 if (This->shader_priv) {
1636 This->shader_backend->shader_free_private(iface);
1638 if (This->focus_window) wined3d_unregister_window(This->focus_window);
1639 return hr;
1642 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1643 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1646 IWineD3DSwapChainImpl *swapchain = NULL;
1647 HRESULT hr;
1649 /* Setup the implicit swapchain */
1650 TRACE("Creating implicit swapchain\n");
1651 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1652 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1653 if (FAILED(hr))
1655 WARN("Failed to create implicit swapchain\n");
1656 goto err_out;
1659 This->NumberOfSwapChains = 1;
1660 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1661 if(!This->swapchains) {
1662 ERR("Out of memory!\n");
1663 goto err_out;
1665 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1666 return WINED3D_OK;
1668 err_out:
1669 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1670 return hr;
1673 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1675 IWineD3DResource_UnLoad(resource);
1676 IWineD3DResource_Release(resource);
1677 return WINED3D_OK;
1680 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1681 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1684 const struct wined3d_gl_info *gl_info;
1685 struct wined3d_context *context;
1686 int sampler;
1687 UINT i;
1688 TRACE("(%p)\n", This);
1690 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1692 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1693 * it was created. Thus make sure a context is active for the glDelete* calls
1695 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1696 gl_info = context->gl_info;
1698 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1700 /* Unload resources */
1701 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1703 TRACE("Deleting high order patches\n");
1704 for(i = 0; i < PATCHMAP_SIZE; i++) {
1705 struct list *e1, *e2;
1706 struct WineD3DRectPatch *patch;
1707 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1708 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1709 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1713 /* Delete the palette conversion shader if it is around */
1714 if(This->paletteConversionShader) {
1715 ENTER_GL();
1716 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
1717 LEAVE_GL();
1718 This->paletteConversionShader = 0;
1721 /* Delete the pbuffer context if there is any */
1722 if(This->pbufferContext) context_destroy(This, This->pbufferContext);
1724 /* Delete the mouse cursor texture */
1725 if(This->cursorTexture) {
1726 ENTER_GL();
1727 glDeleteTextures(1, &This->cursorTexture);
1728 LEAVE_GL();
1729 This->cursorTexture = 0;
1732 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1733 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1735 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1736 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1739 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1740 * private data, it might contain opengl pointers
1742 if(This->depth_blt_texture) {
1743 ENTER_GL();
1744 glDeleteTextures(1, &This->depth_blt_texture);
1745 LEAVE_GL();
1746 This->depth_blt_texture = 0;
1748 if (This->depth_blt_rb) {
1749 ENTER_GL();
1750 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1751 LEAVE_GL();
1752 This->depth_blt_rb = 0;
1753 This->depth_blt_rb_w = 0;
1754 This->depth_blt_rb_h = 0;
1757 /* Release the update stateblock */
1758 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1759 if(This->updateStateBlock != This->stateBlock)
1760 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1762 This->updateStateBlock = NULL;
1764 { /* because were not doing proper internal refcounts releasing the primary state block
1765 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1766 to set this->stateBlock = NULL; first */
1767 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1768 This->stateBlock = NULL;
1770 /* Release the stateblock */
1771 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1772 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1776 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1777 This->blitter->free_private(iface);
1778 This->frag_pipe->free_private(iface);
1779 This->shader_backend->shader_free_private(iface);
1781 /* Release the buffers (with sanity checks)*/
1782 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1783 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1784 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
1785 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
1787 This->stencilBufferTarget = NULL;
1789 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1790 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1791 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1793 TRACE("Setting rendertarget to NULL\n");
1794 This->render_targets[0] = NULL;
1796 if (This->auto_depth_stencil_buffer) {
1797 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
1799 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1801 This->auto_depth_stencil_buffer = NULL;
1804 context_release(context);
1806 for(i=0; i < This->NumberOfSwapChains; i++) {
1807 TRACE("Releasing the implicit swapchain %d\n", i);
1808 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1809 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1813 HeapFree(GetProcessHeap(), 0, This->swapchains);
1814 This->swapchains = NULL;
1815 This->NumberOfSwapChains = 0;
1817 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1818 HeapFree(GetProcessHeap(), 0, This->palettes);
1819 This->palettes = NULL;
1820 This->NumberOfPalettes = 0;
1822 HeapFree(GetProcessHeap(), 0, This->render_targets);
1823 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1824 This->render_targets = NULL;
1825 This->draw_buffers = NULL;
1827 This->d3d_initialized = FALSE;
1829 if (This->focus_window) wined3d_unregister_window(This->focus_window);
1831 return WINED3D_OK;
1834 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1836 unsigned int i;
1838 for(i=0; i < This->NumberOfSwapChains; i++) {
1839 TRACE("Releasing the implicit swapchain %d\n", i);
1840 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1841 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1845 HeapFree(GetProcessHeap(), 0, This->swapchains);
1846 This->swapchains = NULL;
1847 This->NumberOfSwapChains = 0;
1848 return WINED3D_OK;
1851 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1852 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1853 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1855 * There is no way to deactivate thread safety once it is enabled.
1857 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1860 /*For now just store the flag(needed in case of ddraw) */
1861 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1864 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1865 const WINED3DDISPLAYMODE* pMode) {
1866 DEVMODEW devmode;
1867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1868 LONG ret;
1869 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1870 RECT clip_rc;
1872 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1874 /* Resize the screen even without a window:
1875 * The app could have unset it with SetCooperativeLevel, but not called
1876 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1877 * but we don't have any hwnd
1880 memset(&devmode, 0, sizeof(devmode));
1881 devmode.dmSize = sizeof(devmode);
1882 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1883 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1884 devmode.dmPelsWidth = pMode->Width;
1885 devmode.dmPelsHeight = pMode->Height;
1887 devmode.dmDisplayFrequency = pMode->RefreshRate;
1888 if (pMode->RefreshRate != 0) {
1889 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1892 /* Only change the mode if necessary */
1893 if( (This->ddraw_width == pMode->Width) &&
1894 (This->ddraw_height == pMode->Height) &&
1895 (This->ddraw_format == pMode->Format) &&
1896 (pMode->RefreshRate == 0) ) {
1897 return WINED3D_OK;
1900 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1901 if (ret != DISP_CHANGE_SUCCESSFUL) {
1902 if(devmode.dmDisplayFrequency != 0) {
1903 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1904 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1905 devmode.dmDisplayFrequency = 0;
1906 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1908 if(ret != DISP_CHANGE_SUCCESSFUL) {
1909 return WINED3DERR_NOTAVAILABLE;
1913 /* Store the new values */
1914 This->ddraw_width = pMode->Width;
1915 This->ddraw_height = pMode->Height;
1916 This->ddraw_format = pMode->Format;
1918 /* And finally clip mouse to our screen */
1919 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1920 ClipCursor(&clip_rc);
1922 return WINED3D_OK;
1925 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1927 *ppD3D = This->wined3d;
1928 TRACE("Returning %p.\n", *ppD3D);
1929 IWineD3D_AddRef(*ppD3D);
1930 return WINED3D_OK;
1933 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1936 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1937 (This->adapter->TextureRam/(1024*1024)),
1938 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
1939 /* return simulated texture memory left */
1940 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
1943 /*****
1944 * Get / Set Stream Source
1945 *****/
1946 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
1947 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
1949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1950 IWineD3DBuffer *oldSrc;
1952 if (StreamNumber >= MAX_STREAMS) {
1953 WARN("Stream out of range %d\n", StreamNumber);
1954 return WINED3DERR_INVALIDCALL;
1955 } else if(OffsetInBytes & 0x3) {
1956 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
1957 return WINED3DERR_INVALIDCALL;
1960 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
1961 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
1963 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
1965 if(oldSrc == pStreamData &&
1966 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
1967 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
1968 TRACE("Application is setting the old values over, nothing to do\n");
1969 return WINED3D_OK;
1972 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
1973 if (pStreamData) {
1974 This->updateStateBlock->streamStride[StreamNumber] = Stride;
1975 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
1978 /* Handle recording of state blocks */
1979 if (This->isRecordingState) {
1980 TRACE("Recording... not performing anything\n");
1981 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
1982 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
1983 return WINED3D_OK;
1986 if (pStreamData != NULL) {
1987 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
1988 IWineD3DBuffer_AddRef(pStreamData);
1990 if (oldSrc != NULL) {
1991 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
1992 IWineD3DBuffer_Release(oldSrc);
1995 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
1997 return WINED3D_OK;
2000 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2001 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2005 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2006 This->stateBlock->streamSource[StreamNumber],
2007 This->stateBlock->streamOffset[StreamNumber],
2008 This->stateBlock->streamStride[StreamNumber]);
2010 if (StreamNumber >= MAX_STREAMS) {
2011 WARN("Stream out of range %d\n", StreamNumber);
2012 return WINED3DERR_INVALIDCALL;
2014 *pStream = This->stateBlock->streamSource[StreamNumber];
2015 *pStride = This->stateBlock->streamStride[StreamNumber];
2016 if (pOffset) {
2017 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2020 if (*pStream != NULL) {
2021 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2023 return WINED3D_OK;
2026 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2028 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2029 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2031 /* Verify input at least in d3d9 this is invalid*/
2032 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2033 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2034 return WINED3DERR_INVALIDCALL;
2036 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2037 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2038 return WINED3DERR_INVALIDCALL;
2040 if( Divider == 0 ){
2041 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2042 return WINED3DERR_INVALIDCALL;
2045 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2046 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2048 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2049 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2051 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2052 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2053 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2056 return WINED3D_OK;
2059 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2062 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2063 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2065 TRACE("(%p) : returning %d\n", This, *Divider);
2067 return WINED3D_OK;
2070 /*****
2071 * Get / Set & Multiply Transform
2072 *****/
2073 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2076 /* Most of this routine, comments included copied from ddraw tree initially: */
2077 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2079 /* Handle recording of state blocks */
2080 if (This->isRecordingState) {
2081 TRACE("Recording... not performing anything\n");
2082 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2083 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2084 return WINED3D_OK;
2088 * If the new matrix is the same as the current one,
2089 * we cut off any further processing. this seems to be a reasonable
2090 * optimization because as was noticed, some apps (warcraft3 for example)
2091 * tend towards setting the same matrix repeatedly for some reason.
2093 * From here on we assume that the new matrix is different, wherever it matters.
2095 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2096 TRACE("The app is setting the same matrix over again\n");
2097 return WINED3D_OK;
2098 } else {
2099 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2103 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2104 where ViewMat = Camera space, WorldMat = world space.
2106 In OpenGL, camera and world space is combined into GL_MODELVIEW
2107 matrix. The Projection matrix stay projection matrix.
2110 /* Capture the times we can just ignore the change for now */
2111 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2112 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2113 /* Handled by the state manager */
2116 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2117 return WINED3D_OK;
2120 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2122 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2123 *pMatrix = This->stateBlock->transforms[State];
2124 return WINED3D_OK;
2127 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2128 const WINED3DMATRIX *mat = NULL;
2129 WINED3DMATRIX temp;
2131 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2132 * below means it will be recorded in a state block change, but it
2133 * works regardless where it is recorded.
2134 * If this is found to be wrong, change to StateBlock.
2136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2137 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2139 if (State <= HIGHEST_TRANSFORMSTATE)
2141 mat = &This->updateStateBlock->transforms[State];
2142 } else {
2143 FIXME("Unhandled transform state!!\n");
2146 multiply_matrix(&temp, mat, pMatrix);
2148 /* Apply change via set transform - will reapply to eg. lights this way */
2149 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2152 /*****
2153 * Get / Set Light
2154 *****/
2155 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2156 you can reference any indexes you want as long as that number max are enabled at any
2157 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2158 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2159 but when recording, just build a chain pretty much of commands to be replayed. */
2161 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2162 float rho;
2163 struct wined3d_light_info *object = NULL;
2164 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2165 struct list *e;
2167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2168 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2170 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2171 * the gl driver.
2173 if(!pLight) {
2174 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2175 return WINED3DERR_INVALIDCALL;
2178 switch(pLight->Type) {
2179 case WINED3DLIGHT_POINT:
2180 case WINED3DLIGHT_SPOT:
2181 case WINED3DLIGHT_PARALLELPOINT:
2182 case WINED3DLIGHT_GLSPOT:
2183 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2184 * most wanted
2186 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2188 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2189 return WINED3DERR_INVALIDCALL;
2191 break;
2193 case WINED3DLIGHT_DIRECTIONAL:
2194 /* Ignores attenuation */
2195 break;
2197 default:
2198 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2199 return WINED3DERR_INVALIDCALL;
2202 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2204 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2205 if(object->OriginalIndex == Index) break;
2206 object = NULL;
2209 if(!object) {
2210 TRACE("Adding new light\n");
2211 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2212 if(!object) {
2213 ERR("Out of memory error when allocating a light\n");
2214 return E_OUTOFMEMORY;
2216 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2217 object->glIndex = -1;
2218 object->OriginalIndex = Index;
2221 /* Initialize the object */
2222 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,
2223 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2224 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2225 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2226 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2227 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2228 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2230 /* Save away the information */
2231 object->OriginalParms = *pLight;
2233 switch (pLight->Type) {
2234 case WINED3DLIGHT_POINT:
2235 /* Position */
2236 object->lightPosn[0] = pLight->Position.x;
2237 object->lightPosn[1] = pLight->Position.y;
2238 object->lightPosn[2] = pLight->Position.z;
2239 object->lightPosn[3] = 1.0f;
2240 object->cutoff = 180.0f;
2241 /* FIXME: Range */
2242 break;
2244 case WINED3DLIGHT_DIRECTIONAL:
2245 /* Direction */
2246 object->lightPosn[0] = -pLight->Direction.x;
2247 object->lightPosn[1] = -pLight->Direction.y;
2248 object->lightPosn[2] = -pLight->Direction.z;
2249 object->lightPosn[3] = 0.0f;
2250 object->exponent = 0.0f;
2251 object->cutoff = 180.0f;
2252 break;
2254 case WINED3DLIGHT_SPOT:
2255 /* Position */
2256 object->lightPosn[0] = pLight->Position.x;
2257 object->lightPosn[1] = pLight->Position.y;
2258 object->lightPosn[2] = pLight->Position.z;
2259 object->lightPosn[3] = 1.0f;
2261 /* Direction */
2262 object->lightDirn[0] = pLight->Direction.x;
2263 object->lightDirn[1] = pLight->Direction.y;
2264 object->lightDirn[2] = pLight->Direction.z;
2265 object->lightDirn[3] = 1.0f;
2268 * opengl-ish and d3d-ish spot lights use too different models for the
2269 * light "intensity" as a function of the angle towards the main light direction,
2270 * so we only can approximate very roughly.
2271 * however spot lights are rather rarely used in games (if ever used at all).
2272 * furthermore if still used, probably nobody pays attention to such details.
2274 if (pLight->Falloff == 0) {
2275 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2276 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2277 * will always be 1.0 for both of them, and we don't have to care for the
2278 * rest of the rather complex calculation
2280 object->exponent = 0.0f;
2281 } else {
2282 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2283 if (rho < 0.0001f) rho = 0.0001f;
2284 object->exponent = -0.3f/logf(cosf(rho/2));
2286 if (object->exponent > 128.0f)
2288 object->exponent = 128.0f;
2290 object->cutoff = pLight->Phi*90/M_PI;
2292 /* FIXME: Range */
2293 break;
2295 default:
2296 FIXME("Unrecognized light type %d\n", pLight->Type);
2299 /* Update the live definitions if the light is currently assigned a glIndex */
2300 if (object->glIndex != -1 && !This->isRecordingState) {
2301 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2303 return WINED3D_OK;
2306 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2308 struct wined3d_light_info *lightInfo = NULL;
2309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2310 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2311 struct list *e;
2312 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2314 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2316 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2317 if(lightInfo->OriginalIndex == Index) break;
2318 lightInfo = NULL;
2321 if (lightInfo == NULL) {
2322 TRACE("Light information requested but light not defined\n");
2323 return WINED3DERR_INVALIDCALL;
2326 *pLight = lightInfo->OriginalParms;
2327 return WINED3D_OK;
2330 /*****
2331 * Get / Set Light Enable
2332 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2333 *****/
2334 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2336 struct wined3d_light_info *lightInfo = NULL;
2337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2338 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2339 struct list *e;
2340 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2342 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2344 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2345 if(lightInfo->OriginalIndex == Index) break;
2346 lightInfo = NULL;
2348 TRACE("Found light: %p\n", lightInfo);
2350 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2351 if (lightInfo == NULL) {
2353 TRACE("Light enabled requested but light not defined, so defining one!\n");
2354 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2356 /* Search for it again! Should be fairly quick as near head of list */
2357 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2359 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2360 if(lightInfo->OriginalIndex == Index) break;
2361 lightInfo = NULL;
2363 if (lightInfo == NULL) {
2364 FIXME("Adding default lights has failed dismally\n");
2365 return WINED3DERR_INVALIDCALL;
2369 if(!Enable) {
2370 if(lightInfo->glIndex != -1) {
2371 if(!This->isRecordingState) {
2372 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2375 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2376 lightInfo->glIndex = -1;
2377 } else {
2378 TRACE("Light already disabled, nothing to do\n");
2380 lightInfo->enabled = FALSE;
2381 } else {
2382 lightInfo->enabled = TRUE;
2383 if (lightInfo->glIndex != -1) {
2384 /* nop */
2385 TRACE("Nothing to do as light was enabled\n");
2386 } else {
2387 int i;
2388 /* Find a free gl light */
2389 for(i = 0; i < This->maxConcurrentLights; i++) {
2390 if(This->updateStateBlock->activeLights[i] == NULL) {
2391 This->updateStateBlock->activeLights[i] = lightInfo;
2392 lightInfo->glIndex = i;
2393 break;
2396 if(lightInfo->glIndex == -1) {
2397 /* Our tests show that Windows returns D3D_OK in this situation, even with
2398 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2399 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2400 * as well for those lights.
2402 * TODO: Test how this affects rendering
2404 WARN("Too many concurrently active lights\n");
2405 return WINED3D_OK;
2408 /* i == lightInfo->glIndex */
2409 if(!This->isRecordingState) {
2410 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2415 return WINED3D_OK;
2418 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2420 struct wined3d_light_info *lightInfo = NULL;
2421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2422 struct list *e;
2423 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2424 TRACE("(%p) : for idx(%d)\n", This, Index);
2426 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2428 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2429 if(lightInfo->OriginalIndex == Index) break;
2430 lightInfo = NULL;
2433 if (lightInfo == NULL) {
2434 TRACE("Light enabled state requested but light not defined\n");
2435 return WINED3DERR_INVALIDCALL;
2437 /* true is 128 according to SetLightEnable */
2438 *pEnable = lightInfo->enabled ? 128 : 0;
2439 return WINED3D_OK;
2442 /*****
2443 * Get / Set Clip Planes
2444 *****/
2445 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2446 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2447 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2449 /* Validate Index */
2450 if (Index >= This->adapter->gl_info.limits.clipplanes)
2452 TRACE("Application has requested clipplane this device doesn't support\n");
2453 return WINED3DERR_INVALIDCALL;
2456 This->updateStateBlock->changed.clipplane |= 1 << Index;
2458 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2459 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2460 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2461 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2462 TRACE("Application is setting old values over, nothing to do\n");
2463 return WINED3D_OK;
2466 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2467 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2468 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2469 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2471 /* Handle recording of state blocks */
2472 if (This->isRecordingState) {
2473 TRACE("Recording... not performing anything\n");
2474 return WINED3D_OK;
2477 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2479 return WINED3D_OK;
2482 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2484 TRACE("(%p) : for idx %d\n", This, Index);
2486 /* Validate Index */
2487 if (Index >= This->adapter->gl_info.limits.clipplanes)
2489 TRACE("Application has requested clipplane this device doesn't support\n");
2490 return WINED3DERR_INVALIDCALL;
2493 pPlane[0] = This->stateBlock->clipplane[Index][0];
2494 pPlane[1] = This->stateBlock->clipplane[Index][1];
2495 pPlane[2] = This->stateBlock->clipplane[Index][2];
2496 pPlane[3] = This->stateBlock->clipplane[Index][3];
2497 return WINED3D_OK;
2500 /*****
2501 * Get / Set Clip Plane Status
2502 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2503 *****/
2504 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2506 FIXME("(%p) : stub\n", This);
2507 if (NULL == pClipStatus) {
2508 return WINED3DERR_INVALIDCALL;
2510 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2511 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2512 return WINED3D_OK;
2515 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2517 FIXME("(%p) : stub\n", This);
2518 if (NULL == pClipStatus) {
2519 return WINED3DERR_INVALIDCALL;
2521 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2522 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2523 return WINED3D_OK;
2526 /*****
2527 * Get / Set Material
2528 *****/
2529 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2532 This->updateStateBlock->changed.material = TRUE;
2533 This->updateStateBlock->material = *pMaterial;
2535 /* Handle recording of state blocks */
2536 if (This->isRecordingState) {
2537 TRACE("Recording... not performing anything\n");
2538 return WINED3D_OK;
2541 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2542 return WINED3D_OK;
2545 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2547 *pMaterial = This->updateStateBlock->material;
2548 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2549 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2550 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2551 pMaterial->Ambient.b, pMaterial->Ambient.a);
2552 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2553 pMaterial->Specular.b, pMaterial->Specular.a);
2554 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2555 pMaterial->Emissive.b, pMaterial->Emissive.a);
2556 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2558 return WINED3D_OK;
2561 /*****
2562 * Get / Set Indices
2563 *****/
2564 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2565 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2568 IWineD3DBuffer *oldIdxs;
2570 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2571 oldIdxs = This->updateStateBlock->pIndexData;
2573 This->updateStateBlock->changed.indices = TRUE;
2574 This->updateStateBlock->pIndexData = pIndexData;
2575 This->updateStateBlock->IndexFmt = fmt;
2577 /* Handle recording of state blocks */
2578 if (This->isRecordingState) {
2579 TRACE("Recording... not performing anything\n");
2580 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2581 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2582 return WINED3D_OK;
2585 if(oldIdxs != pIndexData) {
2586 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2587 if(pIndexData) {
2588 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2589 IWineD3DBuffer_AddRef(pIndexData);
2591 if(oldIdxs) {
2592 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2593 IWineD3DBuffer_Release(oldIdxs);
2597 return WINED3D_OK;
2600 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2604 *ppIndexData = This->stateBlock->pIndexData;
2606 /* up ref count on ppindexdata */
2607 if (*ppIndexData) {
2608 IWineD3DBuffer_AddRef(*ppIndexData);
2609 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2610 }else{
2611 TRACE("(%p) No index data set\n", This);
2613 TRACE("Returning %p\n", *ppIndexData);
2615 return WINED3D_OK;
2618 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2619 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2621 TRACE("(%p)->(%d)\n", This, BaseIndex);
2623 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2624 TRACE("Application is setting the old value over, nothing to do\n");
2625 return WINED3D_OK;
2628 This->updateStateBlock->baseVertexIndex = BaseIndex;
2630 if (This->isRecordingState) {
2631 TRACE("Recording... not performing anything\n");
2632 return WINED3D_OK;
2634 /* The base vertex index affects the stream sources */
2635 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2636 return WINED3D_OK;
2639 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2641 TRACE("(%p) : base_index %p\n", This, base_index);
2643 *base_index = This->stateBlock->baseVertexIndex;
2645 TRACE("Returning %u\n", *base_index);
2647 return WINED3D_OK;
2650 /*****
2651 * Get / Set Viewports
2652 *****/
2653 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2656 TRACE("(%p)\n", This);
2657 This->updateStateBlock->changed.viewport = TRUE;
2658 This->updateStateBlock->viewport = *pViewport;
2660 /* Handle recording of state blocks */
2661 if (This->isRecordingState) {
2662 TRACE("Recording... not performing anything\n");
2663 return WINED3D_OK;
2666 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2667 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2669 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2670 return WINED3D_OK;
2674 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2676 TRACE("(%p)\n", This);
2677 *pViewport = This->stateBlock->viewport;
2678 return WINED3D_OK;
2681 /*****
2682 * Get / Set Render States
2683 * TODO: Verify against dx9 definitions
2684 *****/
2685 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2688 DWORD oldValue = This->stateBlock->renderState[State];
2690 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2692 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2693 This->updateStateBlock->renderState[State] = Value;
2695 /* Handle recording of state blocks */
2696 if (This->isRecordingState) {
2697 TRACE("Recording... not performing anything\n");
2698 return WINED3D_OK;
2701 /* Compared here and not before the assignment to allow proper stateblock recording */
2702 if(Value == oldValue) {
2703 TRACE("Application is setting the old value over, nothing to do\n");
2704 } else {
2705 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2708 return WINED3D_OK;
2711 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2713 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2714 *pValue = This->stateBlock->renderState[State];
2715 return WINED3D_OK;
2718 /*****
2719 * Get / Set Sampler States
2720 * TODO: Verify against dx9 definitions
2721 *****/
2723 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2725 DWORD oldValue;
2727 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2728 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2730 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2731 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2734 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2735 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2736 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2739 * SetSampler is designed to allow for more than the standard up to 8 textures
2740 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2741 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2743 * http://developer.nvidia.com/object/General_FAQ.html#t6
2745 * There are two new settings for GForce
2746 * the sampler one:
2747 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2748 * and the texture one:
2749 * GL_MAX_TEXTURE_COORDS_ARB.
2750 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2751 ******************/
2753 oldValue = This->stateBlock->samplerState[Sampler][Type];
2754 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2755 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2757 /* Handle recording of state blocks */
2758 if (This->isRecordingState) {
2759 TRACE("Recording... not performing anything\n");
2760 return WINED3D_OK;
2763 if(oldValue == Value) {
2764 TRACE("Application is setting the old value over, nothing to do\n");
2765 return WINED3D_OK;
2768 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2770 return WINED3D_OK;
2773 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2776 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2777 This, Sampler, debug_d3dsamplerstate(Type), Type);
2779 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2780 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2783 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2784 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2785 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2787 *Value = This->stateBlock->samplerState[Sampler][Type];
2788 TRACE("(%p) : Returning %#x\n", This, *Value);
2790 return WINED3D_OK;
2793 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2796 This->updateStateBlock->changed.scissorRect = TRUE;
2797 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2798 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2799 return WINED3D_OK;
2801 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2803 if(This->isRecordingState) {
2804 TRACE("Recording... not performing anything\n");
2805 return WINED3D_OK;
2808 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2810 return WINED3D_OK;
2813 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2816 *pRect = This->updateStateBlock->scissorRect;
2817 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2818 return WINED3D_OK;
2821 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2823 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2825 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2827 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2828 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2830 This->updateStateBlock->vertexDecl = pDecl;
2831 This->updateStateBlock->changed.vertexDecl = TRUE;
2833 if (This->isRecordingState) {
2834 TRACE("Recording... not performing anything\n");
2835 return WINED3D_OK;
2836 } else if(pDecl == oldDecl) {
2837 /* Checked after the assignment to allow proper stateblock recording */
2838 TRACE("Application is setting the old declaration over, nothing to do\n");
2839 return WINED3D_OK;
2842 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2843 return WINED3D_OK;
2846 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2849 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2851 *ppDecl = This->stateBlock->vertexDecl;
2852 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2853 return WINED3D_OK;
2856 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2858 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2860 This->updateStateBlock->vertexShader = pShader;
2861 This->updateStateBlock->changed.vertexShader = TRUE;
2863 if (This->isRecordingState) {
2864 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2865 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2866 TRACE("Recording... not performing anything\n");
2867 return WINED3D_OK;
2868 } else if(oldShader == pShader) {
2869 /* Checked here to allow proper stateblock recording */
2870 TRACE("App is setting the old shader over, nothing to do\n");
2871 return WINED3D_OK;
2874 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2875 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2876 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2878 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2880 return WINED3D_OK;
2883 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2886 if (NULL == ppShader) {
2887 return WINED3DERR_INVALIDCALL;
2889 *ppShader = This->stateBlock->vertexShader;
2890 if( NULL != *ppShader)
2891 IWineD3DVertexShader_AddRef(*ppShader);
2893 TRACE("(%p) : returning %p\n", This, *ppShader);
2894 return WINED3D_OK;
2897 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2898 IWineD3DDevice *iface,
2899 UINT start,
2900 CONST BOOL *srcData,
2901 UINT count) {
2903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2904 unsigned int i, cnt = min(count, MAX_CONST_B - start);
2906 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2907 iface, srcData, start, count);
2909 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
2911 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2912 for (i = 0; i < cnt; i++)
2913 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2915 for (i = start; i < cnt + start; ++i) {
2916 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
2919 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2921 return WINED3D_OK;
2924 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2925 IWineD3DDevice *iface,
2926 UINT start,
2927 BOOL *dstData,
2928 UINT count) {
2930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2931 int cnt = min(count, MAX_CONST_B - start);
2933 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2934 iface, dstData, start, count);
2936 if (dstData == NULL || cnt < 0)
2937 return WINED3DERR_INVALIDCALL;
2939 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2940 return WINED3D_OK;
2943 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2944 IWineD3DDevice *iface,
2945 UINT start,
2946 CONST int *srcData,
2947 UINT count) {
2949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2950 unsigned int i, cnt = min(count, MAX_CONST_I - start);
2952 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2953 iface, srcData, start, count);
2955 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
2957 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2958 for (i = 0; i < cnt; i++)
2959 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2960 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2962 for (i = start; i < cnt + start; ++i) {
2963 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
2966 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2968 return WINED3D_OK;
2971 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2972 IWineD3DDevice *iface,
2973 UINT start,
2974 int *dstData,
2975 UINT count) {
2977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2978 int cnt = min(count, MAX_CONST_I - start);
2980 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2981 iface, dstData, start, count);
2983 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2984 return WINED3DERR_INVALIDCALL;
2986 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
2987 return WINED3D_OK;
2990 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
2991 IWineD3DDevice *iface,
2992 UINT start,
2993 CONST float *srcData,
2994 UINT count) {
2996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2997 UINT i;
2999 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3000 iface, srcData, start, count);
3002 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3003 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3004 return WINED3DERR_INVALIDCALL;
3006 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3007 if(TRACE_ON(d3d)) {
3008 for (i = 0; i < count; i++)
3009 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3010 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3013 if (!This->isRecordingState)
3015 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3016 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3019 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3020 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3022 return WINED3D_OK;
3025 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3026 IWineD3DDevice *iface,
3027 UINT start,
3028 float *dstData,
3029 UINT count) {
3031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3032 int cnt = min(count, This->d3d_vshader_constantF - start);
3034 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3035 iface, dstData, start, count);
3037 if (dstData == NULL || cnt < 0)
3038 return WINED3DERR_INVALIDCALL;
3040 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3041 return WINED3D_OK;
3044 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3045 DWORD i;
3046 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3048 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3052 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3054 DWORD i = This->rev_tex_unit_map[unit];
3055 DWORD j = This->texUnitMap[stage];
3057 This->texUnitMap[stage] = unit;
3058 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3060 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3063 This->rev_tex_unit_map[unit] = stage;
3064 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3066 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3070 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3071 int i;
3073 This->fixed_function_usage_map = 0;
3074 for (i = 0; i < MAX_TEXTURES; ++i) {
3075 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3076 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3077 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3078 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3079 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3080 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3081 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3082 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3084 if (color_op == WINED3DTOP_DISABLE) {
3085 /* Not used, and disable higher stages */
3086 break;
3089 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3090 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3091 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3092 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3093 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3094 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3095 This->fixed_function_usage_map |= (1 << i);
3098 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3099 This->fixed_function_usage_map |= (1 << (i + 1));
3104 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3106 unsigned int i, tex;
3107 WORD ffu_map;
3109 device_update_fixed_function_usage_map(This);
3110 ffu_map = This->fixed_function_usage_map;
3112 if (This->max_ffp_textures == gl_info->limits.texture_stages
3113 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3115 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3117 if (!(ffu_map & 1)) continue;
3119 if (This->texUnitMap[i] != i) {
3120 device_map_stage(This, i, i);
3121 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3122 markTextureStagesDirty(This, i);
3125 return;
3128 /* Now work out the mapping */
3129 tex = 0;
3130 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3132 if (!(ffu_map & 1)) continue;
3134 if (This->texUnitMap[i] != tex) {
3135 device_map_stage(This, i, tex);
3136 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3137 markTextureStagesDirty(This, i);
3140 ++tex;
3144 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3146 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3147 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3148 unsigned int i;
3150 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3151 if (sampler_type[i] && This->texUnitMap[i] != i)
3153 device_map_stage(This, i, i);
3154 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3155 if (i < gl_info->limits.texture_stages)
3157 markTextureStagesDirty(This, i);
3163 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3164 const DWORD *vshader_sampler_tokens, DWORD unit)
3166 DWORD current_mapping = This->rev_tex_unit_map[unit];
3168 /* Not currently used */
3169 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3171 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3172 /* Used by a fragment sampler */
3174 if (!pshader_sampler_tokens) {
3175 /* No pixel shader, check fixed function */
3176 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3179 /* Pixel shader, check the shader's sampler map */
3180 return !pshader_sampler_tokens[current_mapping];
3183 /* Used by a vertex sampler */
3184 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3187 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3189 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3190 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3191 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3192 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3193 int i;
3195 if (ps) {
3196 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3198 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3199 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3200 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3203 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3204 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3205 if (vshader_sampler_type[i])
3207 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3209 /* Already mapped somewhere */
3210 continue;
3213 while (start >= 0) {
3214 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3216 device_map_stage(This, vsampler_idx, start);
3217 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3219 --start;
3220 break;
3223 --start;
3229 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3231 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3232 BOOL vs = use_vs(This->stateBlock);
3233 BOOL ps = use_ps(This->stateBlock);
3235 * Rules are:
3236 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3237 * that would be really messy and require shader recompilation
3238 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3239 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3241 if (ps) device_map_psamplers(This, gl_info);
3242 else device_map_fixed_function_samplers(This, gl_info);
3244 if (vs) device_map_vsamplers(This, ps, gl_info);
3247 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3249 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3250 This->updateStateBlock->pixelShader = pShader;
3251 This->updateStateBlock->changed.pixelShader = TRUE;
3253 /* Handle recording of state blocks */
3254 if (This->isRecordingState) {
3255 TRACE("Recording... not performing anything\n");
3258 if (This->isRecordingState) {
3259 TRACE("Recording... not performing anything\n");
3260 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3261 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3262 return WINED3D_OK;
3265 if(pShader == oldShader) {
3266 TRACE("App is setting the old pixel shader over, nothing to do\n");
3267 return WINED3D_OK;
3270 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3271 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3273 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3276 return WINED3D_OK;
3279 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3282 if (NULL == ppShader) {
3283 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3284 return WINED3DERR_INVALIDCALL;
3287 *ppShader = This->stateBlock->pixelShader;
3288 if (NULL != *ppShader) {
3289 IWineD3DPixelShader_AddRef(*ppShader);
3291 TRACE("(%p) : returning %p\n", This, *ppShader);
3292 return WINED3D_OK;
3295 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3296 IWineD3DDevice *iface,
3297 UINT start,
3298 CONST BOOL *srcData,
3299 UINT count) {
3301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3302 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3304 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3305 iface, srcData, start, count);
3307 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3309 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3310 for (i = 0; i < cnt; i++)
3311 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3313 for (i = start; i < cnt + start; ++i) {
3314 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3317 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3319 return WINED3D_OK;
3322 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3323 IWineD3DDevice *iface,
3324 UINT start,
3325 BOOL *dstData,
3326 UINT count) {
3328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3329 int cnt = min(count, MAX_CONST_B - start);
3331 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3332 iface, dstData, start, count);
3334 if (dstData == NULL || cnt < 0)
3335 return WINED3DERR_INVALIDCALL;
3337 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3338 return WINED3D_OK;
3341 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3342 IWineD3DDevice *iface,
3343 UINT start,
3344 CONST int *srcData,
3345 UINT count) {
3347 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3348 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3350 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3351 iface, srcData, start, count);
3353 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3355 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3356 for (i = 0; i < cnt; i++)
3357 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3358 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3360 for (i = start; i < cnt + start; ++i) {
3361 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3364 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3366 return WINED3D_OK;
3369 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3370 IWineD3DDevice *iface,
3371 UINT start,
3372 int *dstData,
3373 UINT count) {
3375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3376 int cnt = min(count, MAX_CONST_I - start);
3378 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3379 iface, dstData, start, count);
3381 if (dstData == NULL || cnt < 0)
3382 return WINED3DERR_INVALIDCALL;
3384 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3385 return WINED3D_OK;
3388 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3389 IWineD3DDevice *iface,
3390 UINT start,
3391 CONST float *srcData,
3392 UINT count) {
3394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3395 UINT i;
3397 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3398 iface, srcData, start, count);
3400 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3401 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3402 return WINED3DERR_INVALIDCALL;
3404 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3405 if(TRACE_ON(d3d)) {
3406 for (i = 0; i < count; i++)
3407 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3408 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3411 if (!This->isRecordingState)
3413 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3414 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3417 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3418 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3420 return WINED3D_OK;
3423 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3424 IWineD3DDevice *iface,
3425 UINT start,
3426 float *dstData,
3427 UINT count) {
3429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3430 int cnt = min(count, This->d3d_pshader_constantF - start);
3432 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3433 iface, dstData, start, count);
3435 if (dstData == NULL || cnt < 0)
3436 return WINED3DERR_INVALIDCALL;
3438 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3439 return WINED3D_OK;
3442 /* Context activation is done by the caller. */
3443 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3444 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3445 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3446 DWORD DestFVF)
3448 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3449 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3450 unsigned int i;
3451 WINED3DVIEWPORT vp;
3452 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3453 BOOL doClip;
3454 DWORD numTextures;
3456 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3458 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3461 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3463 ERR("Source has no position mask\n");
3464 return WINED3DERR_INVALIDCALL;
3467 /* We might access VBOs from this code, so hold the lock */
3468 ENTER_GL();
3470 if (dest->resource.allocatedMemory == NULL) {
3471 buffer_get_sysmem(dest);
3474 /* Get a pointer into the destination vbo(create one if none exists) and
3475 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3477 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3479 dest->flags |= WINED3D_BUFFER_CREATEBO;
3480 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3483 if (dest->buffer_object)
3485 unsigned char extrabytes = 0;
3486 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3487 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3488 * this may write 4 extra bytes beyond the area that should be written
3490 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3491 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3492 if(!dest_conv_addr) {
3493 ERR("Out of memory\n");
3494 /* Continue without storing converted vertices */
3496 dest_conv = dest_conv_addr;
3499 /* Should I clip?
3500 * a) WINED3DRS_CLIPPING is enabled
3501 * b) WINED3DVOP_CLIP is passed
3503 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3504 static BOOL warned = FALSE;
3506 * The clipping code is not quite correct. Some things need
3507 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3508 * so disable clipping for now.
3509 * (The graphics in Half-Life are broken, and my processvertices
3510 * test crashes with IDirect3DDevice3)
3511 doClip = TRUE;
3513 doClip = FALSE;
3514 if(!warned) {
3515 warned = TRUE;
3516 FIXME("Clipping is broken and disabled for now\n");
3518 } else doClip = FALSE;
3519 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3521 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3522 WINED3DTS_VIEW,
3523 &view_mat);
3524 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3525 WINED3DTS_PROJECTION,
3526 &proj_mat);
3527 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3528 WINED3DTS_WORLDMATRIX(0),
3529 &world_mat);
3531 TRACE("View mat:\n");
3532 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);
3533 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);
3534 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);
3535 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);
3537 TRACE("Proj mat:\n");
3538 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);
3539 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);
3540 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);
3541 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);
3543 TRACE("World mat:\n");
3544 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);
3545 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);
3546 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);
3547 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);
3549 /* Get the viewport */
3550 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3551 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3552 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3554 multiply_matrix(&mat,&view_mat,&world_mat);
3555 multiply_matrix(&mat,&proj_mat,&mat);
3557 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3559 for (i = 0; i < dwCount; i+= 1) {
3560 unsigned int tex_index;
3562 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3563 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3564 /* The position first */
3565 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3566 const float *p = (const float *)(element->data + i * element->stride);
3567 float x, y, z, rhw;
3568 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3570 /* Multiplication with world, view and projection matrix */
3571 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);
3572 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);
3573 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);
3574 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);
3576 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3578 /* WARNING: The following things are taken from d3d7 and were not yet checked
3579 * against d3d8 or d3d9!
3582 /* Clipping conditions: From msdn
3584 * A vertex is clipped if it does not match the following requirements
3585 * -rhw < x <= rhw
3586 * -rhw < y <= rhw
3587 * 0 < z <= rhw
3588 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3590 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3591 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3595 if( !doClip ||
3596 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3597 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3598 ( rhw > eps ) ) ) {
3600 /* "Normal" viewport transformation (not clipped)
3601 * 1) The values are divided by rhw
3602 * 2) The y axis is negative, so multiply it with -1
3603 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3604 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3605 * 4) Multiply x with Width/2 and add Width/2
3606 * 5) The same for the height
3607 * 6) Add the viewpoint X and Y to the 2D coordinates and
3608 * The minimum Z value to z
3609 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3611 * Well, basically it's simply a linear transformation into viewport
3612 * coordinates
3615 x /= rhw;
3616 y /= rhw;
3617 z /= rhw;
3619 y *= -1;
3621 x *= vp.Width / 2;
3622 y *= vp.Height / 2;
3623 z *= vp.MaxZ - vp.MinZ;
3625 x += vp.Width / 2 + vp.X;
3626 y += vp.Height / 2 + vp.Y;
3627 z += vp.MinZ;
3629 rhw = 1 / rhw;
3630 } else {
3631 /* That vertex got clipped
3632 * Contrary to OpenGL it is not dropped completely, it just
3633 * undergoes a different calculation.
3635 TRACE("Vertex got clipped\n");
3636 x += rhw;
3637 y += rhw;
3639 x /= 2;
3640 y /= 2;
3642 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3643 * outside of the main vertex buffer memory. That needs some more
3644 * investigation...
3648 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3651 ( (float *) dest_ptr)[0] = x;
3652 ( (float *) dest_ptr)[1] = y;
3653 ( (float *) dest_ptr)[2] = z;
3654 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3656 dest_ptr += 3 * sizeof(float);
3658 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3659 dest_ptr += sizeof(float);
3662 if(dest_conv) {
3663 float w = 1 / rhw;
3664 ( (float *) dest_conv)[0] = x * w;
3665 ( (float *) dest_conv)[1] = y * w;
3666 ( (float *) dest_conv)[2] = z * w;
3667 ( (float *) dest_conv)[3] = w;
3669 dest_conv += 3 * sizeof(float);
3671 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3672 dest_conv += sizeof(float);
3676 if (DestFVF & WINED3DFVF_PSIZE) {
3677 dest_ptr += sizeof(DWORD);
3678 if(dest_conv) dest_conv += sizeof(DWORD);
3680 if (DestFVF & WINED3DFVF_NORMAL) {
3681 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3682 const float *normal = (const float *)(element->data + i * element->stride);
3683 /* AFAIK this should go into the lighting information */
3684 FIXME("Didn't expect the destination to have a normal\n");
3685 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3686 if(dest_conv) {
3687 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3691 if (DestFVF & WINED3DFVF_DIFFUSE) {
3692 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3693 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3694 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3696 static BOOL warned = FALSE;
3698 if(!warned) {
3699 ERR("No diffuse color in source, but destination has one\n");
3700 warned = TRUE;
3703 *( (DWORD *) dest_ptr) = 0xffffffff;
3704 dest_ptr += sizeof(DWORD);
3706 if(dest_conv) {
3707 *( (DWORD *) dest_conv) = 0xffffffff;
3708 dest_conv += sizeof(DWORD);
3711 else {
3712 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3713 if(dest_conv) {
3714 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3715 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3716 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3717 dest_conv += sizeof(DWORD);
3722 if (DestFVF & WINED3DFVF_SPECULAR)
3724 /* What's the color value in the feedback buffer? */
3725 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3726 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3727 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3729 static BOOL warned = FALSE;
3731 if(!warned) {
3732 ERR("No specular color in source, but destination has one\n");
3733 warned = TRUE;
3736 *( (DWORD *) dest_ptr) = 0xFF000000;
3737 dest_ptr += sizeof(DWORD);
3739 if(dest_conv) {
3740 *( (DWORD *) dest_conv) = 0xFF000000;
3741 dest_conv += sizeof(DWORD);
3744 else {
3745 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3746 if(dest_conv) {
3747 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3748 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3749 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3750 dest_conv += sizeof(DWORD);
3755 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3756 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3757 const float *tex_coord = (const float *)(element->data + i * element->stride);
3758 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3760 ERR("No source texture, but destination requests one\n");
3761 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3762 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3764 else {
3765 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3766 if(dest_conv) {
3767 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3773 if(dest_conv) {
3774 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3775 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3776 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3777 dwCount * get_flexible_vertex_size(DestFVF),
3778 dest_conv_addr));
3779 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3780 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3783 LEAVE_GL();
3785 return WINED3D_OK;
3787 #undef copy_and_next
3789 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3790 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3791 DWORD DestFVF)
3793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3794 struct wined3d_stream_info stream_info;
3795 struct wined3d_context *context;
3796 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3797 HRESULT hr;
3799 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3801 if(pVertexDecl) {
3802 ERR("Output vertex declaration not implemented yet\n");
3805 /* Need any context to write to the vbo. */
3806 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
3808 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3809 * control the streamIsUP flag, thus restore it afterwards.
3811 This->stateBlock->streamIsUP = FALSE;
3812 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3813 This->stateBlock->streamIsUP = streamWasUP;
3815 if(vbo || SrcStartIndex) {
3816 unsigned int i;
3817 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3818 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3820 * Also get the start index in, but only loop over all elements if there's something to add at all.
3822 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3824 struct wined3d_stream_info_element *e;
3826 if (!(stream_info.use_map & (1 << i))) continue;
3828 e = &stream_info.elements[i];
3829 if (e->buffer_object)
3831 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3832 e->buffer_object = 0;
3833 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3834 ENTER_GL();
3835 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3836 vb->buffer_object = 0;
3837 LEAVE_GL();
3839 if (e->data) e->data += e->stride * SrcStartIndex;
3843 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3844 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3846 context_release(context);
3848 return hr;
3851 /*****
3852 * Get / Set Texture Stage States
3853 * TODO: Verify against dx9 definitions
3854 *****/
3855 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3857 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3858 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3860 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3862 if (Stage >= gl_info->limits.texture_stages)
3864 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3865 Stage, gl_info->limits.texture_stages - 1);
3866 return WINED3D_OK;
3869 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3870 This->updateStateBlock->textureState[Stage][Type] = Value;
3872 if (This->isRecordingState) {
3873 TRACE("Recording... not performing anything\n");
3874 return WINED3D_OK;
3877 /* Checked after the assignments to allow proper stateblock recording */
3878 if(oldValue == Value) {
3879 TRACE("App is setting the old value over, nothing to do\n");
3880 return WINED3D_OK;
3883 if(Stage > This->stateBlock->lowest_disabled_stage &&
3884 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3885 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3886 * Changes in other states are important on disabled stages too
3888 return WINED3D_OK;
3891 if(Type == WINED3DTSS_COLOROP) {
3892 unsigned int i;
3894 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3895 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3896 * they have to be disabled
3898 * The current stage is dirtified below.
3900 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3901 TRACE("Additionally dirtifying stage %u\n", i);
3902 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3904 This->stateBlock->lowest_disabled_stage = Stage;
3905 TRACE("New lowest disabled: %u\n", Stage);
3906 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3907 /* Previously disabled stage enabled. Stages above it may need enabling
3908 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3909 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3911 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3914 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
3916 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3917 break;
3919 TRACE("Additionally dirtifying stage %u due to enable\n", i);
3920 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3922 This->stateBlock->lowest_disabled_stage = i;
3923 TRACE("New lowest disabled: %u\n", i);
3927 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3929 return WINED3D_OK;
3932 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3934 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3935 *pValue = This->updateStateBlock->textureState[Stage][Type];
3936 return WINED3D_OK;
3939 /*****
3940 * Get / Set Texture
3941 *****/
3942 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
3943 DWORD stage, IWineD3DBaseTexture *texture)
3945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3946 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3947 IWineD3DBaseTexture *prev;
3949 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
3951 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
3952 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3954 /* Windows accepts overflowing this array... we do not. */
3955 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
3957 WARN("Ignoring invalid stage %u.\n", stage);
3958 return WINED3D_OK;
3961 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
3962 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
3964 WARN("Rejecting attempt to set scratch texture.\n");
3965 return WINED3DERR_INVALIDCALL;
3968 This->updateStateBlock->changed.textures |= 1 << stage;
3970 prev = This->updateStateBlock->textures[stage];
3971 TRACE("Previous texture %p.\n", prev);
3973 if (texture == prev)
3975 TRACE("App is setting the same texture again, nothing to do.\n");
3976 return WINED3D_OK;
3979 TRACE("Setting new texture to %p.\n", texture);
3980 This->updateStateBlock->textures[stage] = texture;
3982 if (This->isRecordingState)
3984 TRACE("Recording... not performing anything\n");
3986 if (texture) IWineD3DBaseTexture_AddRef(texture);
3987 if (prev) IWineD3DBaseTexture_Release(prev);
3989 return WINED3D_OK;
3992 if (texture)
3994 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
3995 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
3996 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
3998 IWineD3DBaseTexture_AddRef(texture);
4000 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4002 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4005 if (!prev && stage < gl_info->limits.texture_stages)
4007 /* The source arguments for color and alpha ops have different
4008 * meanings when a NULL texture is bound, so the COLOROP and
4009 * ALPHAOP have to be dirtified. */
4010 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4011 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4014 if (bind_count == 1) t->baseTexture.sampler = stage;
4017 if (prev)
4019 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4020 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4022 IWineD3DBaseTexture_Release(prev);
4024 if (!texture && stage < gl_info->limits.texture_stages)
4026 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4027 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4030 if (bind_count && t->baseTexture.sampler == stage)
4032 unsigned int i;
4034 /* Search for other stages the texture is bound to. Shouldn't
4035 * happen if applications bind textures to a single stage only. */
4036 TRACE("Searching for other stages the texture is bound to.\n");
4037 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4039 if (This->updateStateBlock->textures[i] == prev)
4041 TRACE("Texture is also bound to stage %u.\n", i);
4042 t->baseTexture.sampler = i;
4043 break;
4049 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4051 return WINED3D_OK;
4054 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4057 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4059 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4060 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4063 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4064 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4065 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4068 *ppTexture=This->stateBlock->textures[Stage];
4069 if (*ppTexture)
4070 IWineD3DBaseTexture_AddRef(*ppTexture);
4072 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4074 return WINED3D_OK;
4077 /*****
4078 * Get Back Buffer
4079 *****/
4080 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4081 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4083 IWineD3DSwapChain *swapchain;
4084 HRESULT hr;
4086 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4087 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4089 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4090 if (FAILED(hr))
4092 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4093 return hr;
4096 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4097 IWineD3DSwapChain_Release(swapchain);
4098 if (FAILED(hr))
4100 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4101 return hr;
4104 return WINED3D_OK;
4107 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4109 WARN("(%p) : stub, calling idirect3d for now\n", This);
4110 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4113 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4114 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4115 IWineD3DSwapChain *swapChain;
4116 HRESULT hr;
4118 if(iSwapChain > 0) {
4119 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4120 if (hr == WINED3D_OK) {
4121 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4122 IWineD3DSwapChain_Release(swapChain);
4123 } else {
4124 FIXME("(%p) Error getting display mode\n", This);
4126 } else {
4127 /* Don't read the real display mode,
4128 but return the stored mode instead. X11 can't change the color
4129 depth, and some apps are pretty angry if they SetDisplayMode from
4130 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4132 Also don't relay to the swapchain because with ddraw it's possible
4133 that there isn't a swapchain at all */
4134 pMode->Width = This->ddraw_width;
4135 pMode->Height = This->ddraw_height;
4136 pMode->Format = This->ddraw_format;
4137 pMode->RefreshRate = 0;
4138 hr = WINED3D_OK;
4141 return hr;
4144 /*****
4145 * Stateblock related functions
4146 *****/
4148 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4150 IWineD3DStateBlock *stateblock;
4151 HRESULT hr;
4153 TRACE("(%p)\n", This);
4155 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4157 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4158 if (FAILED(hr)) return hr;
4160 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4161 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4162 This->isRecordingState = TRUE;
4164 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4166 return WINED3D_OK;
4169 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4171 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4173 if (!This->isRecordingState) {
4174 WARN("(%p) not recording! returning error\n", This);
4175 *ppStateBlock = NULL;
4176 return WINED3DERR_INVALIDCALL;
4179 stateblock_init_contained_states(object);
4181 *ppStateBlock = (IWineD3DStateBlock*) object;
4182 This->isRecordingState = FALSE;
4183 This->updateStateBlock = This->stateBlock;
4184 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4185 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4186 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4187 return WINED3D_OK;
4190 /*****
4191 * Scene related functions
4192 *****/
4193 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4194 /* At the moment we have no need for any functionality at the beginning
4195 of a scene */
4196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4197 TRACE("(%p)\n", This);
4199 if(This->inScene) {
4200 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4201 return WINED3DERR_INVALIDCALL;
4203 This->inScene = TRUE;
4204 return WINED3D_OK;
4207 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4210 struct wined3d_context *context;
4212 TRACE("(%p)\n", This);
4214 if(!This->inScene) {
4215 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4216 return WINED3DERR_INVALIDCALL;
4219 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4220 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4221 wglFlush();
4222 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4223 * fails. */
4224 context_release(context);
4226 This->inScene = FALSE;
4227 return WINED3D_OK;
4230 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4231 const RECT *pSourceRect, const RECT *pDestRect,
4232 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4234 IWineD3DSwapChain *swapChain = NULL;
4235 int i;
4236 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4238 TRACE("iface %p.\n", iface);
4240 for(i = 0 ; i < swapchains ; i ++) {
4242 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4243 TRACE("presentinng chain %d, %p\n", i, swapChain);
4244 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4245 IWineD3DSwapChain_Release(swapChain);
4248 return WINED3D_OK;
4251 /* Not called from the VTable (internal subroutine) */
4252 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4253 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4254 float Z, DWORD Stencil) {
4255 GLbitfield glMask = 0;
4256 unsigned int i;
4257 WINED3DRECT curRect;
4258 RECT vp_rect;
4259 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4260 UINT drawable_width, drawable_height;
4261 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4262 struct wined3d_context *context;
4264 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4265 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4266 * for the cleared parts, and the untouched parts.
4268 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4269 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4270 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4271 * checking all this if the dest surface is in the drawable anyway.
4273 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4274 while(1) {
4275 if(vp->X != 0 || vp->Y != 0 ||
4276 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4277 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4278 break;
4280 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4281 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4282 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4283 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4284 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4285 break;
4287 if(Count > 0 && pRects && (
4288 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4289 pRects[0].x2 < target->currentDesc.Width ||
4290 pRects[0].y2 < target->currentDesc.Height)) {
4291 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4292 break;
4294 break;
4298 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4300 target->get_drawable_size(context, &drawable_width, &drawable_height);
4302 ENTER_GL();
4304 /* Only set the values up once, as they are not changing */
4305 if (Flags & WINED3DCLEAR_STENCIL) {
4306 glClearStencil(Stencil);
4307 checkGLcall("glClearStencil");
4308 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4309 glStencilMask(0xFFFFFFFF);
4312 if (Flags & WINED3DCLEAR_ZBUFFER) {
4313 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4314 glDepthMask(GL_TRUE);
4315 glClearDepth(Z);
4316 checkGLcall("glClearDepth");
4317 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4318 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4320 if (vp->X != 0 || vp->Y != 0 ||
4321 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4322 surface_load_ds_location(This->stencilBufferTarget, context, location);
4324 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4325 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4326 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4327 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4328 surface_load_ds_location(This->stencilBufferTarget, context, location);
4330 else if (Count > 0 && pRects && (
4331 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4332 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4333 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4334 surface_load_ds_location(This->stencilBufferTarget, context, location);
4338 if (Flags & WINED3DCLEAR_TARGET) {
4339 TRACE("Clearing screen with glClear to color %x\n", Color);
4340 glClearColor(D3DCOLOR_R(Color),
4341 D3DCOLOR_G(Color),
4342 D3DCOLOR_B(Color),
4343 D3DCOLOR_A(Color));
4344 checkGLcall("glClearColor");
4346 /* Clear ALL colors! */
4347 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4348 glMask = glMask | GL_COLOR_BUFFER_BIT;
4351 vp_rect.left = vp->X;
4352 vp_rect.top = vp->Y;
4353 vp_rect.right = vp->X + vp->Width;
4354 vp_rect.bottom = vp->Y + vp->Height;
4355 if (!(Count > 0 && pRects)) {
4356 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4357 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4359 if (context->render_offscreen)
4361 glScissor(vp_rect.left, vp_rect.top,
4362 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4363 } else {
4364 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4365 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4367 checkGLcall("glScissor");
4368 glClear(glMask);
4369 checkGLcall("glClear");
4370 } else {
4371 /* Now process each rect in turn */
4372 for (i = 0; i < Count; i++) {
4373 /* Note gl uses lower left, width/height */
4374 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4375 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4376 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4378 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4379 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4380 curRect.x1, (target->currentDesc.Height - curRect.y2),
4381 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4383 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4384 * The rectangle is not cleared, no error is returned, but further rectanlges are
4385 * still cleared if they are valid
4387 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4388 TRACE("Rectangle with negative dimensions, ignoring\n");
4389 continue;
4392 if (context->render_offscreen)
4394 glScissor(curRect.x1, curRect.y1,
4395 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4396 } else {
4397 glScissor(curRect.x1, drawable_height - curRect.y2,
4398 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4400 checkGLcall("glScissor");
4402 glClear(glMask);
4403 checkGLcall("glClear");
4407 /* Restore the old values (why..?) */
4408 if (Flags & WINED3DCLEAR_STENCIL) {
4409 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4411 if (Flags & WINED3DCLEAR_TARGET) {
4412 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4413 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4414 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4415 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4416 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4418 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4419 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4421 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4423 if (Flags & WINED3DCLEAR_ZBUFFER) {
4424 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4425 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4426 surface_modify_ds_location(This->stencilBufferTarget, location);
4429 LEAVE_GL();
4431 wglFlush(); /* Flush to ensure ordering across contexts. */
4433 context_release(context);
4435 return WINED3D_OK;
4438 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4439 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4441 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4443 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4444 Count, pRects, Flags, Color, Z, Stencil);
4446 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4447 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4448 /* TODO: What about depth stencil buffers without stencil bits? */
4449 return WINED3DERR_INVALIDCALL;
4452 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4455 /*****
4456 * Drawing functions
4457 *****/
4459 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4460 WINED3DPRIMITIVETYPE primitive_type)
4462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4464 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4466 This->updateStateBlock->changed.primitive_type = TRUE;
4467 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4470 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4471 WINED3DPRIMITIVETYPE *primitive_type)
4473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4475 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4477 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4479 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4482 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4486 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4488 if(!This->stateBlock->vertexDecl) {
4489 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4490 return WINED3DERR_INVALIDCALL;
4493 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4494 if(This->stateBlock->streamIsUP) {
4495 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4496 This->stateBlock->streamIsUP = FALSE;
4499 if(This->stateBlock->loadBaseVertexIndex != 0) {
4500 This->stateBlock->loadBaseVertexIndex = 0;
4501 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4503 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4504 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4505 return WINED3D_OK;
4508 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4511 UINT idxStride = 2;
4512 IWineD3DBuffer *pIB;
4513 GLuint vbo;
4515 pIB = This->stateBlock->pIndexData;
4516 if (!pIB) {
4517 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4518 * without an index buffer set. (The first time at least...)
4519 * D3D8 simply dies, but I doubt it can do much harm to return
4520 * D3DERR_INVALIDCALL there as well. */
4521 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4522 return WINED3DERR_INVALIDCALL;
4525 if(!This->stateBlock->vertexDecl) {
4526 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4527 return WINED3DERR_INVALIDCALL;
4530 if(This->stateBlock->streamIsUP) {
4531 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4532 This->stateBlock->streamIsUP = FALSE;
4534 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4536 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4538 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4539 idxStride = 2;
4540 } else {
4541 idxStride = 4;
4544 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4545 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4546 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4549 drawPrimitive(iface, index_count, startIndex, idxStride,
4550 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4552 return WINED3D_OK;
4555 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4556 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4559 IWineD3DBuffer *vb;
4561 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4562 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4564 if(!This->stateBlock->vertexDecl) {
4565 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4566 return WINED3DERR_INVALIDCALL;
4569 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4570 vb = This->stateBlock->streamSource[0];
4571 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4572 if (vb) IWineD3DBuffer_Release(vb);
4573 This->stateBlock->streamOffset[0] = 0;
4574 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4575 This->stateBlock->streamIsUP = TRUE;
4576 This->stateBlock->loadBaseVertexIndex = 0;
4578 /* TODO: Only mark dirty if drawing from a different UP address */
4579 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4581 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4583 /* MSDN specifies stream zero settings must be set to NULL */
4584 This->stateBlock->streamStride[0] = 0;
4585 This->stateBlock->streamSource[0] = NULL;
4587 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4588 * the new stream sources or use UP drawing again
4590 return WINED3D_OK;
4593 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4594 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4595 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4597 int idxStride;
4598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4599 IWineD3DBuffer *vb;
4600 IWineD3DBuffer *ib;
4602 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4603 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4605 if(!This->stateBlock->vertexDecl) {
4606 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4607 return WINED3DERR_INVALIDCALL;
4610 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4611 idxStride = 2;
4612 } else {
4613 idxStride = 4;
4616 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4617 vb = This->stateBlock->streamSource[0];
4618 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4619 if (vb) IWineD3DBuffer_Release(vb);
4620 This->stateBlock->streamIsUP = TRUE;
4621 This->stateBlock->streamOffset[0] = 0;
4622 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4624 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4625 This->stateBlock->baseVertexIndex = 0;
4626 This->stateBlock->loadBaseVertexIndex = 0;
4627 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4628 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4629 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4631 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4633 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4634 This->stateBlock->streamSource[0] = NULL;
4635 This->stateBlock->streamStride[0] = 0;
4636 ib = This->stateBlock->pIndexData;
4637 if(ib) {
4638 IWineD3DBuffer_Release(ib);
4639 This->stateBlock->pIndexData = NULL;
4641 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4642 * SetStreamSource to specify a vertex buffer
4645 return WINED3D_OK;
4648 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4649 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4653 /* Mark the state dirty until we have nicer tracking
4654 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4655 * that value.
4657 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4658 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4659 This->stateBlock->baseVertexIndex = 0;
4660 This->up_strided = DrawPrimStrideData;
4661 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4662 This->up_strided = NULL;
4663 return WINED3D_OK;
4666 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4667 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4668 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4670 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4671 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4673 /* Mark the state dirty until we have nicer tracking
4674 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4675 * that value.
4677 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4678 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4679 This->stateBlock->streamIsUP = TRUE;
4680 This->stateBlock->baseVertexIndex = 0;
4681 This->up_strided = DrawPrimStrideData;
4682 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4683 This->up_strided = NULL;
4684 return WINED3D_OK;
4687 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4688 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4689 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4691 WINED3DLOCKED_BOX src;
4692 WINED3DLOCKED_BOX dst;
4693 HRESULT hr;
4695 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4696 iface, pSourceVolume, pDestinationVolume);
4698 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4699 * dirtification to improve loading performance.
4701 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4702 if(FAILED(hr)) return hr;
4703 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4704 if(FAILED(hr)) {
4705 IWineD3DVolume_UnlockBox(pSourceVolume);
4706 return hr;
4709 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4711 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4712 if(FAILED(hr)) {
4713 IWineD3DVolume_UnlockBox(pSourceVolume);
4714 } else {
4715 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4717 return hr;
4720 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4721 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4723 unsigned int level_count, i;
4724 WINED3DRESOURCETYPE type;
4725 HRESULT hr;
4727 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4729 /* Verify that the source and destination textures are non-NULL. */
4730 if (!src_texture || !dst_texture)
4732 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4733 return WINED3DERR_INVALIDCALL;
4736 if (src_texture == dst_texture)
4738 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4739 return WINED3DERR_INVALIDCALL;
4742 /* Verify that the source and destination textures are the same type. */
4743 type = IWineD3DBaseTexture_GetType(src_texture);
4744 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4746 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4747 return WINED3DERR_INVALIDCALL;
4750 /* Check that both textures have the identical numbers of levels. */
4751 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4752 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4754 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4755 return WINED3DERR_INVALIDCALL;
4758 /* Make sure that the destination texture is loaded. */
4759 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4761 /* Update every surface level of the texture. */
4762 switch (type)
4764 case WINED3DRTYPE_TEXTURE:
4766 IWineD3DSurface *src_surface;
4767 IWineD3DSurface *dst_surface;
4769 for (i = 0; i < level_count; ++i)
4771 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4772 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4773 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4774 IWineD3DSurface_Release(dst_surface);
4775 IWineD3DSurface_Release(src_surface);
4776 if (FAILED(hr))
4778 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4779 return hr;
4782 break;
4785 case WINED3DRTYPE_CUBETEXTURE:
4787 IWineD3DSurface *src_surface;
4788 IWineD3DSurface *dst_surface;
4789 WINED3DCUBEMAP_FACES face;
4791 for (i = 0; i < level_count; ++i)
4793 /* Update each cube face. */
4794 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4796 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4797 face, i, &src_surface);
4798 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4799 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4800 face, i, &dst_surface);
4801 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4802 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4803 IWineD3DSurface_Release(dst_surface);
4804 IWineD3DSurface_Release(src_surface);
4805 if (FAILED(hr))
4807 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4808 return hr;
4812 break;
4815 case WINED3DRTYPE_VOLUMETEXTURE:
4817 IWineD3DVolume *src_volume;
4818 IWineD3DVolume *dst_volume;
4820 for (i = 0; i < level_count; ++i)
4822 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4823 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4824 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4825 IWineD3DVolume_Release(dst_volume);
4826 IWineD3DVolume_Release(src_volume);
4827 if (FAILED(hr))
4829 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4830 return hr;
4833 break;
4836 default:
4837 FIXME("Unsupported texture type %#x.\n", type);
4838 return WINED3DERR_INVALIDCALL;
4841 return WINED3D_OK;
4844 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4845 IWineD3DSwapChain *swapChain;
4846 HRESULT hr;
4847 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4848 if(hr == WINED3D_OK) {
4849 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4850 IWineD3DSwapChain_Release(swapChain);
4852 return hr;
4855 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4857 IWineD3DBaseTextureImpl *texture;
4858 DWORD i;
4860 TRACE("(%p) : %p\n", This, pNumPasses);
4862 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4863 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
4864 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4865 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4867 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
4868 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4869 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4872 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
4873 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
4875 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
4876 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4877 return E_FAIL;
4879 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
4880 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4881 return E_FAIL;
4883 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
4884 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
4885 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4886 return E_FAIL;
4890 /* return a sensible default */
4891 *pNumPasses = 1;
4893 TRACE("returning D3D_OK\n");
4894 return WINED3D_OK;
4897 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
4899 int i;
4901 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4903 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
4904 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
4905 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
4907 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
4912 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4914 int j;
4915 UINT NewSize;
4916 PALETTEENTRY **palettes;
4918 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4920 if (PaletteNumber >= MAX_PALETTES) {
4921 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4922 return WINED3DERR_INVALIDCALL;
4925 if (PaletteNumber >= This->NumberOfPalettes) {
4926 NewSize = This->NumberOfPalettes;
4927 do {
4928 NewSize *= 2;
4929 } while(PaletteNumber >= NewSize);
4930 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
4931 if (!palettes) {
4932 ERR("Out of memory!\n");
4933 return E_OUTOFMEMORY;
4935 This->palettes = palettes;
4936 This->NumberOfPalettes = NewSize;
4939 if (!This->palettes[PaletteNumber]) {
4940 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
4941 if (!This->palettes[PaletteNumber]) {
4942 ERR("Out of memory!\n");
4943 return E_OUTOFMEMORY;
4947 for (j = 0; j < 256; ++j) {
4948 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4949 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4950 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4951 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4953 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
4954 TRACE("(%p) : returning\n", This);
4955 return WINED3D_OK;
4958 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4960 int j;
4961 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4962 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
4963 /* What happens in such situation isn't documented; Native seems to silently abort
4964 on such conditions. Return Invalid Call. */
4965 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
4966 return WINED3DERR_INVALIDCALL;
4968 for (j = 0; j < 256; ++j) {
4969 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4970 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4971 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4972 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4974 TRACE("(%p) : returning\n", This);
4975 return WINED3D_OK;
4978 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4980 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4981 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
4982 (tested with reference rasterizer). Return Invalid Call. */
4983 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
4984 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
4985 return WINED3DERR_INVALIDCALL;
4987 /*TODO: stateblocks */
4988 if (This->currentPalette != PaletteNumber) {
4989 This->currentPalette = PaletteNumber;
4990 dirtify_p8_texture_samplers(This);
4992 TRACE("(%p) : returning\n", This);
4993 return WINED3D_OK;
4996 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4998 if (PaletteNumber == NULL) {
4999 WARN("(%p) : returning Invalid Call\n", This);
5000 return WINED3DERR_INVALIDCALL;
5002 /*TODO: stateblocks */
5003 *PaletteNumber = This->currentPalette;
5004 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5005 return WINED3D_OK;
5008 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5010 static BOOL warned;
5011 if (!warned)
5013 FIXME("(%p) : stub\n", This);
5014 warned = TRUE;
5017 This->softwareVertexProcessing = bSoftware;
5018 return WINED3D_OK;
5022 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5024 static BOOL warned;
5025 if (!warned)
5027 FIXME("(%p) : stub\n", This);
5028 warned = TRUE;
5030 return This->softwareVertexProcessing;
5033 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5034 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5036 IWineD3DSwapChain *swapchain;
5037 HRESULT hr;
5039 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5040 iface, swapchain_idx, raster_status);
5042 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5043 if (FAILED(hr))
5045 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5046 return hr;
5049 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5050 IWineD3DSwapChain_Release(swapchain);
5051 if (FAILED(hr))
5053 WARN("Failed to get raster status, hr %#x.\n", hr);
5054 return hr;
5057 return WINED3D_OK;
5060 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5062 static BOOL warned;
5063 if(nSegments != 0.0f) {
5064 if (!warned)
5066 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5067 warned = TRUE;
5070 return WINED3D_OK;
5073 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5075 static BOOL warned;
5076 if (!warned)
5078 FIXME("iface %p stub!\n", iface);
5079 warned = TRUE;
5081 return 0.0f;
5084 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5086 /** TODO: remove casts to IWineD3DSurfaceImpl
5087 * NOTE: move code to surface to accomplish this
5088 ****************************************/
5089 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5090 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5091 int srcWidth, srcHeight;
5092 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5093 WINED3DFORMAT destFormat, srcFormat;
5094 UINT destSize;
5095 int srcLeft, destLeft, destTop;
5096 WINED3DPOOL srcPool, destPool;
5097 int offset = 0;
5098 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5099 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5100 GLenum dummy;
5101 DWORD sampler;
5102 int bpp;
5103 CONVERT_TYPES convert = NO_CONVERSION;
5104 struct wined3d_context *context;
5106 WINED3DSURFACE_DESC winedesc;
5108 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5110 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5111 srcSurfaceWidth = winedesc.width;
5112 srcSurfaceHeight = winedesc.height;
5113 srcPool = winedesc.pool;
5114 srcFormat = winedesc.format;
5116 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5117 destSurfaceWidth = winedesc.width;
5118 destSurfaceHeight = winedesc.height;
5119 destPool = winedesc.pool;
5120 destFormat = winedesc.format;
5121 destSize = winedesc.size;
5123 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5124 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5125 return WINED3DERR_INVALIDCALL;
5128 /* This call loads the opengl surface directly, instead of copying the surface to the
5129 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5130 * copy in sysmem and use regular surface loading.
5132 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5133 if(convert != NO_CONVERSION) {
5134 return IWineD3DSurface_BltFast(pDestinationSurface,
5135 pDestPoint ? pDestPoint->x : 0,
5136 pDestPoint ? pDestPoint->y : 0,
5137 pSourceSurface, pSourceRect, 0);
5140 if (destFormat == WINED3DFMT_UNKNOWN) {
5141 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5142 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5144 /* Get the update surface description */
5145 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5148 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5150 ENTER_GL();
5151 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5152 checkGLcall("glActiveTextureARB");
5153 LEAVE_GL();
5155 /* Make sure the surface is loaded and up to date */
5156 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5157 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5159 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5160 dst_format_desc = dst_impl->resource.format_desc;
5162 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5163 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5164 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5165 srcLeft = pSourceRect ? pSourceRect->left : 0;
5166 destLeft = pDestPoint ? pDestPoint->x : 0;
5167 destTop = pDestPoint ? pDestPoint->y : 0;
5170 /* This function doesn't support compressed textures
5171 the pitch is just bytesPerPixel * width */
5172 if(srcWidth != srcSurfaceWidth || srcLeft ){
5173 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5174 offset += srcLeft * src_format_desc->byte_count;
5175 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5177 /* TODO DXT formats */
5179 if(pSourceRect != NULL && pSourceRect->top != 0){
5180 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5182 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5183 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5184 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5186 /* Sanity check */
5187 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5189 /* need to lock the surface to get the data */
5190 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5193 ENTER_GL();
5195 /* TODO: Cube and volume support */
5196 if(rowoffset != 0){
5197 /* not a whole row so we have to do it a line at a time */
5198 int j;
5200 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5201 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5203 for (j = destTop; j < (srcHeight + destTop); ++j)
5205 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5206 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5207 data += rowoffset;
5210 } else { /* Full width, so just write out the whole texture */
5211 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5213 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5215 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5217 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5218 FIXME("Updating part of a compressed texture is not supported.\n");
5220 if (destFormat != srcFormat)
5222 FIXME("Updating mixed format compressed textures is not supported.\n");
5224 else
5226 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5227 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5230 else
5232 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5233 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5236 checkGLcall("glTexSubImage2D");
5238 LEAVE_GL();
5239 context_release(context);
5241 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5242 sampler = This->rev_tex_unit_map[0];
5243 if (sampler != WINED3D_UNMAPPED_STAGE)
5245 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5248 return WINED3D_OK;
5251 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5253 struct WineD3DRectPatch *patch;
5254 GLenum old_primitive_type;
5255 unsigned int i;
5256 struct list *e;
5257 BOOL found;
5258 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5260 if(!(Handle || pRectPatchInfo)) {
5261 /* TODO: Write a test for the return value, thus the FIXME */
5262 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5263 return WINED3DERR_INVALIDCALL;
5266 if(Handle) {
5267 i = PATCHMAP_HASHFUNC(Handle);
5268 found = FALSE;
5269 LIST_FOR_EACH(e, &This->patches[i]) {
5270 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5271 if(patch->Handle == Handle) {
5272 found = TRUE;
5273 break;
5277 if(!found) {
5278 TRACE("Patch does not exist. Creating a new one\n");
5279 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5280 patch->Handle = Handle;
5281 list_add_head(&This->patches[i], &patch->entry);
5282 } else {
5283 TRACE("Found existing patch %p\n", patch);
5285 } else {
5286 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5287 * attributes we have to tesselate, read back, and draw. This needs a patch
5288 * management structure instance. Create one.
5290 * A possible improvement is to check if a vertex shader is used, and if not directly
5291 * draw the patch.
5293 FIXME("Drawing an uncached patch. This is slow\n");
5294 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5297 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5298 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5299 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5300 HRESULT hr;
5301 TRACE("Tesselation density or patch info changed, retesselating\n");
5303 if(pRectPatchInfo) {
5304 patch->RectPatchInfo = *pRectPatchInfo;
5306 patch->numSegs[0] = pNumSegs[0];
5307 patch->numSegs[1] = pNumSegs[1];
5308 patch->numSegs[2] = pNumSegs[2];
5309 patch->numSegs[3] = pNumSegs[3];
5311 hr = tesselate_rectpatch(This, patch);
5312 if(FAILED(hr)) {
5313 WARN("Patch tesselation failed\n");
5315 /* Do not release the handle to store the params of the patch */
5316 if(!Handle) {
5317 HeapFree(GetProcessHeap(), 0, patch);
5319 return hr;
5323 This->currentPatch = patch;
5324 old_primitive_type = This->stateBlock->gl_primitive_type;
5325 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5326 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5327 This->stateBlock->gl_primitive_type = old_primitive_type;
5328 This->currentPatch = NULL;
5330 /* Destroy uncached patches */
5331 if(!Handle) {
5332 HeapFree(GetProcessHeap(), 0, patch->mem);
5333 HeapFree(GetProcessHeap(), 0, patch);
5335 return WINED3D_OK;
5338 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5339 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5341 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5342 iface, handle, segment_count, patch_info);
5344 return WINED3D_OK;
5347 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5349 int i;
5350 struct WineD3DRectPatch *patch;
5351 struct list *e;
5352 TRACE("(%p) Handle(%d)\n", This, Handle);
5354 i = PATCHMAP_HASHFUNC(Handle);
5355 LIST_FOR_EACH(e, &This->patches[i]) {
5356 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5357 if(patch->Handle == Handle) {
5358 TRACE("Deleting patch %p\n", patch);
5359 list_remove(&patch->entry);
5360 HeapFree(GetProcessHeap(), 0, patch->mem);
5361 HeapFree(GetProcessHeap(), 0, patch);
5362 return WINED3D_OK;
5366 /* TODO: Write a test for the return value */
5367 FIXME("Attempt to destroy nonexistent patch\n");
5368 return WINED3DERR_INVALIDCALL;
5371 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5372 HRESULT hr;
5373 IWineD3DSwapChain *swapchain;
5375 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5376 if (SUCCEEDED(hr)) {
5377 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5378 return swapchain;
5381 return NULL;
5384 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5385 const WINED3DRECT *rect, const float color[4])
5387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5388 struct wined3d_context *context;
5390 if (rect) IWineD3DSurface_LoadLocation(surface, SFLAG_INDRAWABLE, NULL);
5391 IWineD3DSurface_ModifyLocation(surface, SFLAG_INDRAWABLE, TRUE);
5393 if (!surface_is_offscreen(surface))
5395 TRACE("Surface %p is onscreen\n", surface);
5397 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5398 ENTER_GL();
5399 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5400 context_set_draw_buffer(context, surface_get_gl_buffer(surface));
5402 else
5404 TRACE("Surface %p is offscreen\n", surface);
5406 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5407 ENTER_GL();
5408 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5409 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5410 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5413 if (rect) {
5414 glEnable(GL_SCISSOR_TEST);
5415 if(surface_is_offscreen(surface)) {
5416 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5417 } else {
5418 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5419 rect->x2 - rect->x1, rect->y2 - rect->y1);
5421 checkGLcall("glScissor");
5422 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5423 } else {
5424 glDisable(GL_SCISSOR_TEST);
5426 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5428 glDisable(GL_BLEND);
5429 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5431 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5432 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5434 glClearColor(color[0], color[1], color[2], color[3]);
5435 glClear(GL_COLOR_BUFFER_BIT);
5436 checkGLcall("glClear");
5438 LEAVE_GL();
5440 wglFlush(); /* Flush to ensure ordering across contexts. */
5442 context_release(context);
5445 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5446 unsigned int r, g, b, a;
5447 DWORD ret;
5449 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5450 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5451 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5452 return color;
5454 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5456 a = (color & 0xff000000) >> 24;
5457 r = (color & 0x00ff0000) >> 16;
5458 g = (color & 0x0000ff00) >> 8;
5459 b = (color & 0x000000ff) >> 0;
5461 switch(destfmt)
5463 case WINED3DFMT_B5G6R5_UNORM:
5464 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5465 r = (r * 32) / 256;
5466 g = (g * 64) / 256;
5467 b = (b * 32) / 256;
5468 ret = r << 11;
5469 ret |= g << 5;
5470 ret |= b;
5471 TRACE("Returning %08x\n", ret);
5472 return ret;
5474 case WINED3DFMT_B5G5R5X1_UNORM:
5475 case WINED3DFMT_B5G5R5A1_UNORM:
5476 a = (a * 2) / 256;
5477 r = (r * 32) / 256;
5478 g = (g * 32) / 256;
5479 b = (b * 32) / 256;
5480 ret = a << 15;
5481 ret |= r << 10;
5482 ret |= g << 5;
5483 ret |= b << 0;
5484 TRACE("Returning %08x\n", ret);
5485 return ret;
5487 case WINED3DFMT_A8_UNORM:
5488 TRACE("Returning %08x\n", a);
5489 return a;
5491 case WINED3DFMT_B4G4R4X4_UNORM:
5492 case WINED3DFMT_B4G4R4A4_UNORM:
5493 a = (a * 16) / 256;
5494 r = (r * 16) / 256;
5495 g = (g * 16) / 256;
5496 b = (b * 16) / 256;
5497 ret = a << 12;
5498 ret |= r << 8;
5499 ret |= g << 4;
5500 ret |= b << 0;
5501 TRACE("Returning %08x\n", ret);
5502 return ret;
5504 case WINED3DFMT_B2G3R3_UNORM:
5505 r = (r * 8) / 256;
5506 g = (g * 8) / 256;
5507 b = (b * 4) / 256;
5508 ret = r << 5;
5509 ret |= g << 2;
5510 ret |= b << 0;
5511 TRACE("Returning %08x\n", ret);
5512 return ret;
5514 case WINED3DFMT_R8G8B8X8_UNORM:
5515 case WINED3DFMT_R8G8B8A8_UNORM:
5516 ret = a << 24;
5517 ret |= b << 16;
5518 ret |= g << 8;
5519 ret |= r << 0;
5520 TRACE("Returning %08x\n", ret);
5521 return ret;
5523 case WINED3DFMT_B10G10R10A2_UNORM:
5524 a = (a * 4) / 256;
5525 r = (r * 1024) / 256;
5526 g = (g * 1024) / 256;
5527 b = (b * 1024) / 256;
5528 ret = a << 30;
5529 ret |= r << 20;
5530 ret |= g << 10;
5531 ret |= b << 0;
5532 TRACE("Returning %08x\n", ret);
5533 return ret;
5535 case WINED3DFMT_R10G10B10A2_UNORM:
5536 a = (a * 4) / 256;
5537 r = (r * 1024) / 256;
5538 g = (g * 1024) / 256;
5539 b = (b * 1024) / 256;
5540 ret = a << 30;
5541 ret |= b << 20;
5542 ret |= g << 10;
5543 ret |= r << 0;
5544 TRACE("Returning %08x\n", ret);
5545 return ret;
5547 default:
5548 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5549 return 0;
5553 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5554 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5556 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5557 WINEDDBLTFX BltFx;
5559 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5561 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5562 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5563 return WINED3DERR_INVALIDCALL;
5566 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5567 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5568 color_fill_fbo(iface, pSurface, pRect, c);
5569 return WINED3D_OK;
5570 } else {
5571 /* Just forward this to the DirectDraw blitting engine */
5572 memset(&BltFx, 0, sizeof(BltFx));
5573 BltFx.dwSize = sizeof(BltFx);
5574 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5575 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5576 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5580 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5581 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5583 IWineD3DResource *resource;
5584 IWineD3DSurface *surface;
5585 HRESULT hr;
5587 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5588 if (FAILED(hr))
5590 ERR("Failed to get resource, hr %#x\n", hr);
5591 return;
5594 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5596 FIXME("Only supported on surface resources\n");
5597 IWineD3DResource_Release(resource);
5598 return;
5601 surface = (IWineD3DSurface *)resource;
5603 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5605 color_fill_fbo(iface, surface, NULL, color);
5607 else
5609 WINEDDBLTFX BltFx;
5610 WINED3DCOLOR c;
5612 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5614 c = ((DWORD)(color[2] * 255.0f));
5615 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5616 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5617 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5619 /* Just forward this to the DirectDraw blitting engine */
5620 memset(&BltFx, 0, sizeof(BltFx));
5621 BltFx.dwSize = sizeof(BltFx);
5622 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5623 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5624 if (FAILED(hr))
5626 ERR("Blt failed, hr %#x\n", hr);
5630 IWineD3DResource_Release(resource);
5633 /* rendertarget and depth stencil functions */
5634 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5637 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5639 ERR("(%p) : Only %d render targets are supported.\n",
5640 This, This->adapter->gl_info.limits.buffers);
5641 return WINED3DERR_INVALIDCALL;
5644 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5645 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5646 /* Note inc ref on returned surface */
5647 if(*ppRenderTarget != NULL)
5648 IWineD3DSurface_AddRef(*ppRenderTarget);
5649 return WINED3D_OK;
5652 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5653 IWineD3DSurface *Front, IWineD3DSurface *Back)
5655 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5656 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5657 IWineD3DSwapChainImpl *Swapchain;
5658 HRESULT hr;
5660 TRACE("iface %p, front %p, back %p.\n", iface, Front, Back);
5662 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5663 if(hr != WINED3D_OK) {
5664 ERR("Can't get the swapchain\n");
5665 return hr;
5668 /* Make sure to release the swapchain */
5669 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5671 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5672 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5673 return WINED3DERR_INVALIDCALL;
5675 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5676 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5677 return WINED3DERR_INVALIDCALL;
5680 if(Swapchain->frontBuffer != Front) {
5681 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5683 if(Swapchain->frontBuffer)
5685 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5686 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5688 Swapchain->frontBuffer = Front;
5690 if(Swapchain->frontBuffer) {
5691 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5692 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5696 if(Back && !Swapchain->backBuffer) {
5697 /* We need memory for the back buffer array - only one back buffer this way */
5698 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5699 if(!Swapchain->backBuffer) {
5700 ERR("Out of memory\n");
5701 return E_OUTOFMEMORY;
5705 if(Swapchain->backBuffer[0] != Back) {
5706 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5708 /* What to do about the context here in the case of multithreading? Not sure.
5709 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5711 WARN("No active context?\n");
5713 ENTER_GL();
5714 if(!Swapchain->backBuffer[0]) {
5715 /* GL was told to draw to the front buffer at creation,
5716 * undo that
5718 glDrawBuffer(GL_BACK);
5719 checkGLcall("glDrawBuffer(GL_BACK)");
5720 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5721 Swapchain->presentParms.BackBufferCount = 1;
5722 } else if (!Back) {
5723 /* That makes problems - disable for now */
5724 /* glDrawBuffer(GL_FRONT); */
5725 checkGLcall("glDrawBuffer(GL_FRONT)");
5726 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5727 Swapchain->presentParms.BackBufferCount = 0;
5729 LEAVE_GL();
5731 if(Swapchain->backBuffer[0])
5733 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5734 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5736 Swapchain->backBuffer[0] = Back;
5738 if(Swapchain->backBuffer[0]) {
5739 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5740 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
5741 Swapchain->presentParms.BackBufferWidth = BackImpl->currentDesc.Width;
5742 Swapchain->presentParms.BackBufferHeight = BackImpl->currentDesc.Height;
5743 Swapchain->presentParms.BackBufferFormat = BackImpl->resource.format_desc->format;
5744 } else {
5745 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5746 Swapchain->backBuffer = NULL;
5751 return WINED3D_OK;
5754 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5756 *ppZStencilSurface = This->stencilBufferTarget;
5757 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5759 if(*ppZStencilSurface != NULL) {
5760 /* Note inc ref on returned surface */
5761 IWineD3DSurface_AddRef(*ppZStencilSurface);
5762 return WINED3D_OK;
5763 } else {
5764 return WINED3DERR_NOTFOUND;
5768 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5769 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
5771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5772 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5773 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5774 const struct wined3d_gl_info *gl_info;
5775 struct wined3d_context *context;
5776 GLenum gl_filter;
5777 POINT offset = {0, 0};
5779 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5780 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5781 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5782 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5784 switch (filter) {
5785 case WINED3DTEXF_LINEAR:
5786 gl_filter = GL_LINEAR;
5787 break;
5789 default:
5790 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5791 case WINED3DTEXF_NONE:
5792 case WINED3DTEXF_POINT:
5793 gl_filter = GL_NEAREST;
5794 break;
5797 /* Make sure the drawables are up-to-date. Note that loading the
5798 * destination surface isn't strictly required if we overwrite the
5799 * entire surface. */
5800 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
5801 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
5803 /* Attach src surface to src fbo */
5804 src_swapchain = get_swapchain(src_surface);
5805 dst_swapchain = get_swapchain(dst_surface);
5807 if (src_swapchain) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
5808 else if (dst_swapchain) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5809 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5811 gl_info = context->gl_info;
5813 if (!surface_is_offscreen(src_surface))
5815 GLenum buffer = surface_get_gl_buffer(src_surface);
5817 TRACE("Source surface %p is onscreen\n", src_surface);
5819 if(buffer == GL_FRONT) {
5820 RECT windowsize;
5821 UINT h;
5822 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
5823 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
5824 h = windowsize.bottom - windowsize.top;
5825 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
5826 src_rect->y1 = offset.y + h - src_rect->y1;
5827 src_rect->y2 = offset.y + h - src_rect->y2;
5828 } else {
5829 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5830 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5833 ENTER_GL();
5834 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5835 glReadBuffer(buffer);
5836 checkGLcall("glReadBuffer()");
5837 } else {
5838 TRACE("Source surface %p is offscreen\n", src_surface);
5839 ENTER_GL();
5840 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5841 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
5842 glReadBuffer(GL_COLOR_ATTACHMENT0);
5843 checkGLcall("glReadBuffer()");
5844 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5846 LEAVE_GL();
5848 /* Attach dst surface to dst fbo */
5849 if (!surface_is_offscreen(dst_surface))
5851 GLenum buffer = surface_get_gl_buffer(dst_surface);
5853 TRACE("Destination surface %p is onscreen\n", dst_surface);
5855 if(buffer == GL_FRONT) {
5856 RECT windowsize;
5857 UINT h;
5858 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
5859 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
5860 h = windowsize.bottom - windowsize.top;
5861 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
5862 dst_rect->y1 = offset.y + h - dst_rect->y1;
5863 dst_rect->y2 = offset.y + h - dst_rect->y2;
5864 } else {
5865 /* Screen coords = window coords, surface height = window height */
5866 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5867 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5870 ENTER_GL();
5871 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5872 context_set_draw_buffer(context, buffer);
5874 else
5876 TRACE("Destination surface %p is offscreen\n", dst_surface);
5878 ENTER_GL();
5879 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5880 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
5881 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5882 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5884 glDisable(GL_SCISSOR_TEST);
5885 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5887 if (flip) {
5888 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5889 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
5890 checkGLcall("glBlitFramebuffer()");
5891 } else {
5892 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5893 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
5894 checkGLcall("glBlitFramebuffer()");
5897 LEAVE_GL();
5899 wglFlush(); /* Flush to ensure ordering across contexts. */
5901 context_release(context);
5903 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
5906 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5907 BOOL set_viewport) {
5908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5910 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5912 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5914 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5915 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5916 return WINED3DERR_INVALIDCALL;
5919 /* MSDN says that null disables the render target
5920 but a device must always be associated with a render target
5921 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5923 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5924 FIXME("Trying to set render target 0 to NULL\n");
5925 return WINED3DERR_INVALIDCALL;
5927 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5928 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);
5929 return WINED3DERR_INVALIDCALL;
5932 /* If we are trying to set what we already have, don't bother */
5933 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5934 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5935 return WINED3D_OK;
5937 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5938 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5939 This->render_targets[RenderTargetIndex] = pRenderTarget;
5941 /* Render target 0 is special */
5942 if(RenderTargetIndex == 0 && set_viewport) {
5943 /* Finally, reset the viewport and scissor rect as the MSDN states.
5944 * Tests show that stateblock recording is ignored, the change goes
5945 * directly into the primary stateblock.
5947 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5948 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5949 This->stateBlock->viewport.X = 0;
5950 This->stateBlock->viewport.Y = 0;
5951 This->stateBlock->viewport.MaxZ = 1.0f;
5952 This->stateBlock->viewport.MinZ = 0.0f;
5953 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5955 This->stateBlock->scissorRect.top = 0;
5956 This->stateBlock->scissorRect.left = 0;
5957 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5958 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5959 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5961 return WINED3D_OK;
5964 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5966 HRESULT hr = WINED3D_OK;
5967 IWineD3DSurface *tmp;
5969 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
5971 if (pNewZStencil == This->stencilBufferTarget) {
5972 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5973 } else {
5974 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
5975 * depending on the renter target implementation being used.
5976 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5977 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5978 * stencil buffer and incur an extra memory overhead
5979 ******************************************************/
5981 if (This->stencilBufferTarget) {
5982 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5983 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
5984 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
5985 } else {
5986 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5987 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
5988 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
5989 context_release(context);
5993 tmp = This->stencilBufferTarget;
5994 This->stencilBufferTarget = pNewZStencil;
5995 /* should we be calling the parent or the wined3d surface? */
5996 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5997 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5998 hr = WINED3D_OK;
6000 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6001 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6002 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6003 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6004 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6008 return hr;
6011 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6012 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6014 /* TODO: the use of Impl is deprecated. */
6015 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6016 WINED3DLOCKED_RECT lockedRect;
6018 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6020 /* some basic validation checks */
6021 if(This->cursorTexture) {
6022 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6023 ENTER_GL();
6024 glDeleteTextures(1, &This->cursorTexture);
6025 LEAVE_GL();
6026 context_release(context);
6027 This->cursorTexture = 0;
6030 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6031 This->haveHardwareCursor = TRUE;
6032 else
6033 This->haveHardwareCursor = FALSE;
6035 if(pCursorBitmap) {
6036 WINED3DLOCKED_RECT rect;
6038 /* MSDN: Cursor must be A8R8G8B8 */
6039 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6041 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6042 return WINED3DERR_INVALIDCALL;
6045 /* MSDN: Cursor must be smaller than the display mode */
6046 if(pSur->currentDesc.Width > This->ddraw_width ||
6047 pSur->currentDesc.Height > This->ddraw_height) {
6048 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);
6049 return WINED3DERR_INVALIDCALL;
6052 if (!This->haveHardwareCursor) {
6053 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6055 /* Do not store the surface's pointer because the application may
6056 * release it after setting the cursor image. Windows doesn't
6057 * addref the set surface, so we can't do this either without
6058 * creating circular refcount dependencies. Copy out the gl texture
6059 * instead.
6061 This->cursorWidth = pSur->currentDesc.Width;
6062 This->cursorHeight = pSur->currentDesc.Height;
6063 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6065 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6066 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6067 struct wined3d_context *context;
6068 char *mem, *bits = rect.pBits;
6069 GLint intfmt = glDesc->glInternal;
6070 GLint format = glDesc->glFormat;
6071 GLint type = glDesc->glType;
6072 INT height = This->cursorHeight;
6073 INT width = This->cursorWidth;
6074 INT bpp = glDesc->byte_count;
6075 DWORD sampler;
6076 INT i;
6078 /* Reformat the texture memory (pitch and width can be
6079 * different) */
6080 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6081 for(i = 0; i < height; i++)
6082 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6083 IWineD3DSurface_UnlockRect(pCursorBitmap);
6085 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6087 ENTER_GL();
6089 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6091 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6092 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6095 /* Make sure that a proper texture unit is selected */
6096 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6097 checkGLcall("glActiveTextureARB");
6098 sampler = This->rev_tex_unit_map[0];
6099 if (sampler != WINED3D_UNMAPPED_STAGE)
6101 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6103 /* Create a new cursor texture */
6104 glGenTextures(1, &This->cursorTexture);
6105 checkGLcall("glGenTextures");
6106 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6107 checkGLcall("glBindTexture");
6108 /* Copy the bitmap memory into the cursor texture */
6109 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6110 HeapFree(GetProcessHeap(), 0, mem);
6111 checkGLcall("glTexImage2D");
6113 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6115 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6116 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6119 LEAVE_GL();
6121 context_release(context);
6123 else
6125 FIXME("A cursor texture was not returned.\n");
6126 This->cursorTexture = 0;
6129 else
6131 /* Draw a hardware cursor */
6132 ICONINFO cursorInfo;
6133 HCURSOR cursor;
6134 /* Create and clear maskBits because it is not needed for
6135 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6136 * chunks. */
6137 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6138 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6139 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6140 WINED3DLOCK_NO_DIRTY_UPDATE |
6141 WINED3DLOCK_READONLY
6143 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6144 pSur->currentDesc.Height);
6146 cursorInfo.fIcon = FALSE;
6147 cursorInfo.xHotspot = XHotSpot;
6148 cursorInfo.yHotspot = YHotSpot;
6149 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6150 1, 1, maskBits);
6151 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6152 1, 32, lockedRect.pBits);
6153 IWineD3DSurface_UnlockRect(pCursorBitmap);
6154 /* Create our cursor and clean up. */
6155 cursor = CreateIconIndirect(&cursorInfo);
6156 SetCursor(cursor);
6157 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6158 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6159 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6160 This->hardwareCursor = cursor;
6161 HeapFree(GetProcessHeap(), 0, maskBits);
6165 This->xHotSpot = XHotSpot;
6166 This->yHotSpot = YHotSpot;
6167 return WINED3D_OK;
6170 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6172 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6174 This->xScreenSpace = XScreenSpace;
6175 This->yScreenSpace = YScreenSpace;
6177 return;
6181 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6183 BOOL oldVisible = This->bCursorVisible;
6184 POINT pt;
6186 TRACE("(%p) : visible(%d)\n", This, bShow);
6189 * When ShowCursor is first called it should make the cursor appear at the OS's last
6190 * known cursor position. Because of this, some applications just repetitively call
6191 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6193 GetCursorPos(&pt);
6194 This->xScreenSpace = pt.x;
6195 This->yScreenSpace = pt.y;
6197 if (This->haveHardwareCursor) {
6198 This->bCursorVisible = bShow;
6199 if (bShow)
6200 SetCursor(This->hardwareCursor);
6201 else
6202 SetCursor(NULL);
6204 else
6206 if (This->cursorTexture)
6207 This->bCursorVisible = bShow;
6210 return oldVisible;
6213 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6214 TRACE("checking resource %p for eviction\n", resource);
6215 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6216 TRACE("Evicting %p\n", resource);
6217 IWineD3DResource_UnLoad(resource);
6219 IWineD3DResource_Release(resource);
6220 return S_OK;
6223 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6225 TRACE("iface %p.\n", iface);
6227 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6228 return WINED3D_OK;
6231 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6233 IWineD3DDeviceImpl *device = surface->resource.device;
6234 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6236 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6237 if(surface->Flags & SFLAG_DIBSECTION) {
6238 /* Release the DC */
6239 SelectObject(surface->hDC, surface->dib.holdbitmap);
6240 DeleteDC(surface->hDC);
6241 /* Release the DIB section */
6242 DeleteObject(surface->dib.DIBsection);
6243 surface->dib.bitmap_data = NULL;
6244 surface->resource.allocatedMemory = NULL;
6245 surface->Flags &= ~SFLAG_DIBSECTION;
6247 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6248 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6249 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6250 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6252 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6253 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6254 } else {
6255 surface->pow2Width = surface->pow2Height = 1;
6256 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6257 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6259 surface->glRect.left = 0;
6260 surface->glRect.top = 0;
6261 surface->glRect.right = surface->pow2Width;
6262 surface->glRect.bottom = surface->pow2Height;
6264 if (surface->texture_name)
6266 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6267 ENTER_GL();
6268 glDeleteTextures(1, &surface->texture_name);
6269 LEAVE_GL();
6270 context_release(context);
6271 surface->texture_name = 0;
6272 surface->Flags &= ~SFLAG_CLIENT;
6274 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6275 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6276 surface->Flags |= SFLAG_NONPOW2;
6277 } else {
6278 surface->Flags &= ~SFLAG_NONPOW2;
6280 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6281 surface->resource.allocatedMemory = NULL;
6282 surface->resource.heapMemory = NULL;
6283 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6285 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6286 * to a FBO */
6287 if(!surface_init_sysmem((IWineD3DSurface *) surface))
6289 return E_OUTOFMEMORY;
6291 return WINED3D_OK;
6294 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6295 TRACE("Unloading resource %p\n", resource);
6296 IWineD3DResource_UnLoad(resource);
6297 IWineD3DResource_Release(resource);
6298 return S_OK;
6301 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6303 UINT i, count;
6304 WINED3DDISPLAYMODE m;
6305 HRESULT hr;
6307 /* All Windowed modes are supported, as is leaving the current mode */
6308 if(pp->Windowed) return TRUE;
6309 if(!pp->BackBufferWidth) return TRUE;
6310 if(!pp->BackBufferHeight) return TRUE;
6312 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6313 for(i = 0; i < count; i++) {
6314 memset(&m, 0, sizeof(m));
6315 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6316 if(FAILED(hr)) {
6317 ERR("EnumAdapterModes failed\n");
6319 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6320 /* Mode found, it is supported */
6321 return TRUE;
6324 /* Mode not found -> not supported */
6325 return FALSE;
6328 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6330 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6331 const struct wined3d_gl_info *gl_info;
6332 struct wined3d_context *context;
6333 IWineD3DBaseShaderImpl *shader;
6335 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6336 gl_info = context->gl_info;
6338 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6339 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6340 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6343 ENTER_GL();
6344 if(This->depth_blt_texture) {
6345 glDeleteTextures(1, &This->depth_blt_texture);
6346 This->depth_blt_texture = 0;
6348 if (This->depth_blt_rb) {
6349 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6350 This->depth_blt_rb = 0;
6351 This->depth_blt_rb_w = 0;
6352 This->depth_blt_rb_h = 0;
6354 LEAVE_GL();
6356 This->blitter->free_private(iface);
6357 This->frag_pipe->free_private(iface);
6358 This->shader_backend->shader_free_private(iface);
6359 destroy_dummy_textures(This, gl_info);
6361 context_release(context);
6363 while (This->numContexts)
6365 context_destroy(This, This->contexts[0]);
6367 HeapFree(GetProcessHeap(), 0, swapchain->context);
6368 swapchain->context = NULL;
6369 swapchain->num_contexts = 0;
6372 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6374 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6375 struct wined3d_context *context;
6376 HRESULT hr;
6377 IWineD3DSurfaceImpl *target;
6379 /* Recreate the primary swapchain's context */
6380 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6381 if (!swapchain->context)
6383 ERR("Failed to allocate memory for swapchain context array.\n");
6384 return E_OUTOFMEMORY;
6387 target = (IWineD3DSurfaceImpl *)(swapchain->backBuffer ? swapchain->backBuffer[0] : swapchain->frontBuffer);
6388 context = context_create(This, target, swapchain->win_handle, FALSE, &swapchain->presentParms);
6389 if (!context)
6391 WARN("Failed to create context.\n");
6392 HeapFree(GetProcessHeap(), 0, swapchain->context);
6393 return E_FAIL;
6396 swapchain->context[0] = context;
6397 swapchain->num_contexts = 1;
6398 create_dummy_textures(This);
6399 context_release(context);
6401 hr = This->shader_backend->shader_alloc_private(iface);
6402 if (FAILED(hr))
6404 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6405 goto err;
6408 hr = This->frag_pipe->alloc_private(iface);
6409 if (FAILED(hr))
6411 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6412 This->shader_backend->shader_free_private(iface);
6413 goto err;
6416 hr = This->blitter->alloc_private(iface);
6417 if (FAILED(hr))
6419 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6420 This->frag_pipe->free_private(iface);
6421 This->shader_backend->shader_free_private(iface);
6422 goto err;
6425 return WINED3D_OK;
6427 err:
6428 context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6429 destroy_dummy_textures(This, context->gl_info);
6430 context_release(context);
6431 context_destroy(This, context);
6432 HeapFree(GetProcessHeap(), 0, swapchain->context);
6433 swapchain->num_contexts = 0;
6434 return hr;
6437 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6439 IWineD3DSwapChainImpl *swapchain;
6440 HRESULT hr;
6441 BOOL DisplayModeChanged = FALSE;
6442 WINED3DDISPLAYMODE mode;
6443 TRACE("(%p)\n", This);
6445 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6446 if(FAILED(hr)) {
6447 ERR("Failed to get the first implicit swapchain\n");
6448 return hr;
6451 if(!is_display_mode_supported(This, pPresentationParameters)) {
6452 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6453 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6454 pPresentationParameters->BackBufferHeight);
6455 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6456 return WINED3DERR_INVALIDCALL;
6459 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6460 * on an existing gl context, so there's no real need for recreation.
6462 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6464 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6466 TRACE("New params:\n");
6467 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6468 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6469 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6470 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6471 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6472 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6473 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6474 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6475 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6476 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6477 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6478 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6479 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6481 /* No special treatment of these parameters. Just store them */
6482 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6483 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6484 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6485 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6487 /* What to do about these? */
6488 if(pPresentationParameters->BackBufferCount != 0 &&
6489 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6490 ERR("Cannot change the back buffer count yet\n");
6492 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6493 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6494 ERR("Cannot change the back buffer format yet\n");
6496 if(pPresentationParameters->hDeviceWindow != NULL &&
6497 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6498 ERR("Cannot change the device window yet\n");
6500 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6501 HRESULT hrc;
6503 TRACE("Creating the depth stencil buffer\n");
6505 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6506 This->parent,
6507 pPresentationParameters->BackBufferWidth,
6508 pPresentationParameters->BackBufferHeight,
6509 pPresentationParameters->AutoDepthStencilFormat,
6510 pPresentationParameters->MultiSampleType,
6511 pPresentationParameters->MultiSampleQuality,
6512 FALSE,
6513 &This->auto_depth_stencil_buffer);
6515 if (FAILED(hrc)) {
6516 ERR("Failed to create the depth stencil buffer\n");
6517 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6518 return WINED3DERR_INVALIDCALL;
6522 /* Reset the depth stencil */
6523 if (pPresentationParameters->EnableAutoDepthStencil)
6524 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6525 else
6526 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6528 TRACE("Resetting stateblock\n");
6529 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6530 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6532 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6534 if(pPresentationParameters->Windowed) {
6535 mode.Width = swapchain->orig_width;
6536 mode.Height = swapchain->orig_height;
6537 mode.RefreshRate = 0;
6538 mode.Format = swapchain->presentParms.BackBufferFormat;
6539 } else {
6540 mode.Width = pPresentationParameters->BackBufferWidth;
6541 mode.Height = pPresentationParameters->BackBufferHeight;
6542 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6543 mode.Format = swapchain->presentParms.BackBufferFormat;
6546 /* Should Width == 800 && Height == 0 set 800x600? */
6547 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6548 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6549 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6551 UINT i;
6553 if(!pPresentationParameters->Windowed) {
6554 DisplayModeChanged = TRUE;
6556 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6557 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6559 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6560 if(FAILED(hr))
6562 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6563 return hr;
6566 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6567 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6568 if(FAILED(hr))
6570 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6571 return hr;
6574 if(This->auto_depth_stencil_buffer) {
6575 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6576 if(FAILED(hr))
6578 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6579 return hr;
6584 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6585 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6586 DisplayModeChanged) {
6588 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6590 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
6591 if(swapchain->presentParms.Windowed) {
6592 /* switch from windowed to fs */
6593 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6594 pPresentationParameters->BackBufferHeight);
6595 } else {
6596 /* Fullscreen -> fullscreen mode change */
6597 MoveWindow(swapchain->win_handle, 0, 0,
6598 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6599 TRUE);
6601 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
6602 /* Fullscreen -> windowed switch */
6603 swapchain_restore_fullscreen_window(swapchain);
6605 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6606 } else if(!pPresentationParameters->Windowed) {
6607 DWORD style = This->style, exStyle = This->exStyle;
6608 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6609 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6610 * Reset to clear up their mess. Guild Wars also loses the device during that.
6612 This->style = 0;
6613 This->exStyle = 0;
6614 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6615 pPresentationParameters->BackBufferHeight);
6616 This->style = style;
6617 This->exStyle = exStyle;
6620 /* Note: No parent needed for initial internal stateblock */
6621 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6622 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6623 else TRACE("Created stateblock %p\n", This->stateBlock);
6624 This->updateStateBlock = This->stateBlock;
6625 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6627 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6628 if(FAILED(hr)) {
6629 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6632 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6634 RECT client_rect;
6635 GetClientRect(swapchain->win_handle, &client_rect);
6637 if(!swapchain->presentParms.BackBufferCount)
6639 TRACE("Single buffered rendering\n");
6640 swapchain->render_to_fbo = FALSE;
6642 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6643 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6645 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6646 swapchain->presentParms.BackBufferWidth,
6647 swapchain->presentParms.BackBufferHeight,
6648 client_rect.right, client_rect.bottom);
6649 swapchain->render_to_fbo = TRUE;
6651 else
6653 TRACE("Rendering directly to GL_BACK\n");
6654 swapchain->render_to_fbo = FALSE;
6658 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6659 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6661 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6662 * first use
6664 return hr;
6667 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6669 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6671 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6673 return WINED3D_OK;
6677 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6679 TRACE("(%p) : pParameters %p\n", This, pParameters);
6681 *pParameters = This->createParms;
6682 return WINED3D_OK;
6685 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6686 IWineD3DSwapChain *swapchain;
6688 TRACE("Relaying to swapchain\n");
6690 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6691 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6692 IWineD3DSwapChain_Release(swapchain);
6696 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6697 IWineD3DSwapChain *swapchain;
6699 TRACE("Relaying to swapchain\n");
6701 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6702 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6703 IWineD3DSwapChain_Release(swapchain);
6708 /** ********************************************************
6709 * Notification functions
6710 ** ********************************************************/
6711 /** This function must be called in the release of a resource when ref == 0,
6712 * the contents of resource must still be correct,
6713 * any handles to other resource held by the caller must be closed
6714 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6715 *****************************************************/
6716 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6718 TRACE("(%p) : Adding resource %p\n", This, resource);
6720 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6723 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6725 TRACE("(%p) : Removing resource %p\n", This, resource);
6727 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6730 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6732 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6733 int counter;
6735 TRACE("(%p) : resource %p\n", This, resource);
6737 context_resource_released((IWineD3DDevice *)This, resource, type);
6739 switch (type) {
6740 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6741 case WINED3DRTYPE_SURFACE: {
6742 unsigned int i;
6744 if (This->d3d_initialized)
6746 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6748 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6749 This->render_targets[i] = NULL;
6752 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6753 This->stencilBufferTarget = NULL;
6757 break;
6759 case WINED3DRTYPE_TEXTURE:
6760 case WINED3DRTYPE_CUBETEXTURE:
6761 case WINED3DRTYPE_VOLUMETEXTURE:
6762 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6763 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6764 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6765 This->stateBlock->textures[counter] = NULL;
6767 if (This->updateStateBlock != This->stateBlock ){
6768 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6769 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6770 This->updateStateBlock->textures[counter] = NULL;
6774 break;
6775 case WINED3DRTYPE_VOLUME:
6776 /* TODO: nothing really? */
6777 break;
6778 case WINED3DRTYPE_BUFFER:
6780 int streamNumber;
6781 TRACE("Cleaning up stream pointers\n");
6783 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6784 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6785 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6787 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6788 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6789 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6790 This->updateStateBlock->streamSource[streamNumber] = 0;
6791 /* Set changed flag? */
6794 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) */
6795 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6796 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6797 This->stateBlock->streamSource[streamNumber] = 0;
6802 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6803 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6804 This->updateStateBlock->pIndexData = NULL;
6807 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6808 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6809 This->stateBlock->pIndexData = NULL;
6813 break;
6815 default:
6816 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6817 break;
6821 /* Remove the resource from the resourceStore */
6822 device_resource_remove(This, resource);
6824 TRACE("Resource released\n");
6828 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6830 IWineD3DResourceImpl *resource, *cursor;
6831 HRESULT ret;
6832 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6834 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6835 TRACE("enumerating resource %p\n", resource);
6836 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6837 ret = pCallback((IWineD3DResource *) resource, pData);
6838 if(ret == S_FALSE) {
6839 TRACE("Canceling enumeration\n");
6840 break;
6843 return WINED3D_OK;
6846 /**********************************************************
6847 * IWineD3DDevice VTbl follows
6848 **********************************************************/
6850 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6852 /*** IUnknown methods ***/
6853 IWineD3DDeviceImpl_QueryInterface,
6854 IWineD3DDeviceImpl_AddRef,
6855 IWineD3DDeviceImpl_Release,
6856 /*** IWineD3DDevice methods ***/
6857 IWineD3DDeviceImpl_GetParent,
6858 /*** Creation methods**/
6859 IWineD3DDeviceImpl_CreateBuffer,
6860 IWineD3DDeviceImpl_CreateVertexBuffer,
6861 IWineD3DDeviceImpl_CreateIndexBuffer,
6862 IWineD3DDeviceImpl_CreateStateBlock,
6863 IWineD3DDeviceImpl_CreateSurface,
6864 IWineD3DDeviceImpl_CreateRendertargetView,
6865 IWineD3DDeviceImpl_CreateTexture,
6866 IWineD3DDeviceImpl_CreateVolumeTexture,
6867 IWineD3DDeviceImpl_CreateVolume,
6868 IWineD3DDeviceImpl_CreateCubeTexture,
6869 IWineD3DDeviceImpl_CreateQuery,
6870 IWineD3DDeviceImpl_CreateSwapChain,
6871 IWineD3DDeviceImpl_CreateVertexDeclaration,
6872 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6873 IWineD3DDeviceImpl_CreateVertexShader,
6874 IWineD3DDeviceImpl_CreateGeometryShader,
6875 IWineD3DDeviceImpl_CreatePixelShader,
6876 IWineD3DDeviceImpl_CreatePalette,
6877 /*** Odd functions **/
6878 IWineD3DDeviceImpl_Init3D,
6879 IWineD3DDeviceImpl_InitGDI,
6880 IWineD3DDeviceImpl_Uninit3D,
6881 IWineD3DDeviceImpl_UninitGDI,
6882 IWineD3DDeviceImpl_SetMultithreaded,
6883 IWineD3DDeviceImpl_EvictManagedResources,
6884 IWineD3DDeviceImpl_GetAvailableTextureMem,
6885 IWineD3DDeviceImpl_GetBackBuffer,
6886 IWineD3DDeviceImpl_GetCreationParameters,
6887 IWineD3DDeviceImpl_GetDeviceCaps,
6888 IWineD3DDeviceImpl_GetDirect3D,
6889 IWineD3DDeviceImpl_GetDisplayMode,
6890 IWineD3DDeviceImpl_SetDisplayMode,
6891 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6892 IWineD3DDeviceImpl_GetRasterStatus,
6893 IWineD3DDeviceImpl_GetSwapChain,
6894 IWineD3DDeviceImpl_Reset,
6895 IWineD3DDeviceImpl_SetDialogBoxMode,
6896 IWineD3DDeviceImpl_SetCursorProperties,
6897 IWineD3DDeviceImpl_SetCursorPosition,
6898 IWineD3DDeviceImpl_ShowCursor,
6899 /*** Getters and setters **/
6900 IWineD3DDeviceImpl_SetClipPlane,
6901 IWineD3DDeviceImpl_GetClipPlane,
6902 IWineD3DDeviceImpl_SetClipStatus,
6903 IWineD3DDeviceImpl_GetClipStatus,
6904 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6905 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6906 IWineD3DDeviceImpl_SetDepthStencilSurface,
6907 IWineD3DDeviceImpl_GetDepthStencilSurface,
6908 IWineD3DDeviceImpl_SetGammaRamp,
6909 IWineD3DDeviceImpl_GetGammaRamp,
6910 IWineD3DDeviceImpl_SetIndexBuffer,
6911 IWineD3DDeviceImpl_GetIndexBuffer,
6912 IWineD3DDeviceImpl_SetBaseVertexIndex,
6913 IWineD3DDeviceImpl_GetBaseVertexIndex,
6914 IWineD3DDeviceImpl_SetLight,
6915 IWineD3DDeviceImpl_GetLight,
6916 IWineD3DDeviceImpl_SetLightEnable,
6917 IWineD3DDeviceImpl_GetLightEnable,
6918 IWineD3DDeviceImpl_SetMaterial,
6919 IWineD3DDeviceImpl_GetMaterial,
6920 IWineD3DDeviceImpl_SetNPatchMode,
6921 IWineD3DDeviceImpl_GetNPatchMode,
6922 IWineD3DDeviceImpl_SetPaletteEntries,
6923 IWineD3DDeviceImpl_GetPaletteEntries,
6924 IWineD3DDeviceImpl_SetPixelShader,
6925 IWineD3DDeviceImpl_GetPixelShader,
6926 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6927 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6928 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6929 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6930 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6931 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6932 IWineD3DDeviceImpl_SetRenderState,
6933 IWineD3DDeviceImpl_GetRenderState,
6934 IWineD3DDeviceImpl_SetRenderTarget,
6935 IWineD3DDeviceImpl_GetRenderTarget,
6936 IWineD3DDeviceImpl_SetFrontBackBuffers,
6937 IWineD3DDeviceImpl_SetSamplerState,
6938 IWineD3DDeviceImpl_GetSamplerState,
6939 IWineD3DDeviceImpl_SetScissorRect,
6940 IWineD3DDeviceImpl_GetScissorRect,
6941 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6942 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6943 IWineD3DDeviceImpl_SetStreamSource,
6944 IWineD3DDeviceImpl_GetStreamSource,
6945 IWineD3DDeviceImpl_SetStreamSourceFreq,
6946 IWineD3DDeviceImpl_GetStreamSourceFreq,
6947 IWineD3DDeviceImpl_SetTexture,
6948 IWineD3DDeviceImpl_GetTexture,
6949 IWineD3DDeviceImpl_SetTextureStageState,
6950 IWineD3DDeviceImpl_GetTextureStageState,
6951 IWineD3DDeviceImpl_SetTransform,
6952 IWineD3DDeviceImpl_GetTransform,
6953 IWineD3DDeviceImpl_SetVertexDeclaration,
6954 IWineD3DDeviceImpl_GetVertexDeclaration,
6955 IWineD3DDeviceImpl_SetVertexShader,
6956 IWineD3DDeviceImpl_GetVertexShader,
6957 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6958 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6959 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6960 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6961 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6962 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6963 IWineD3DDeviceImpl_SetViewport,
6964 IWineD3DDeviceImpl_GetViewport,
6965 IWineD3DDeviceImpl_MultiplyTransform,
6966 IWineD3DDeviceImpl_ValidateDevice,
6967 IWineD3DDeviceImpl_ProcessVertices,
6968 /*** State block ***/
6969 IWineD3DDeviceImpl_BeginStateBlock,
6970 IWineD3DDeviceImpl_EndStateBlock,
6971 /*** Scene management ***/
6972 IWineD3DDeviceImpl_BeginScene,
6973 IWineD3DDeviceImpl_EndScene,
6974 IWineD3DDeviceImpl_Present,
6975 IWineD3DDeviceImpl_Clear,
6976 IWineD3DDeviceImpl_ClearRendertargetView,
6977 /*** Drawing ***/
6978 IWineD3DDeviceImpl_SetPrimitiveType,
6979 IWineD3DDeviceImpl_GetPrimitiveType,
6980 IWineD3DDeviceImpl_DrawPrimitive,
6981 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6982 IWineD3DDeviceImpl_DrawPrimitiveUP,
6983 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6984 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6985 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6986 IWineD3DDeviceImpl_DrawRectPatch,
6987 IWineD3DDeviceImpl_DrawTriPatch,
6988 IWineD3DDeviceImpl_DeletePatch,
6989 IWineD3DDeviceImpl_ColorFill,
6990 IWineD3DDeviceImpl_UpdateTexture,
6991 IWineD3DDeviceImpl_UpdateSurface,
6992 IWineD3DDeviceImpl_GetFrontBufferData,
6993 /*** object tracking ***/
6994 IWineD3DDeviceImpl_EnumResources
6997 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6998 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6999 IUnknown *parent, IWineD3DDeviceParent *device_parent)
7001 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
7002 const struct fragment_pipeline *fragment_pipeline;
7003 struct shader_caps shader_caps;
7004 struct fragment_caps ffp_caps;
7005 WINED3DDISPLAYMODE mode;
7006 unsigned int i;
7007 HRESULT hr;
7009 device->lpVtbl = &IWineD3DDevice_Vtbl;
7010 device->ref = 1;
7011 device->wined3d = (IWineD3D *)wined3d;
7012 IWineD3D_AddRef(device->wined3d);
7013 device->adapter = wined3d->adapter_count ? adapter : NULL;
7014 device->parent = parent;
7015 device->device_parent = device_parent;
7016 list_init(&device->resources);
7017 list_init(&device->shaders);
7019 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7020 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
7022 /* Get the initial screen setup for ddraw. */
7023 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
7024 if (FAILED(hr))
7026 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7027 IWineD3D_Release(device->wined3d);
7028 return hr;
7030 device->ddraw_width = mode.Width;
7031 device->ddraw_height = mode.Height;
7032 device->ddraw_format = mode.Format;
7034 /* Save the creation parameters. */
7035 device->createParms.AdapterOrdinal = adapter_idx;
7036 device->createParms.DeviceType = device_type;
7037 device->createParms.hFocusWindow = focus_window;
7038 device->createParms.BehaviorFlags = flags;
7040 device->devType = device_type;
7041 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7043 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7044 device->shader_backend = adapter->shader_backend;
7046 memset(&shader_caps, 0, sizeof(shader_caps));
7047 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7048 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7049 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7050 device->vs_clipping = shader_caps.VSClipping;
7052 memset(&ffp_caps, 0, sizeof(ffp_caps));
7053 fragment_pipeline = adapter->fragment_pipe;
7054 device->frag_pipe = fragment_pipeline;
7055 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7056 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7058 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7059 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7060 if (FAILED(hr))
7062 ERR("Failed to compile state table, hr %#x.\n", hr);
7063 IWineD3D_Release(device->wined3d);
7064 return hr;
7067 device->blitter = adapter->blitter;
7069 return WINED3D_OK;
7073 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7074 DWORD rep = This->StateTable[state].representative;
7075 struct wined3d_context *context;
7076 DWORD idx;
7077 BYTE shift;
7078 UINT i;
7080 for(i = 0; i < This->numContexts; i++) {
7081 context = This->contexts[i];
7082 if(isStateDirty(context, rep)) continue;
7084 context->dirtyArray[context->numDirtyEntries++] = rep;
7085 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7086 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7087 context->isStateDirty[idx] |= (1 << shift);
7091 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7093 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.device;
7094 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7095 *width = device->pbufferWidth;
7096 *height = device->pbufferHeight;
7099 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7101 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7102 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7103 *width = surface->pow2Width;
7104 *height = surface->pow2Height;
7107 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7109 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7110 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7111 * current context's drawable, which is the size of the back buffer of the swapchain
7112 * the active context belongs to. The back buffer of the swapchain is stored as the
7113 * surface the context belongs to. */
7114 *width = surface->currentDesc.Width;
7115 *height = surface->currentDesc.Height;
7118 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7119 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7121 if (device->filter_messages)
7123 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7124 window, message, wparam, lparam);
7125 return DefWindowProcW(window, message, wparam, lparam);
7128 if (message == WM_DESTROY)
7130 TRACE("unregister window %p.\n", window);
7131 wined3d_unregister_window(window);
7133 if (device->focus_window == window) device->focus_window = NULL;
7134 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7137 return CallWindowProcW(proc, window, message, wparam, lparam);