d3dxof: Turn some TRACEs into WARNs in case of parsing error.
[wine/multimedia.git] / dlls / wined3d / device.c
blob578d8e4808b1d6306b194713ca26b16ad53beea7
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 unsigned int i;
184 stream_info->use_map = 0;
185 stream_info->swizzle_map = 0;
187 /* Check for transformed vertices, disable vertex shader if present. */
188 stream_info->position_transformed = declaration->position_transformed;
189 if (declaration->position_transformed) use_vshader = FALSE;
191 /* Translate the declaration into strided data. */
192 for (i = 0; i < declaration->element_count; ++i)
194 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
195 GLuint buffer_object = 0;
196 const BYTE *data = NULL;
197 BOOL stride_used;
198 unsigned int idx;
199 DWORD stride;
201 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
202 element, i + 1, declaration->element_count);
204 if (!This->stateBlock->streamSource[element->input_slot]) continue;
206 stride = This->stateBlock->streamStride[element->input_slot];
207 if (This->stateBlock->streamIsUP)
209 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
210 buffer_object = 0;
211 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
213 else
215 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
216 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
218 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
219 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
220 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
221 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
222 * not, drawStridedSlow is needed, including a vertex buffer path. */
223 if (This->stateBlock->loadBaseVertexIndex < 0)
225 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
226 buffer_object = 0;
227 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
228 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
230 FIXME("System memory vertex data load offset is negative!\n");
234 if (fixup)
236 if (buffer_object) *fixup = TRUE;
237 else if (*fixup && !use_vshader
238 && (element->usage == WINED3DDECLUSAGE_COLOR
239 || element->usage == WINED3DDECLUSAGE_POSITIONT))
241 static BOOL warned = FALSE;
242 if (!warned)
244 /* This may be bad with the fixed function pipeline. */
245 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
246 warned = TRUE;
251 data += element->offset;
253 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
255 if (use_vshader)
257 if (element->output_slot == ~0U)
259 /* TODO: Assuming vertexdeclarations are usually used with the
260 * same or a similar shader, it might be worth it to store the
261 * last used output slot and try that one first. */
262 stride_used = vshader_get_input(This->stateBlock->vertexShader,
263 element->usage, element->usage_idx, &idx);
265 else
267 idx = element->output_slot;
268 stride_used = TRUE;
271 else
273 if (!element->ffp_valid)
275 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
276 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
277 stride_used = FALSE;
279 else
281 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
285 if (stride_used)
287 TRACE("Load %s array %u [usage %s, usage_idx %u, "
288 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
289 use_vshader ? "shader": "fixed function", idx,
290 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
291 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
293 stream_info->elements[idx].format_desc = element->format_desc;
294 stream_info->elements[idx].stride = stride;
295 stream_info->elements[idx].data = data;
296 stream_info->elements[idx].stream_idx = element->input_slot;
297 stream_info->elements[idx].buffer_object = buffer_object;
299 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
300 && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
302 stream_info->swizzle_map |= 1 << idx;
304 stream_info->use_map |= 1 << idx;
308 if (!This->stateBlock->streamIsUP)
310 WORD map = stream_info->use_map;
312 /* PreLoad all the vertex buffers. */
313 for (i = 0; map; map >>= 1, ++i)
315 struct wined3d_stream_info_element *element;
316 struct wined3d_buffer *buffer;
318 if (!(map & 1)) continue;
320 element = &stream_info->elements[i];
321 buffer = (struct wined3d_buffer *)This->stateBlock->streamSource[element->stream_idx];
322 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)buffer);
324 /* If PreLoad dropped the buffer object, update the stream info. */
325 if (buffer->buffer_object != element->buffer_object)
327 element->buffer_object = 0;
328 element->data = buffer_get_sysmem(buffer) + (ptrdiff_t)element->data;
334 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
335 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
337 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, gl_info);
338 e->format_desc = format_desc;
339 e->stride = strided->dwStride;
340 e->data = strided->lpData;
341 e->stream_idx = 0;
342 e->buffer_object = 0;
345 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
346 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
348 unsigned int i;
350 memset(stream_info, 0, sizeof(*stream_info));
352 if (strided->position.lpData)
353 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
354 if (strided->normal.lpData)
355 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
356 if (strided->diffuse.lpData)
357 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
358 if (strided->specular.lpData)
359 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
361 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
363 if (strided->texCoords[i].lpData)
364 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
365 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
368 stream_info->position_transformed = strided->position_transformed;
370 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
372 if (!stream_info->elements[i].format_desc) continue;
374 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
375 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
377 stream_info->swizzle_map |= 1 << i;
379 stream_info->use_map |= 1 << i;
383 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
385 TRACE("Strided Data:\n");
386 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
387 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
388 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
389 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
390 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
391 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
392 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
393 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
394 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
395 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
396 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
403 /* Context activation is done by the caller. */
404 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
406 struct wined3d_stream_info *stream_info = &device->strided_streams;
407 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
408 BOOL vs = stateblock->vertexShader && device->vs_selected_mode != SHADER_NONE;
409 BOOL fixup = FALSE;
411 if (device->up_strided)
413 /* Note: this is a ddraw fixed-function code path. */
414 TRACE("=============================== Strided Input ================================\n");
415 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
416 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
418 else
420 TRACE("============================= Vertex Declaration =============================\n");
421 device_stream_info_from_declaration(device, vs, stream_info, &fixup);
424 if (vs && !stream_info->position_transformed)
426 if (((IWineD3DVertexDeclarationImpl *)stateblock->vertexDecl)->half_float_conv_needed && !fixup)
428 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
429 device->useDrawStridedSlow = TRUE;
431 else
433 device->useDrawStridedSlow = FALSE;
436 else
438 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
439 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
440 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
442 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
444 device->useDrawStridedSlow = TRUE;
446 else
448 device->useDrawStridedSlow = FALSE;
453 static void device_preload_texture(IWineD3DStateBlockImpl *stateblock, unsigned int idx)
455 IWineD3DBaseTextureImpl *texture;
456 enum WINED3DSRGB srgb;
458 if (!(texture = (IWineD3DBaseTextureImpl *)stateblock->textures[idx])) return;
459 srgb = stateblock->samplerState[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
460 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
463 void device_preload_textures(IWineD3DDeviceImpl *device)
465 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
466 unsigned int i;
468 if (use_vs(stateblock))
470 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
472 if (((IWineD3DBaseShaderImpl *)stateblock->vertexShader)->baseShader.reg_maps.sampler_type[i])
473 device_preload_texture(stateblock, MAX_FRAGMENT_SAMPLERS + i);
477 if (use_ps(stateblock))
479 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
481 if (((IWineD3DBaseShaderImpl *)stateblock->pixelShader)->baseShader.reg_maps.sampler_type[i])
482 device_preload_texture(stateblock, i);
485 else
487 WORD ffu_map = device->fixed_function_usage_map;
489 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
491 if (ffu_map & 1)
492 device_preload_texture(stateblock, i);
497 /**********************************************************
498 * IUnknown parts follows
499 **********************************************************/
501 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
505 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
506 if (IsEqualGUID(riid, &IID_IUnknown)
507 || IsEqualGUID(riid, &IID_IWineD3DBase)
508 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
509 IUnknown_AddRef(iface);
510 *ppobj = This;
511 return S_OK;
513 *ppobj = NULL;
514 return E_NOINTERFACE;
517 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
519 ULONG refCount = InterlockedIncrement(&This->ref);
521 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
522 return refCount;
525 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
527 ULONG refCount = InterlockedDecrement(&This->ref);
529 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
531 if (!refCount) {
532 UINT i;
534 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
535 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
536 This->multistate_funcs[i] = NULL;
539 /* TODO: Clean up all the surfaces and textures! */
540 /* NOTE: You must release the parent if the object was created via a callback
541 ** ***************************/
543 if (!list_empty(&This->resources)) {
544 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
545 dumpResources(&This->resources);
548 if(This->contexts) ERR("Context array not freed!\n");
549 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
550 This->haveHardwareCursor = FALSE;
552 IWineD3D_Release(This->wined3d);
553 This->wined3d = NULL;
554 HeapFree(GetProcessHeap(), 0, This);
555 TRACE("Freed device %p\n", This);
556 This = NULL;
558 return refCount;
561 /**********************************************************
562 * IWineD3DDevice implementation follows
563 **********************************************************/
564 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
566 *pParent = This->parent;
567 IUnknown_AddRef(This->parent);
568 return WINED3D_OK;
571 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
572 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
575 struct wined3d_buffer *object;
576 HRESULT hr;
578 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
580 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
581 if (!object)
583 ERR("Failed to allocate memory\n");
584 return E_OUTOFMEMORY;
587 FIXME("Ignoring access flags (pool)\n");
589 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
590 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
591 if (FAILED(hr))
593 WARN("Failed to initialize buffer, hr %#x.\n", hr);
594 HeapFree(GetProcessHeap(), 0, object);
595 return hr;
597 object->desc = *desc;
599 TRACE("Created buffer %p.\n", object);
601 *buffer = (IWineD3DBuffer *)object;
603 return WINED3D_OK;
606 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
607 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
608 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
611 struct wined3d_buffer *object;
612 HRESULT hr;
614 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
615 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
617 if (Pool == WINED3DPOOL_SCRATCH)
619 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
620 * anyway, SCRATCH vertex buffers aren't usable anywhere
622 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
623 *ppVertexBuffer = NULL;
624 return WINED3DERR_INVALIDCALL;
627 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
628 if (!object)
630 ERR("Out of memory\n");
631 *ppVertexBuffer = NULL;
632 return WINED3DERR_OUTOFVIDEOMEMORY;
635 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
636 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
637 if (FAILED(hr))
639 WARN("Failed to initialize buffer, hr %#x.\n", hr);
640 HeapFree(GetProcessHeap(), 0, object);
641 return hr;
644 TRACE("Created buffer %p.\n", object);
645 *ppVertexBuffer = (IWineD3DBuffer *)object;
647 return WINED3D_OK;
650 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
651 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
652 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
655 struct wined3d_buffer *object;
656 HRESULT hr;
658 TRACE("(%p) Creating index buffer\n", This);
660 /* Allocate the storage for the device */
661 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
662 if (!object)
664 ERR("Out of memory\n");
665 *ppIndexBuffer = NULL;
666 return WINED3DERR_OUTOFVIDEOMEMORY;
669 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
670 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
671 parent, parent_ops);
672 if (FAILED(hr))
674 WARN("Failed to initialize buffer, hr %#x\n", hr);
675 HeapFree(GetProcessHeap(), 0, object);
676 return hr;
679 TRACE("Created buffer %p.\n", object);
681 *ppIndexBuffer = (IWineD3DBuffer *) object;
683 return WINED3D_OK;
686 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
687 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
690 IWineD3DStateBlockImpl *object;
691 HRESULT hr;
693 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
694 if(!object)
696 ERR("Failed to allocate stateblock memory.\n");
697 return E_OUTOFMEMORY;
700 hr = stateblock_init(object, This, type);
701 if (FAILED(hr))
703 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
704 HeapFree(GetProcessHeap(), 0, object);
705 return hr;
708 TRACE("Created stateblock %p.\n", object);
709 *stateblock = (IWineD3DStateBlock *)object;
711 return WINED3D_OK;
714 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
715 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
716 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
717 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
719 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
720 IWineD3DSurfaceImpl *object;
721 HRESULT hr;
723 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
724 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
725 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
726 ppSurface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
727 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
729 if (Impl == SURFACE_OPENGL && !This->adapter)
731 ERR("OpenGL surfaces are not available without OpenGL.\n");
732 return WINED3DERR_NOTAVAILABLE;
735 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
736 if (!object)
738 ERR("Failed to allocate surface memory.\n");
739 return WINED3DERR_OUTOFVIDEOMEMORY;
742 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
743 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
744 if (FAILED(hr))
746 WARN("Failed to initialize surface, returning %#x.\n", hr);
747 HeapFree(GetProcessHeap(), 0, object);
748 return hr;
751 TRACE("(%p) : Created surface %p\n", This, object);
753 *ppSurface = (IWineD3DSurface *)object;
755 return hr;
758 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
759 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
761 struct wined3d_rendertarget_view *object;
763 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
764 if (!object)
766 ERR("Failed to allocate memory\n");
767 return E_OUTOFMEMORY;
770 object->vtbl = &wined3d_rendertarget_view_vtbl;
771 object->refcount = 1;
772 IWineD3DResource_AddRef(resource);
773 object->resource = resource;
774 object->parent = parent;
776 *rendertarget_view = (IWineD3DRendertargetView *)object;
778 return WINED3D_OK;
781 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
782 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
783 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
786 IWineD3DTextureImpl *object;
787 HRESULT hr;
789 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
790 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
791 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
793 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
794 if (!object)
796 ERR("Out of memory\n");
797 *ppTexture = NULL;
798 return WINED3DERR_OUTOFVIDEOMEMORY;
801 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
802 if (FAILED(hr))
804 WARN("Failed to initialize texture, returning %#x\n", hr);
805 HeapFree(GetProcessHeap(), 0, object);
806 *ppTexture = NULL;
807 return hr;
810 *ppTexture = (IWineD3DTexture *)object;
812 TRACE("(%p) : Created texture %p\n", This, object);
814 return WINED3D_OK;
817 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
818 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
819 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
822 IWineD3DVolumeTextureImpl *object;
823 HRESULT hr;
825 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
826 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
828 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
829 if (!object)
831 ERR("Out of memory\n");
832 *ppVolumeTexture = NULL;
833 return WINED3DERR_OUTOFVIDEOMEMORY;
836 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
837 if (FAILED(hr))
839 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
840 HeapFree(GetProcessHeap(), 0, object);
841 *ppVolumeTexture = NULL;
842 return hr;
845 TRACE("(%p) : Created volume texture %p.\n", This, object);
846 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
848 return WINED3D_OK;
851 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
852 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
853 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
856 IWineD3DVolumeImpl *object;
857 HRESULT hr;
859 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
860 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
862 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
863 if (!object)
865 ERR("Out of memory\n");
866 *ppVolume = NULL;
867 return WINED3DERR_OUTOFVIDEOMEMORY;
870 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
871 if (FAILED(hr))
873 WARN("Failed to initialize volume, returning %#x.\n", hr);
874 HeapFree(GetProcessHeap(), 0, object);
875 return hr;
878 TRACE("(%p) : Created volume %p.\n", This, object);
879 *ppVolume = (IWineD3DVolume *)object;
881 return WINED3D_OK;
884 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
885 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
886 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
889 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
890 HRESULT hr;
892 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
893 if (!object)
895 ERR("Out of memory\n");
896 *ppCubeTexture = NULL;
897 return WINED3DERR_OUTOFVIDEOMEMORY;
900 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
901 if (FAILED(hr))
903 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
904 HeapFree(GetProcessHeap(), 0, object);
905 *ppCubeTexture = NULL;
906 return hr;
909 TRACE("(%p) : Created Cube Texture %p\n", This, object);
910 *ppCubeTexture = (IWineD3DCubeTexture *)object;
912 return WINED3D_OK;
915 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
916 WINED3DQUERYTYPE type, IWineD3DQuery **query, IUnknown *parent)
918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
919 IWineD3DQueryImpl *object;
920 HRESULT hr;
922 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface, type, query, parent);
924 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
925 if (!object)
927 ERR("Failed to allocate query memory.\n");
928 return E_OUTOFMEMORY;
931 hr = query_init(object, This, type, parent);
932 if (FAILED(hr))
934 WARN("Failed to initialize query, hr %#x.\n", hr);
935 HeapFree(GetProcessHeap(), 0, object);
936 return hr;
939 TRACE("Created query %p.\n", object);
940 *query = (IWineD3DQuery *)object;
942 return WINED3D_OK;
945 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
946 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
947 IUnknown *parent, WINED3DSURFTYPE surface_type)
949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
950 IWineD3DSwapChainImpl *object;
951 HRESULT hr;
953 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
954 iface, present_parameters, swapchain, parent, surface_type);
956 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
957 if (!object)
959 ERR("Failed to allocate swapchain memory.\n");
960 return E_OUTOFMEMORY;
963 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
964 if (FAILED(hr))
966 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
967 HeapFree(GetProcessHeap(), 0, object);
968 return hr;
971 TRACE("Created swapchain %p.\n", object);
972 *swapchain = (IWineD3DSwapChain *)object;
974 return WINED3D_OK;
977 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
978 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
980 TRACE("(%p)\n", This);
982 return This->NumberOfSwapChains;
985 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
987 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
989 if(iSwapChain < This->NumberOfSwapChains) {
990 *pSwapChain = This->swapchains[iSwapChain];
991 IWineD3DSwapChain_AddRef(*pSwapChain);
992 TRACE("(%p) returning %p\n", This, *pSwapChain);
993 return WINED3D_OK;
994 } else {
995 TRACE("Swapchain out of range\n");
996 *pSwapChain = NULL;
997 return WINED3DERR_INVALIDCALL;
1001 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1002 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1003 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1006 IWineD3DVertexDeclarationImpl *object = NULL;
1007 HRESULT hr;
1009 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1010 iface, declaration, parent, elements, element_count);
1012 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1013 if(!object)
1015 ERR("Failed to allocate vertex declaration memory.\n");
1016 return E_OUTOFMEMORY;
1019 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1020 if (FAILED(hr))
1022 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1023 HeapFree(GetProcessHeap(), 0, object);
1024 return hr;
1027 TRACE("Created vertex declaration %p.\n", object);
1028 *declaration = (IWineD3DVertexDeclaration *)object;
1030 return WINED3D_OK;
1033 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1034 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1036 unsigned int idx, idx2;
1037 unsigned int offset;
1038 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1039 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1040 BOOL has_blend_idx = has_blend &&
1041 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1042 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1043 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1044 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1045 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1046 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1047 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1049 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1050 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1051 WINED3DVERTEXELEMENT *elements = NULL;
1053 unsigned int size;
1054 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1055 if (has_blend_idx) num_blends--;
1057 /* Compute declaration size */
1058 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1059 has_psize + has_diffuse + has_specular + num_textures;
1061 /* convert the declaration */
1062 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1063 if (!elements) return ~0U;
1065 idx = 0;
1066 if (has_pos) {
1067 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1068 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1069 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1071 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1072 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1073 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1075 else {
1076 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1077 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1079 elements[idx].usage_idx = 0;
1080 idx++;
1082 if (has_blend && (num_blends > 0)) {
1083 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1084 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1085 else {
1086 switch(num_blends) {
1087 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1088 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1089 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1090 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1091 default:
1092 ERR("Unexpected amount of blend values: %u\n", num_blends);
1095 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1096 elements[idx].usage_idx = 0;
1097 idx++;
1099 if (has_blend_idx) {
1100 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1101 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1102 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1103 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1104 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1105 else
1106 elements[idx].format = WINED3DFMT_R32_FLOAT;
1107 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1108 elements[idx].usage_idx = 0;
1109 idx++;
1111 if (has_normal) {
1112 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1113 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1114 elements[idx].usage_idx = 0;
1115 idx++;
1117 if (has_psize) {
1118 elements[idx].format = WINED3DFMT_R32_FLOAT;
1119 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1120 elements[idx].usage_idx = 0;
1121 idx++;
1123 if (has_diffuse) {
1124 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1125 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1126 elements[idx].usage_idx = 0;
1127 idx++;
1129 if (has_specular) {
1130 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1131 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1132 elements[idx].usage_idx = 1;
1133 idx++;
1135 for (idx2 = 0; idx2 < num_textures; idx2++) {
1136 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1137 switch (numcoords) {
1138 case WINED3DFVF_TEXTUREFORMAT1:
1139 elements[idx].format = WINED3DFMT_R32_FLOAT;
1140 break;
1141 case WINED3DFVF_TEXTUREFORMAT2:
1142 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1143 break;
1144 case WINED3DFVF_TEXTUREFORMAT3:
1145 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1146 break;
1147 case WINED3DFVF_TEXTUREFORMAT4:
1148 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1149 break;
1151 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1152 elements[idx].usage_idx = idx2;
1153 idx++;
1156 /* Now compute offsets, and initialize the rest of the fields */
1157 for (idx = 0, offset = 0; idx < size; ++idx)
1159 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1160 elements[idx].input_slot = 0;
1161 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1162 elements[idx].offset = offset;
1163 offset += format_desc->component_count * format_desc->component_size;
1166 *ppVertexElements = elements;
1167 return size;
1170 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1171 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1172 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1175 WINED3DVERTEXELEMENT *elements;
1176 unsigned int size;
1177 DWORD hr;
1179 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1181 size = ConvertFvfToDeclaration(This, fvf, &elements);
1182 if (size == ~0U) return E_OUTOFMEMORY;
1184 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1185 HeapFree(GetProcessHeap(), 0, elements);
1186 return hr;
1189 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1190 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1191 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1192 const struct wined3d_parent_ops *parent_ops)
1194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1195 IWineD3DVertexShaderImpl *object;
1196 HRESULT hr;
1198 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1199 if (!object)
1201 ERR("Failed to allocate shader memory.\n");
1202 return E_OUTOFMEMORY;
1205 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1206 if (FAILED(hr))
1208 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1209 HeapFree(GetProcessHeap(), 0, object);
1210 return hr;
1213 TRACE("Created vertex shader %p.\n", object);
1214 *ppVertexShader = (IWineD3DVertexShader *)object;
1216 return WINED3D_OK;
1219 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1220 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1221 IWineD3DGeometryShader **shader, IUnknown *parent,
1222 const struct wined3d_parent_ops *parent_ops)
1224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1225 struct wined3d_geometryshader *object;
1226 HRESULT hr;
1228 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1229 if (!object)
1231 ERR("Failed to allocate shader memory.\n");
1232 return E_OUTOFMEMORY;
1235 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1236 if (FAILED(hr))
1238 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1239 HeapFree(GetProcessHeap(), 0, object);
1240 return hr;
1243 TRACE("Created geometry shader %p.\n", object);
1244 *shader = (IWineD3DGeometryShader *)object;
1246 return WINED3D_OK;
1249 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1250 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1251 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1252 const struct wined3d_parent_ops *parent_ops)
1254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1255 IWineD3DPixelShaderImpl *object;
1256 HRESULT hr;
1258 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1259 if (!object)
1261 ERR("Failed to allocate shader memory.\n");
1262 return E_OUTOFMEMORY;
1265 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1266 if (FAILED(hr))
1268 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1269 HeapFree(GetProcessHeap(), 0, object);
1270 return hr;
1273 TRACE("Created pixel shader %p.\n", object);
1274 *ppPixelShader = (IWineD3DPixelShader *)object;
1276 return WINED3D_OK;
1279 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1280 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1283 IWineD3DPaletteImpl *object;
1284 HRESULT hr;
1285 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1287 /* Create the new object */
1288 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1289 if(!object) {
1290 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1291 return E_OUTOFMEMORY;
1294 object->lpVtbl = &IWineD3DPalette_Vtbl;
1295 object->ref = 1;
1296 object->Flags = Flags;
1297 object->parent = Parent;
1298 object->device = This;
1299 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1300 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1302 if(!object->hpal) {
1303 HeapFree( GetProcessHeap(), 0, object);
1304 return E_OUTOFMEMORY;
1307 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1308 if(FAILED(hr)) {
1309 IWineD3DPalette_Release((IWineD3DPalette *) object);
1310 return hr;
1313 *Palette = (IWineD3DPalette *) object;
1315 return WINED3D_OK;
1318 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1319 HBITMAP hbm;
1320 BITMAP bm;
1321 HRESULT hr;
1322 HDC dcb = NULL, dcs = NULL;
1323 WINEDDCOLORKEY colorkey;
1325 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1326 if(hbm)
1328 GetObjectA(hbm, sizeof(BITMAP), &bm);
1329 dcb = CreateCompatibleDC(NULL);
1330 if(!dcb) goto out;
1331 SelectObject(dcb, hbm);
1333 else
1335 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1336 * couldn't be loaded
1338 memset(&bm, 0, sizeof(bm));
1339 bm.bmWidth = 32;
1340 bm.bmHeight = 32;
1343 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1344 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1345 NULL, &wined3d_null_parent_ops);
1346 if(FAILED(hr)) {
1347 ERR("Wine logo requested, but failed to create surface\n");
1348 goto out;
1351 if(dcb) {
1352 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1353 if(FAILED(hr)) goto out;
1354 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1355 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1357 colorkey.dwColorSpaceLowValue = 0;
1358 colorkey.dwColorSpaceHighValue = 0;
1359 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1360 } else {
1361 /* Fill the surface with a white color to show that wined3d is there */
1362 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1365 out:
1366 if (dcb) DeleteDC(dcb);
1367 if (hbm) DeleteObject(hbm);
1370 /* Context activation is done by the caller. */
1371 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1373 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1374 unsigned int i;
1375 /* Under DirectX you can have texture stage operations even if no texture is
1376 bound, whereas opengl will only do texture operations when a valid texture is
1377 bound. We emulate this by creating dummy textures and binding them to each
1378 texture stage, but disable all stages by default. Hence if a stage is enabled
1379 then the default texture will kick in until replaced by a SetTexture call */
1380 ENTER_GL();
1382 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1384 /* The dummy texture does not have client storage backing */
1385 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1386 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1389 for (i = 0; i < gl_info->limits.textures; ++i)
1391 GLubyte white = 255;
1393 /* Make appropriate texture active */
1394 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1395 checkGLcall("glActiveTextureARB");
1397 /* Generate an opengl texture name */
1398 glGenTextures(1, &This->dummyTextureName[i]);
1399 checkGLcall("glGenTextures");
1400 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1402 /* Generate a dummy 2d texture (not using 1d because they cause many
1403 * DRI drivers fall back to sw) */
1404 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1405 checkGLcall("glBindTexture");
1407 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1408 checkGLcall("glTexImage2D");
1411 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1413 /* Reenable because if supported it is enabled by default */
1414 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1415 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1418 LEAVE_GL();
1421 /* Context activation is done by the caller. */
1422 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1424 ENTER_GL();
1425 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1426 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1427 LEAVE_GL();
1429 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1432 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1433 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1436 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1437 IWineD3DSwapChainImpl *swapchain = NULL;
1438 struct wined3d_context *context;
1439 HRESULT hr;
1440 DWORD state;
1441 unsigned int i;
1443 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1445 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1446 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1448 if (!pPresentationParameters->Windowed)
1450 This->focus_window = This->createParms.hFocusWindow;
1451 if (!This->focus_window) This->focus_window = pPresentationParameters->hDeviceWindow;
1452 if (!wined3d_register_window(This->focus_window, This))
1454 ERR("Failed to register window %p.\n", This->focus_window);
1455 return E_FAIL;
1459 TRACE("(%p) : Creating stateblock\n", This);
1460 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1461 hr = IWineD3DDevice_CreateStateBlock(iface,
1462 WINED3DSBT_INIT,
1463 (IWineD3DStateBlock **)&This->stateBlock,
1464 NULL);
1465 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1466 WARN("Failed to create stateblock\n");
1467 goto err_out;
1469 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1470 This->updateStateBlock = This->stateBlock;
1471 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1473 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1474 sizeof(IWineD3DSurface *) * gl_info->limits.buffers);
1475 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1476 sizeof(GLenum) * gl_info->limits.buffers);
1478 This->NumberOfPalettes = 1;
1479 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1480 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1481 ERR("Out of memory!\n");
1482 hr = E_OUTOFMEMORY;
1483 goto err_out;
1485 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1486 if(!This->palettes[0]) {
1487 ERR("Out of memory!\n");
1488 hr = E_OUTOFMEMORY;
1489 goto err_out;
1491 for (i = 0; i < 256; ++i) {
1492 This->palettes[0][i].peRed = 0xFF;
1493 This->palettes[0][i].peGreen = 0xFF;
1494 This->palettes[0][i].peBlue = 0xFF;
1495 This->palettes[0][i].peFlags = 0xFF;
1497 This->currentPalette = 0;
1499 /* Initialize the texture unit mapping to a 1:1 mapping */
1500 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1502 if (state < gl_info->limits.fragment_samplers)
1504 This->texUnitMap[state] = state;
1505 This->rev_tex_unit_map[state] = state;
1506 } else {
1507 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1508 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1512 if (This->focus_window) SetFocus(This->focus_window);
1514 /* Setup the implicit swapchain. This also initializes a context. */
1515 TRACE("Creating implicit swapchain\n");
1516 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1517 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1518 if (FAILED(hr))
1520 WARN("Failed to create implicit swapchain\n");
1521 goto err_out;
1524 This->NumberOfSwapChains = 1;
1525 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1526 if(!This->swapchains) {
1527 ERR("Out of memory!\n");
1528 goto err_out;
1530 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1532 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1533 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1534 This->render_targets[0] = swapchain->backBuffer[0];
1536 else {
1537 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1538 This->render_targets[0] = swapchain->frontBuffer;
1540 IWineD3DSurface_AddRef(This->render_targets[0]);
1542 /* Depth Stencil support */
1543 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1544 if (NULL != This->stencilBufferTarget) {
1545 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1548 hr = This->shader_backend->shader_alloc_private(iface);
1549 if(FAILED(hr)) {
1550 TRACE("Shader private data couldn't be allocated\n");
1551 goto err_out;
1553 hr = This->frag_pipe->alloc_private(iface);
1554 if(FAILED(hr)) {
1555 TRACE("Fragment pipeline private data couldn't be allocated\n");
1556 goto err_out;
1558 hr = This->blitter->alloc_private(iface);
1559 if(FAILED(hr)) {
1560 TRACE("Blitter private data couldn't be allocated\n");
1561 goto err_out;
1564 /* Set up some starting GL setup */
1566 /* Setup all the devices defaults */
1567 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1569 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1571 create_dummy_textures(This);
1573 ENTER_GL();
1575 /* Initialize the current view state */
1576 This->view_ident = 1;
1577 This->contexts[0]->last_was_rhw = 0;
1578 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1579 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1581 switch(wined3d_settings.offscreen_rendering_mode) {
1582 case ORM_FBO:
1583 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1584 break;
1586 case ORM_PBUFFER:
1587 This->offscreenBuffer = GL_BACK;
1588 break;
1590 case ORM_BACKBUFFER:
1592 if (context_get_current()->aux_buffers > 0)
1594 TRACE("Using auxilliary buffer for offscreen rendering\n");
1595 This->offscreenBuffer = GL_AUX0;
1596 } else {
1597 TRACE("Using back buffer for offscreen rendering\n");
1598 This->offscreenBuffer = GL_BACK;
1603 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1604 LEAVE_GL();
1606 context_release(context);
1608 /* Clear the screen */
1609 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1610 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1611 0x00, 1.0f, 0);
1613 This->d3d_initialized = TRUE;
1615 if(wined3d_settings.logo) {
1616 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1618 This->highest_dirty_ps_const = 0;
1619 This->highest_dirty_vs_const = 0;
1620 return WINED3D_OK;
1622 err_out:
1623 HeapFree(GetProcessHeap(), 0, This->render_targets);
1624 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1625 HeapFree(GetProcessHeap(), 0, This->swapchains);
1626 This->NumberOfSwapChains = 0;
1627 if(This->palettes) {
1628 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1629 HeapFree(GetProcessHeap(), 0, This->palettes);
1631 This->NumberOfPalettes = 0;
1632 if(swapchain) {
1633 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1635 if(This->stateBlock) {
1636 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1637 This->stateBlock = NULL;
1639 if (This->blit_priv) {
1640 This->blitter->free_private(iface);
1642 if (This->fragment_priv) {
1643 This->frag_pipe->free_private(iface);
1645 if (This->shader_priv) {
1646 This->shader_backend->shader_free_private(iface);
1648 if (This->focus_window) wined3d_unregister_window(This->focus_window);
1649 return hr;
1652 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1653 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1656 IWineD3DSwapChainImpl *swapchain = NULL;
1657 HRESULT hr;
1659 /* Setup the implicit swapchain */
1660 TRACE("Creating implicit swapchain\n");
1661 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1662 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1663 if (FAILED(hr))
1665 WARN("Failed to create implicit swapchain\n");
1666 goto err_out;
1669 This->NumberOfSwapChains = 1;
1670 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1671 if(!This->swapchains) {
1672 ERR("Out of memory!\n");
1673 goto err_out;
1675 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1676 return WINED3D_OK;
1678 err_out:
1679 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1680 return hr;
1683 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1685 IWineD3DResource_UnLoad(resource);
1686 IWineD3DResource_Release(resource);
1687 return WINED3D_OK;
1690 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1691 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1694 const struct wined3d_gl_info *gl_info;
1695 struct wined3d_context *context;
1696 int sampler;
1697 UINT i;
1698 TRACE("(%p)\n", This);
1700 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1702 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1703 * it was created. Thus make sure a context is active for the glDelete* calls
1705 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1706 gl_info = context->gl_info;
1708 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1710 /* Unload resources */
1711 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1713 TRACE("Deleting high order patches\n");
1714 for(i = 0; i < PATCHMAP_SIZE; i++) {
1715 struct list *e1, *e2;
1716 struct WineD3DRectPatch *patch;
1717 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1718 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1719 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1723 /* Delete the palette conversion shader if it is around */
1724 if(This->paletteConversionShader) {
1725 ENTER_GL();
1726 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
1727 LEAVE_GL();
1728 This->paletteConversionShader = 0;
1731 /* Delete the pbuffer context if there is any */
1732 if(This->pbufferContext) context_destroy(This, This->pbufferContext);
1734 /* Delete the mouse cursor texture */
1735 if(This->cursorTexture) {
1736 ENTER_GL();
1737 glDeleteTextures(1, &This->cursorTexture);
1738 LEAVE_GL();
1739 This->cursorTexture = 0;
1742 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1743 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1745 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1746 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1749 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1750 * private data, it might contain opengl pointers
1752 if(This->depth_blt_texture) {
1753 ENTER_GL();
1754 glDeleteTextures(1, &This->depth_blt_texture);
1755 LEAVE_GL();
1756 This->depth_blt_texture = 0;
1758 if (This->depth_blt_rb) {
1759 ENTER_GL();
1760 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1761 LEAVE_GL();
1762 This->depth_blt_rb = 0;
1763 This->depth_blt_rb_w = 0;
1764 This->depth_blt_rb_h = 0;
1767 /* Release the update stateblock */
1768 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1769 if(This->updateStateBlock != This->stateBlock)
1770 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1772 This->updateStateBlock = NULL;
1774 { /* because were not doing proper internal refcounts releasing the primary state block
1775 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1776 to set this->stateBlock = NULL; first */
1777 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1778 This->stateBlock = NULL;
1780 /* Release the stateblock */
1781 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1782 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1786 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1787 This->blitter->free_private(iface);
1788 This->frag_pipe->free_private(iface);
1789 This->shader_backend->shader_free_private(iface);
1791 /* Release the buffers (with sanity checks)*/
1792 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1793 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1794 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
1795 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
1797 This->stencilBufferTarget = NULL;
1799 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1800 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1801 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1803 TRACE("Setting rendertarget to NULL\n");
1804 This->render_targets[0] = NULL;
1806 if (This->auto_depth_stencil_buffer) {
1807 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
1809 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1811 This->auto_depth_stencil_buffer = NULL;
1814 context_release(context);
1816 for(i=0; i < This->NumberOfSwapChains; i++) {
1817 TRACE("Releasing the implicit swapchain %d\n", i);
1818 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1819 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1823 HeapFree(GetProcessHeap(), 0, This->swapchains);
1824 This->swapchains = NULL;
1825 This->NumberOfSwapChains = 0;
1827 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1828 HeapFree(GetProcessHeap(), 0, This->palettes);
1829 This->palettes = NULL;
1830 This->NumberOfPalettes = 0;
1832 HeapFree(GetProcessHeap(), 0, This->render_targets);
1833 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1834 This->render_targets = NULL;
1835 This->draw_buffers = NULL;
1837 This->d3d_initialized = FALSE;
1839 if (This->focus_window) wined3d_unregister_window(This->focus_window);
1841 return WINED3D_OK;
1844 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1846 unsigned int i;
1848 for(i=0; i < This->NumberOfSwapChains; i++) {
1849 TRACE("Releasing the implicit swapchain %d\n", i);
1850 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1851 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1855 HeapFree(GetProcessHeap(), 0, This->swapchains);
1856 This->swapchains = NULL;
1857 This->NumberOfSwapChains = 0;
1858 return WINED3D_OK;
1861 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1862 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1863 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1865 * There is no way to deactivate thread safety once it is enabled.
1867 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1870 /*For now just store the flag(needed in case of ddraw) */
1871 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1874 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1875 const WINED3DDISPLAYMODE* pMode) {
1876 DEVMODEW devmode;
1877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1878 LONG ret;
1879 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1880 RECT clip_rc;
1882 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1884 /* Resize the screen even without a window:
1885 * The app could have unset it with SetCooperativeLevel, but not called
1886 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1887 * but we don't have any hwnd
1890 memset(&devmode, 0, sizeof(devmode));
1891 devmode.dmSize = sizeof(devmode);
1892 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1893 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1894 devmode.dmPelsWidth = pMode->Width;
1895 devmode.dmPelsHeight = pMode->Height;
1897 devmode.dmDisplayFrequency = pMode->RefreshRate;
1898 if (pMode->RefreshRate != 0) {
1899 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1902 /* Only change the mode if necessary */
1903 if( (This->ddraw_width == pMode->Width) &&
1904 (This->ddraw_height == pMode->Height) &&
1905 (This->ddraw_format == pMode->Format) &&
1906 (pMode->RefreshRate == 0) ) {
1907 return WINED3D_OK;
1910 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1911 if (ret != DISP_CHANGE_SUCCESSFUL) {
1912 if(devmode.dmDisplayFrequency != 0) {
1913 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1914 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1915 devmode.dmDisplayFrequency = 0;
1916 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1918 if(ret != DISP_CHANGE_SUCCESSFUL) {
1919 return WINED3DERR_NOTAVAILABLE;
1923 /* Store the new values */
1924 This->ddraw_width = pMode->Width;
1925 This->ddraw_height = pMode->Height;
1926 This->ddraw_format = pMode->Format;
1928 /* And finally clip mouse to our screen */
1929 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1930 ClipCursor(&clip_rc);
1932 return WINED3D_OK;
1935 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1936 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1937 *ppD3D = This->wined3d;
1938 TRACE("Returning %p.\n", *ppD3D);
1939 IWineD3D_AddRef(*ppD3D);
1940 return WINED3D_OK;
1943 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1946 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1947 (This->adapter->TextureRam/(1024*1024)),
1948 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
1949 /* return simulated texture memory left */
1950 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
1953 /*****
1954 * Get / Set Stream Source
1955 *****/
1956 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
1957 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
1959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1960 IWineD3DBuffer *oldSrc;
1962 if (StreamNumber >= MAX_STREAMS) {
1963 WARN("Stream out of range %d\n", StreamNumber);
1964 return WINED3DERR_INVALIDCALL;
1965 } else if(OffsetInBytes & 0x3) {
1966 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
1967 return WINED3DERR_INVALIDCALL;
1970 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
1971 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
1973 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
1975 if(oldSrc == pStreamData &&
1976 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
1977 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
1978 TRACE("Application is setting the old values over, nothing to do\n");
1979 return WINED3D_OK;
1982 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
1983 if (pStreamData) {
1984 This->updateStateBlock->streamStride[StreamNumber] = Stride;
1985 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
1988 /* Handle recording of state blocks */
1989 if (This->isRecordingState) {
1990 TRACE("Recording... not performing anything\n");
1991 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
1992 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
1993 return WINED3D_OK;
1996 if (pStreamData != NULL) {
1997 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
1998 IWineD3DBuffer_AddRef(pStreamData);
2000 if (oldSrc != NULL) {
2001 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2002 IWineD3DBuffer_Release(oldSrc);
2005 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2007 return WINED3D_OK;
2010 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2011 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2015 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2016 This->stateBlock->streamSource[StreamNumber],
2017 This->stateBlock->streamOffset[StreamNumber],
2018 This->stateBlock->streamStride[StreamNumber]);
2020 if (StreamNumber >= MAX_STREAMS) {
2021 WARN("Stream out of range %d\n", StreamNumber);
2022 return WINED3DERR_INVALIDCALL;
2024 *pStream = This->stateBlock->streamSource[StreamNumber];
2025 *pStride = This->stateBlock->streamStride[StreamNumber];
2026 if (pOffset) {
2027 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2030 if (*pStream != NULL) {
2031 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2033 return WINED3D_OK;
2036 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2038 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2039 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2041 /* Verify input at least in d3d9 this is invalid*/
2042 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2043 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2044 return WINED3DERR_INVALIDCALL;
2046 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2047 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2048 return WINED3DERR_INVALIDCALL;
2050 if( Divider == 0 ){
2051 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2052 return WINED3DERR_INVALIDCALL;
2055 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2056 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2058 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2059 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2061 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2062 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2063 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2066 return WINED3D_OK;
2069 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2072 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2073 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2075 TRACE("(%p) : returning %d\n", This, *Divider);
2077 return WINED3D_OK;
2080 /*****
2081 * Get / Set & Multiply Transform
2082 *****/
2083 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2086 /* Most of this routine, comments included copied from ddraw tree initially: */
2087 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2089 /* Handle recording of state blocks */
2090 if (This->isRecordingState) {
2091 TRACE("Recording... not performing anything\n");
2092 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2093 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2094 return WINED3D_OK;
2098 * If the new matrix is the same as the current one,
2099 * we cut off any further processing. this seems to be a reasonable
2100 * optimization because as was noticed, some apps (warcraft3 for example)
2101 * tend towards setting the same matrix repeatedly for some reason.
2103 * From here on we assume that the new matrix is different, wherever it matters.
2105 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2106 TRACE("The app is setting the same matrix over again\n");
2107 return WINED3D_OK;
2108 } else {
2109 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2113 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2114 where ViewMat = Camera space, WorldMat = world space.
2116 In OpenGL, camera and world space is combined into GL_MODELVIEW
2117 matrix. The Projection matrix stay projection matrix.
2120 /* Capture the times we can just ignore the change for now */
2121 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2122 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2123 /* Handled by the state manager */
2126 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2127 return WINED3D_OK;
2130 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2132 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2133 *pMatrix = This->stateBlock->transforms[State];
2134 return WINED3D_OK;
2137 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2138 const WINED3DMATRIX *mat = NULL;
2139 WINED3DMATRIX temp;
2141 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2142 * below means it will be recorded in a state block change, but it
2143 * works regardless where it is recorded.
2144 * If this is found to be wrong, change to StateBlock.
2146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2147 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2149 if (State <= HIGHEST_TRANSFORMSTATE)
2151 mat = &This->updateStateBlock->transforms[State];
2152 } else {
2153 FIXME("Unhandled transform state!!\n");
2156 multiply_matrix(&temp, mat, pMatrix);
2158 /* Apply change via set transform - will reapply to eg. lights this way */
2159 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2162 /*****
2163 * Get / Set Light
2164 *****/
2165 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2166 you can reference any indexes you want as long as that number max are enabled at any
2167 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2168 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2169 but when recording, just build a chain pretty much of commands to be replayed. */
2171 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2172 float rho;
2173 struct wined3d_light_info *object = NULL;
2174 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2175 struct list *e;
2177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2178 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2180 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2181 * the gl driver.
2183 if(!pLight) {
2184 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2185 return WINED3DERR_INVALIDCALL;
2188 switch(pLight->Type) {
2189 case WINED3DLIGHT_POINT:
2190 case WINED3DLIGHT_SPOT:
2191 case WINED3DLIGHT_PARALLELPOINT:
2192 case WINED3DLIGHT_GLSPOT:
2193 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2194 * most wanted
2196 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2198 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2199 return WINED3DERR_INVALIDCALL;
2201 break;
2203 case WINED3DLIGHT_DIRECTIONAL:
2204 /* Ignores attenuation */
2205 break;
2207 default:
2208 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2209 return WINED3DERR_INVALIDCALL;
2212 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2214 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2215 if(object->OriginalIndex == Index) break;
2216 object = NULL;
2219 if(!object) {
2220 TRACE("Adding new light\n");
2221 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2222 if(!object) {
2223 ERR("Out of memory error when allocating a light\n");
2224 return E_OUTOFMEMORY;
2226 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2227 object->glIndex = -1;
2228 object->OriginalIndex = Index;
2231 /* Initialize the object */
2232 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,
2233 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2234 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2235 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2236 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2237 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2238 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2240 /* Save away the information */
2241 object->OriginalParms = *pLight;
2243 switch (pLight->Type) {
2244 case WINED3DLIGHT_POINT:
2245 /* Position */
2246 object->lightPosn[0] = pLight->Position.x;
2247 object->lightPosn[1] = pLight->Position.y;
2248 object->lightPosn[2] = pLight->Position.z;
2249 object->lightPosn[3] = 1.0f;
2250 object->cutoff = 180.0f;
2251 /* FIXME: Range */
2252 break;
2254 case WINED3DLIGHT_DIRECTIONAL:
2255 /* Direction */
2256 object->lightPosn[0] = -pLight->Direction.x;
2257 object->lightPosn[1] = -pLight->Direction.y;
2258 object->lightPosn[2] = -pLight->Direction.z;
2259 object->lightPosn[3] = 0.0f;
2260 object->exponent = 0.0f;
2261 object->cutoff = 180.0f;
2262 break;
2264 case WINED3DLIGHT_SPOT:
2265 /* Position */
2266 object->lightPosn[0] = pLight->Position.x;
2267 object->lightPosn[1] = pLight->Position.y;
2268 object->lightPosn[2] = pLight->Position.z;
2269 object->lightPosn[3] = 1.0f;
2271 /* Direction */
2272 object->lightDirn[0] = pLight->Direction.x;
2273 object->lightDirn[1] = pLight->Direction.y;
2274 object->lightDirn[2] = pLight->Direction.z;
2275 object->lightDirn[3] = 1.0f;
2278 * opengl-ish and d3d-ish spot lights use too different models for the
2279 * light "intensity" as a function of the angle towards the main light direction,
2280 * so we only can approximate very roughly.
2281 * however spot lights are rather rarely used in games (if ever used at all).
2282 * furthermore if still used, probably nobody pays attention to such details.
2284 if (pLight->Falloff == 0) {
2285 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2286 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2287 * will always be 1.0 for both of them, and we don't have to care for the
2288 * rest of the rather complex calculation
2290 object->exponent = 0.0f;
2291 } else {
2292 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2293 if (rho < 0.0001f) rho = 0.0001f;
2294 object->exponent = -0.3f/logf(cosf(rho/2));
2296 if (object->exponent > 128.0f)
2298 object->exponent = 128.0f;
2300 object->cutoff = pLight->Phi*90/M_PI;
2302 /* FIXME: Range */
2303 break;
2305 default:
2306 FIXME("Unrecognized light type %d\n", pLight->Type);
2309 /* Update the live definitions if the light is currently assigned a glIndex */
2310 if (object->glIndex != -1 && !This->isRecordingState) {
2311 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2313 return WINED3D_OK;
2316 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2318 struct wined3d_light_info *lightInfo = NULL;
2319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2320 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2321 struct list *e;
2322 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2324 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2326 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2327 if(lightInfo->OriginalIndex == Index) break;
2328 lightInfo = NULL;
2331 if (lightInfo == NULL) {
2332 TRACE("Light information requested but light not defined\n");
2333 return WINED3DERR_INVALIDCALL;
2336 *pLight = lightInfo->OriginalParms;
2337 return WINED3D_OK;
2340 /*****
2341 * Get / Set Light Enable
2342 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2343 *****/
2344 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2346 struct wined3d_light_info *lightInfo = NULL;
2347 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2348 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2349 struct list *e;
2350 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2352 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2354 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2355 if(lightInfo->OriginalIndex == Index) break;
2356 lightInfo = NULL;
2358 TRACE("Found light: %p\n", lightInfo);
2360 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2361 if (lightInfo == NULL) {
2363 TRACE("Light enabled requested but light not defined, so defining one!\n");
2364 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2366 /* Search for it again! Should be fairly quick as near head of list */
2367 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2369 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2370 if(lightInfo->OriginalIndex == Index) break;
2371 lightInfo = NULL;
2373 if (lightInfo == NULL) {
2374 FIXME("Adding default lights has failed dismally\n");
2375 return WINED3DERR_INVALIDCALL;
2379 if(!Enable) {
2380 if(lightInfo->glIndex != -1) {
2381 if(!This->isRecordingState) {
2382 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2385 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2386 lightInfo->glIndex = -1;
2387 } else {
2388 TRACE("Light already disabled, nothing to do\n");
2390 lightInfo->enabled = FALSE;
2391 } else {
2392 lightInfo->enabled = TRUE;
2393 if (lightInfo->glIndex != -1) {
2394 /* nop */
2395 TRACE("Nothing to do as light was enabled\n");
2396 } else {
2397 int i;
2398 /* Find a free gl light */
2399 for(i = 0; i < This->maxConcurrentLights; i++) {
2400 if(This->updateStateBlock->activeLights[i] == NULL) {
2401 This->updateStateBlock->activeLights[i] = lightInfo;
2402 lightInfo->glIndex = i;
2403 break;
2406 if(lightInfo->glIndex == -1) {
2407 /* Our tests show that Windows returns D3D_OK in this situation, even with
2408 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2409 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2410 * as well for those lights.
2412 * TODO: Test how this affects rendering
2414 WARN("Too many concurrently active lights\n");
2415 return WINED3D_OK;
2418 /* i == lightInfo->glIndex */
2419 if(!This->isRecordingState) {
2420 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2425 return WINED3D_OK;
2428 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2430 struct wined3d_light_info *lightInfo = NULL;
2431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2432 struct list *e;
2433 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2434 TRACE("(%p) : for idx(%d)\n", This, Index);
2436 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2438 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2439 if(lightInfo->OriginalIndex == Index) break;
2440 lightInfo = NULL;
2443 if (lightInfo == NULL) {
2444 TRACE("Light enabled state requested but light not defined\n");
2445 return WINED3DERR_INVALIDCALL;
2447 /* true is 128 according to SetLightEnable */
2448 *pEnable = lightInfo->enabled ? 128 : 0;
2449 return WINED3D_OK;
2452 /*****
2453 * Get / Set Clip Planes
2454 *****/
2455 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2457 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2459 /* Validate Index */
2460 if (Index >= This->adapter->gl_info.limits.clipplanes)
2462 TRACE("Application has requested clipplane this device doesn't support\n");
2463 return WINED3DERR_INVALIDCALL;
2466 This->updateStateBlock->changed.clipplane |= 1 << Index;
2468 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2469 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2470 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2471 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2472 TRACE("Application is setting old values over, nothing to do\n");
2473 return WINED3D_OK;
2476 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2477 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2478 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2479 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2481 /* Handle recording of state blocks */
2482 if (This->isRecordingState) {
2483 TRACE("Recording... not performing anything\n");
2484 return WINED3D_OK;
2487 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2489 return WINED3D_OK;
2492 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2494 TRACE("(%p) : for idx %d\n", This, Index);
2496 /* Validate Index */
2497 if (Index >= This->adapter->gl_info.limits.clipplanes)
2499 TRACE("Application has requested clipplane this device doesn't support\n");
2500 return WINED3DERR_INVALIDCALL;
2503 pPlane[0] = This->stateBlock->clipplane[Index][0];
2504 pPlane[1] = This->stateBlock->clipplane[Index][1];
2505 pPlane[2] = This->stateBlock->clipplane[Index][2];
2506 pPlane[3] = This->stateBlock->clipplane[Index][3];
2507 return WINED3D_OK;
2510 /*****
2511 * Get / Set Clip Plane Status
2512 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2513 *****/
2514 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2516 FIXME("(%p) : stub\n", This);
2517 if (NULL == pClipStatus) {
2518 return WINED3DERR_INVALIDCALL;
2520 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2521 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2522 return WINED3D_OK;
2525 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2527 FIXME("(%p) : stub\n", This);
2528 if (NULL == pClipStatus) {
2529 return WINED3DERR_INVALIDCALL;
2531 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2532 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2533 return WINED3D_OK;
2536 /*****
2537 * Get / Set Material
2538 *****/
2539 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2540 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2542 This->updateStateBlock->changed.material = TRUE;
2543 This->updateStateBlock->material = *pMaterial;
2545 /* Handle recording of state blocks */
2546 if (This->isRecordingState) {
2547 TRACE("Recording... not performing anything\n");
2548 return WINED3D_OK;
2551 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2552 return WINED3D_OK;
2555 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2557 *pMaterial = This->updateStateBlock->material;
2558 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2559 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2560 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2561 pMaterial->Ambient.b, pMaterial->Ambient.a);
2562 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2563 pMaterial->Specular.b, pMaterial->Specular.a);
2564 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2565 pMaterial->Emissive.b, pMaterial->Emissive.a);
2566 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2568 return WINED3D_OK;
2571 /*****
2572 * Get / Set Indices
2573 *****/
2574 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2575 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2578 IWineD3DBuffer *oldIdxs;
2580 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2581 oldIdxs = This->updateStateBlock->pIndexData;
2583 This->updateStateBlock->changed.indices = TRUE;
2584 This->updateStateBlock->pIndexData = pIndexData;
2585 This->updateStateBlock->IndexFmt = fmt;
2587 /* Handle recording of state blocks */
2588 if (This->isRecordingState) {
2589 TRACE("Recording... not performing anything\n");
2590 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2591 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2592 return WINED3D_OK;
2595 if(oldIdxs != pIndexData) {
2596 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2597 if(pIndexData) {
2598 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2599 IWineD3DBuffer_AddRef(pIndexData);
2601 if(oldIdxs) {
2602 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2603 IWineD3DBuffer_Release(oldIdxs);
2607 return WINED3D_OK;
2610 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2614 *ppIndexData = This->stateBlock->pIndexData;
2616 /* up ref count on ppindexdata */
2617 if (*ppIndexData) {
2618 IWineD3DBuffer_AddRef(*ppIndexData);
2619 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2620 }else{
2621 TRACE("(%p) No index data set\n", This);
2623 TRACE("Returning %p\n", *ppIndexData);
2625 return WINED3D_OK;
2628 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2629 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2631 TRACE("(%p)->(%d)\n", This, BaseIndex);
2633 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2634 TRACE("Application is setting the old value over, nothing to do\n");
2635 return WINED3D_OK;
2638 This->updateStateBlock->baseVertexIndex = BaseIndex;
2640 if (This->isRecordingState) {
2641 TRACE("Recording... not performing anything\n");
2642 return WINED3D_OK;
2644 /* The base vertex index affects the stream sources */
2645 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2646 return WINED3D_OK;
2649 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2651 TRACE("(%p) : base_index %p\n", This, base_index);
2653 *base_index = This->stateBlock->baseVertexIndex;
2655 TRACE("Returning %u\n", *base_index);
2657 return WINED3D_OK;
2660 /*****
2661 * Get / Set Viewports
2662 *****/
2663 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2666 TRACE("(%p)\n", This);
2667 This->updateStateBlock->changed.viewport = TRUE;
2668 This->updateStateBlock->viewport = *pViewport;
2670 /* Handle recording of state blocks */
2671 if (This->isRecordingState) {
2672 TRACE("Recording... not performing anything\n");
2673 return WINED3D_OK;
2676 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2677 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2679 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2680 return WINED3D_OK;
2684 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2686 TRACE("(%p)\n", This);
2687 *pViewport = This->stateBlock->viewport;
2688 return WINED3D_OK;
2691 /*****
2692 * Get / Set Render States
2693 * TODO: Verify against dx9 definitions
2694 *****/
2695 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2698 DWORD oldValue = This->stateBlock->renderState[State];
2700 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2702 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2703 This->updateStateBlock->renderState[State] = Value;
2705 /* Handle recording of state blocks */
2706 if (This->isRecordingState) {
2707 TRACE("Recording... not performing anything\n");
2708 return WINED3D_OK;
2711 /* Compared here and not before the assignment to allow proper stateblock recording */
2712 if(Value == oldValue) {
2713 TRACE("Application is setting the old value over, nothing to do\n");
2714 } else {
2715 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2718 return WINED3D_OK;
2721 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2723 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2724 *pValue = This->stateBlock->renderState[State];
2725 return WINED3D_OK;
2728 /*****
2729 * Get / Set Sampler States
2730 * TODO: Verify against dx9 definitions
2731 *****/
2733 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2735 DWORD oldValue;
2737 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2738 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2740 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2741 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2744 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2745 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2746 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2749 * SetSampler is designed to allow for more than the standard up to 8 textures
2750 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2751 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2753 * http://developer.nvidia.com/object/General_FAQ.html#t6
2755 * There are two new settings for GForce
2756 * the sampler one:
2757 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2758 * and the texture one:
2759 * GL_MAX_TEXTURE_COORDS_ARB.
2760 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2761 ******************/
2763 oldValue = This->stateBlock->samplerState[Sampler][Type];
2764 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2765 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2767 /* Handle recording of state blocks */
2768 if (This->isRecordingState) {
2769 TRACE("Recording... not performing anything\n");
2770 return WINED3D_OK;
2773 if(oldValue == Value) {
2774 TRACE("Application is setting the old value over, nothing to do\n");
2775 return WINED3D_OK;
2778 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2780 return WINED3D_OK;
2783 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2786 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2787 This, Sampler, debug_d3dsamplerstate(Type), Type);
2789 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2790 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2793 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2794 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2795 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2797 *Value = This->stateBlock->samplerState[Sampler][Type];
2798 TRACE("(%p) : Returning %#x\n", This, *Value);
2800 return WINED3D_OK;
2803 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2806 This->updateStateBlock->changed.scissorRect = TRUE;
2807 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2808 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2809 return WINED3D_OK;
2811 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2813 if(This->isRecordingState) {
2814 TRACE("Recording... not performing anything\n");
2815 return WINED3D_OK;
2818 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2820 return WINED3D_OK;
2823 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2826 *pRect = This->updateStateBlock->scissorRect;
2827 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2828 return WINED3D_OK;
2831 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2833 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2835 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2837 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2838 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2840 This->updateStateBlock->vertexDecl = pDecl;
2841 This->updateStateBlock->changed.vertexDecl = TRUE;
2843 if (This->isRecordingState) {
2844 TRACE("Recording... not performing anything\n");
2845 return WINED3D_OK;
2846 } else if(pDecl == oldDecl) {
2847 /* Checked after the assignment to allow proper stateblock recording */
2848 TRACE("Application is setting the old declaration over, nothing to do\n");
2849 return WINED3D_OK;
2852 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2853 return WINED3D_OK;
2856 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2859 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2861 *ppDecl = This->stateBlock->vertexDecl;
2862 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2863 return WINED3D_OK;
2866 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2868 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2870 This->updateStateBlock->vertexShader = pShader;
2871 This->updateStateBlock->changed.vertexShader = TRUE;
2873 if (This->isRecordingState) {
2874 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2875 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2876 TRACE("Recording... not performing anything\n");
2877 return WINED3D_OK;
2878 } else if(oldShader == pShader) {
2879 /* Checked here to allow proper stateblock recording */
2880 TRACE("App is setting the old shader over, nothing to do\n");
2881 return WINED3D_OK;
2884 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2885 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2886 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2888 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2890 return WINED3D_OK;
2893 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2896 if (NULL == ppShader) {
2897 return WINED3DERR_INVALIDCALL;
2899 *ppShader = This->stateBlock->vertexShader;
2900 if( NULL != *ppShader)
2901 IWineD3DVertexShader_AddRef(*ppShader);
2903 TRACE("(%p) : returning %p\n", This, *ppShader);
2904 return WINED3D_OK;
2907 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2908 IWineD3DDevice *iface,
2909 UINT start,
2910 CONST BOOL *srcData,
2911 UINT count) {
2913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2914 unsigned int i, cnt = min(count, MAX_CONST_B - start);
2916 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2917 iface, srcData, start, count);
2919 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
2921 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2922 for (i = 0; i < cnt; i++)
2923 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2925 for (i = start; i < cnt + start; ++i) {
2926 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
2929 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2931 return WINED3D_OK;
2934 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2935 IWineD3DDevice *iface,
2936 UINT start,
2937 BOOL *dstData,
2938 UINT count) {
2940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2941 int cnt = min(count, MAX_CONST_B - start);
2943 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2944 iface, dstData, start, count);
2946 if (dstData == NULL || cnt < 0)
2947 return WINED3DERR_INVALIDCALL;
2949 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2950 return WINED3D_OK;
2953 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2954 IWineD3DDevice *iface,
2955 UINT start,
2956 CONST int *srcData,
2957 UINT count) {
2959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2960 unsigned int i, cnt = min(count, MAX_CONST_I - start);
2962 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2963 iface, srcData, start, count);
2965 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
2967 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2968 for (i = 0; i < cnt; i++)
2969 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2970 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2972 for (i = start; i < cnt + start; ++i) {
2973 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
2976 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2978 return WINED3D_OK;
2981 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2982 IWineD3DDevice *iface,
2983 UINT start,
2984 int *dstData,
2985 UINT count) {
2987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2988 int cnt = min(count, MAX_CONST_I - start);
2990 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2991 iface, dstData, start, count);
2993 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2994 return WINED3DERR_INVALIDCALL;
2996 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
2997 return WINED3D_OK;
3000 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3001 IWineD3DDevice *iface,
3002 UINT start,
3003 CONST float *srcData,
3004 UINT count) {
3006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3007 UINT i;
3009 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3010 iface, srcData, start, count);
3012 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3013 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3014 return WINED3DERR_INVALIDCALL;
3016 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3017 if(TRACE_ON(d3d)) {
3018 for (i = 0; i < count; i++)
3019 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3020 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3023 if (!This->isRecordingState)
3025 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3026 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3029 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3030 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3032 return WINED3D_OK;
3035 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3036 IWineD3DDevice *iface,
3037 UINT start,
3038 float *dstData,
3039 UINT count) {
3041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3042 int cnt = min(count, This->d3d_vshader_constantF - start);
3044 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3045 iface, dstData, start, count);
3047 if (dstData == NULL || cnt < 0)
3048 return WINED3DERR_INVALIDCALL;
3050 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3051 return WINED3D_OK;
3054 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3055 DWORD i;
3056 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3058 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3062 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3064 DWORD i = This->rev_tex_unit_map[unit];
3065 DWORD j = This->texUnitMap[stage];
3067 This->texUnitMap[stage] = unit;
3068 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3070 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3073 This->rev_tex_unit_map[unit] = stage;
3074 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3076 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3080 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3081 int i;
3083 This->fixed_function_usage_map = 0;
3084 for (i = 0; i < MAX_TEXTURES; ++i) {
3085 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3086 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3087 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3088 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3089 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3090 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3091 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3092 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3094 if (color_op == WINED3DTOP_DISABLE) {
3095 /* Not used, and disable higher stages */
3096 break;
3099 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3100 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3101 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3102 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3103 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3104 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3105 This->fixed_function_usage_map |= (1 << i);
3108 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3109 This->fixed_function_usage_map |= (1 << (i + 1));
3114 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3116 unsigned int i, tex;
3117 WORD ffu_map;
3119 device_update_fixed_function_usage_map(This);
3120 ffu_map = This->fixed_function_usage_map;
3122 if (This->max_ffp_textures == gl_info->limits.texture_stages
3123 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3125 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3127 if (!(ffu_map & 1)) continue;
3129 if (This->texUnitMap[i] != i) {
3130 device_map_stage(This, i, i);
3131 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3132 markTextureStagesDirty(This, i);
3135 return;
3138 /* Now work out the mapping */
3139 tex = 0;
3140 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3142 if (!(ffu_map & 1)) continue;
3144 if (This->texUnitMap[i] != tex) {
3145 device_map_stage(This, i, tex);
3146 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3147 markTextureStagesDirty(This, i);
3150 ++tex;
3154 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3156 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3157 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3158 unsigned int i;
3160 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3161 if (sampler_type[i] && This->texUnitMap[i] != i)
3163 device_map_stage(This, i, i);
3164 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3165 if (i < gl_info->limits.texture_stages)
3167 markTextureStagesDirty(This, i);
3173 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3174 const DWORD *vshader_sampler_tokens, DWORD unit)
3176 DWORD current_mapping = This->rev_tex_unit_map[unit];
3178 /* Not currently used */
3179 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3181 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3182 /* Used by a fragment sampler */
3184 if (!pshader_sampler_tokens) {
3185 /* No pixel shader, check fixed function */
3186 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3189 /* Pixel shader, check the shader's sampler map */
3190 return !pshader_sampler_tokens[current_mapping];
3193 /* Used by a vertex sampler */
3194 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3197 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3199 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3200 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3201 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3202 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3203 int i;
3205 if (ps) {
3206 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3208 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3209 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3210 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3213 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3214 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3215 if (vshader_sampler_type[i])
3217 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3219 /* Already mapped somewhere */
3220 continue;
3223 while (start >= 0) {
3224 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3226 device_map_stage(This, vsampler_idx, start);
3227 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3229 --start;
3230 break;
3233 --start;
3239 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3241 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3242 BOOL vs = use_vs(This->stateBlock);
3243 BOOL ps = use_ps(This->stateBlock);
3245 * Rules are:
3246 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3247 * that would be really messy and require shader recompilation
3248 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3249 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3251 if (ps) device_map_psamplers(This, gl_info);
3252 else device_map_fixed_function_samplers(This, gl_info);
3254 if (vs) device_map_vsamplers(This, ps, gl_info);
3257 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3259 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3260 This->updateStateBlock->pixelShader = pShader;
3261 This->updateStateBlock->changed.pixelShader = TRUE;
3263 /* Handle recording of state blocks */
3264 if (This->isRecordingState) {
3265 TRACE("Recording... not performing anything\n");
3268 if (This->isRecordingState) {
3269 TRACE("Recording... not performing anything\n");
3270 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3271 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3272 return WINED3D_OK;
3275 if(pShader == oldShader) {
3276 TRACE("App is setting the old pixel shader over, nothing to do\n");
3277 return WINED3D_OK;
3280 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3281 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3283 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3284 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3286 return WINED3D_OK;
3289 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3292 if (NULL == ppShader) {
3293 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3294 return WINED3DERR_INVALIDCALL;
3297 *ppShader = This->stateBlock->pixelShader;
3298 if (NULL != *ppShader) {
3299 IWineD3DPixelShader_AddRef(*ppShader);
3301 TRACE("(%p) : returning %p\n", This, *ppShader);
3302 return WINED3D_OK;
3305 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3306 IWineD3DDevice *iface,
3307 UINT start,
3308 CONST BOOL *srcData,
3309 UINT count) {
3311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3312 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3314 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3315 iface, srcData, start, count);
3317 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3319 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3320 for (i = 0; i < cnt; i++)
3321 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3323 for (i = start; i < cnt + start; ++i) {
3324 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3327 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3329 return WINED3D_OK;
3332 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3333 IWineD3DDevice *iface,
3334 UINT start,
3335 BOOL *dstData,
3336 UINT count) {
3338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3339 int cnt = min(count, MAX_CONST_B - start);
3341 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3342 iface, dstData, start, count);
3344 if (dstData == NULL || cnt < 0)
3345 return WINED3DERR_INVALIDCALL;
3347 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3348 return WINED3D_OK;
3351 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3352 IWineD3DDevice *iface,
3353 UINT start,
3354 CONST int *srcData,
3355 UINT count) {
3357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3358 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3360 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3361 iface, srcData, start, count);
3363 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3365 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3366 for (i = 0; i < cnt; i++)
3367 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3368 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3370 for (i = start; i < cnt + start; ++i) {
3371 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3374 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3376 return WINED3D_OK;
3379 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3380 IWineD3DDevice *iface,
3381 UINT start,
3382 int *dstData,
3383 UINT count) {
3385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3386 int cnt = min(count, MAX_CONST_I - start);
3388 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3389 iface, dstData, start, count);
3391 if (dstData == NULL || cnt < 0)
3392 return WINED3DERR_INVALIDCALL;
3394 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3395 return WINED3D_OK;
3398 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3399 IWineD3DDevice *iface,
3400 UINT start,
3401 CONST float *srcData,
3402 UINT count) {
3404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3405 UINT i;
3407 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3408 iface, srcData, start, count);
3410 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3411 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3412 return WINED3DERR_INVALIDCALL;
3414 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3415 if(TRACE_ON(d3d)) {
3416 for (i = 0; i < count; i++)
3417 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3418 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3421 if (!This->isRecordingState)
3423 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3424 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3427 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3428 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3430 return WINED3D_OK;
3433 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3434 IWineD3DDevice *iface,
3435 UINT start,
3436 float *dstData,
3437 UINT count) {
3439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3440 int cnt = min(count, This->d3d_pshader_constantF - start);
3442 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3443 iface, dstData, start, count);
3445 if (dstData == NULL || cnt < 0)
3446 return WINED3DERR_INVALIDCALL;
3448 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3449 return WINED3D_OK;
3452 /* Context activation is done by the caller. */
3453 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3454 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3455 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3456 DWORD DestFVF)
3458 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3459 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3460 unsigned int i;
3461 WINED3DVIEWPORT vp;
3462 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3463 BOOL doClip;
3464 DWORD numTextures;
3466 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3468 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3471 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3473 ERR("Source has no position mask\n");
3474 return WINED3DERR_INVALIDCALL;
3477 /* We might access VBOs from this code, so hold the lock */
3478 ENTER_GL();
3480 if (dest->resource.allocatedMemory == NULL) {
3481 buffer_get_sysmem(dest);
3484 /* Get a pointer into the destination vbo(create one if none exists) and
3485 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3487 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3489 dest->flags |= WINED3D_BUFFER_CREATEBO;
3490 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3493 if (dest->buffer_object)
3495 unsigned char extrabytes = 0;
3496 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3497 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3498 * this may write 4 extra bytes beyond the area that should be written
3500 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3501 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3502 if(!dest_conv_addr) {
3503 ERR("Out of memory\n");
3504 /* Continue without storing converted vertices */
3506 dest_conv = dest_conv_addr;
3509 /* Should I clip?
3510 * a) WINED3DRS_CLIPPING is enabled
3511 * b) WINED3DVOP_CLIP is passed
3513 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3514 static BOOL warned = FALSE;
3516 * The clipping code is not quite correct. Some things need
3517 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3518 * so disable clipping for now.
3519 * (The graphics in Half-Life are broken, and my processvertices
3520 * test crashes with IDirect3DDevice3)
3521 doClip = TRUE;
3523 doClip = FALSE;
3524 if(!warned) {
3525 warned = TRUE;
3526 FIXME("Clipping is broken and disabled for now\n");
3528 } else doClip = FALSE;
3529 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3531 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3532 WINED3DTS_VIEW,
3533 &view_mat);
3534 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3535 WINED3DTS_PROJECTION,
3536 &proj_mat);
3537 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3538 WINED3DTS_WORLDMATRIX(0),
3539 &world_mat);
3541 TRACE("View mat:\n");
3542 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);
3543 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);
3544 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);
3545 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);
3547 TRACE("Proj mat:\n");
3548 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);
3549 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);
3550 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);
3551 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);
3553 TRACE("World mat:\n");
3554 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);
3555 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);
3556 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);
3557 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);
3559 /* Get the viewport */
3560 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3561 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3562 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3564 multiply_matrix(&mat,&view_mat,&world_mat);
3565 multiply_matrix(&mat,&proj_mat,&mat);
3567 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3569 for (i = 0; i < dwCount; i+= 1) {
3570 unsigned int tex_index;
3572 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3573 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3574 /* The position first */
3575 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3576 const float *p = (const float *)(element->data + i * element->stride);
3577 float x, y, z, rhw;
3578 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3580 /* Multiplication with world, view and projection matrix */
3581 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);
3582 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);
3583 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);
3584 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);
3586 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3588 /* WARNING: The following things are taken from d3d7 and were not yet checked
3589 * against d3d8 or d3d9!
3592 /* Clipping conditions: From msdn
3594 * A vertex is clipped if it does not match the following requirements
3595 * -rhw < x <= rhw
3596 * -rhw < y <= rhw
3597 * 0 < z <= rhw
3598 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3600 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3601 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3605 if( !doClip ||
3606 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3607 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3608 ( rhw > eps ) ) ) {
3610 /* "Normal" viewport transformation (not clipped)
3611 * 1) The values are divided by rhw
3612 * 2) The y axis is negative, so multiply it with -1
3613 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3614 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3615 * 4) Multiply x with Width/2 and add Width/2
3616 * 5) The same for the height
3617 * 6) Add the viewpoint X and Y to the 2D coordinates and
3618 * The minimum Z value to z
3619 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3621 * Well, basically it's simply a linear transformation into viewport
3622 * coordinates
3625 x /= rhw;
3626 y /= rhw;
3627 z /= rhw;
3629 y *= -1;
3631 x *= vp.Width / 2;
3632 y *= vp.Height / 2;
3633 z *= vp.MaxZ - vp.MinZ;
3635 x += vp.Width / 2 + vp.X;
3636 y += vp.Height / 2 + vp.Y;
3637 z += vp.MinZ;
3639 rhw = 1 / rhw;
3640 } else {
3641 /* That vertex got clipped
3642 * Contrary to OpenGL it is not dropped completely, it just
3643 * undergoes a different calculation.
3645 TRACE("Vertex got clipped\n");
3646 x += rhw;
3647 y += rhw;
3649 x /= 2;
3650 y /= 2;
3652 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3653 * outside of the main vertex buffer memory. That needs some more
3654 * investigation...
3658 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3661 ( (float *) dest_ptr)[0] = x;
3662 ( (float *) dest_ptr)[1] = y;
3663 ( (float *) dest_ptr)[2] = z;
3664 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3666 dest_ptr += 3 * sizeof(float);
3668 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3669 dest_ptr += sizeof(float);
3672 if(dest_conv) {
3673 float w = 1 / rhw;
3674 ( (float *) dest_conv)[0] = x * w;
3675 ( (float *) dest_conv)[1] = y * w;
3676 ( (float *) dest_conv)[2] = z * w;
3677 ( (float *) dest_conv)[3] = w;
3679 dest_conv += 3 * sizeof(float);
3681 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3682 dest_conv += sizeof(float);
3686 if (DestFVF & WINED3DFVF_PSIZE) {
3687 dest_ptr += sizeof(DWORD);
3688 if(dest_conv) dest_conv += sizeof(DWORD);
3690 if (DestFVF & WINED3DFVF_NORMAL) {
3691 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3692 const float *normal = (const float *)(element->data + i * element->stride);
3693 /* AFAIK this should go into the lighting information */
3694 FIXME("Didn't expect the destination to have a normal\n");
3695 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3696 if(dest_conv) {
3697 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3701 if (DestFVF & WINED3DFVF_DIFFUSE) {
3702 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3703 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3704 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3706 static BOOL warned = FALSE;
3708 if(!warned) {
3709 ERR("No diffuse color in source, but destination has one\n");
3710 warned = TRUE;
3713 *( (DWORD *) dest_ptr) = 0xffffffff;
3714 dest_ptr += sizeof(DWORD);
3716 if(dest_conv) {
3717 *( (DWORD *) dest_conv) = 0xffffffff;
3718 dest_conv += sizeof(DWORD);
3721 else {
3722 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3723 if(dest_conv) {
3724 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3725 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3726 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3727 dest_conv += sizeof(DWORD);
3732 if (DestFVF & WINED3DFVF_SPECULAR)
3734 /* What's the color value in the feedback buffer? */
3735 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3736 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3737 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3739 static BOOL warned = FALSE;
3741 if(!warned) {
3742 ERR("No specular color in source, but destination has one\n");
3743 warned = TRUE;
3746 *( (DWORD *) dest_ptr) = 0xFF000000;
3747 dest_ptr += sizeof(DWORD);
3749 if(dest_conv) {
3750 *( (DWORD *) dest_conv) = 0xFF000000;
3751 dest_conv += sizeof(DWORD);
3754 else {
3755 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3756 if(dest_conv) {
3757 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3758 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3759 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3760 dest_conv += sizeof(DWORD);
3765 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3766 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3767 const float *tex_coord = (const float *)(element->data + i * element->stride);
3768 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3770 ERR("No source texture, but destination requests one\n");
3771 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3772 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3774 else {
3775 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3776 if(dest_conv) {
3777 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3783 if(dest_conv) {
3784 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3785 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3786 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3787 dwCount * get_flexible_vertex_size(DestFVF),
3788 dest_conv_addr));
3789 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3790 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3793 LEAVE_GL();
3795 return WINED3D_OK;
3797 #undef copy_and_next
3799 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3800 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3801 DWORD DestFVF)
3803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3804 struct wined3d_stream_info stream_info;
3805 struct wined3d_context *context;
3806 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3807 HRESULT hr;
3809 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3811 if(pVertexDecl) {
3812 ERR("Output vertex declaration not implemented yet\n");
3815 /* Need any context to write to the vbo. */
3816 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
3818 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3819 * control the streamIsUP flag, thus restore it afterwards.
3821 This->stateBlock->streamIsUP = FALSE;
3822 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3823 This->stateBlock->streamIsUP = streamWasUP;
3825 if(vbo || SrcStartIndex) {
3826 unsigned int i;
3827 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3828 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3830 * Also get the start index in, but only loop over all elements if there's something to add at all.
3832 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3834 struct wined3d_stream_info_element *e;
3836 if (!(stream_info.use_map & (1 << i))) continue;
3838 e = &stream_info.elements[i];
3839 if (e->buffer_object)
3841 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3842 e->buffer_object = 0;
3843 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3844 ENTER_GL();
3845 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3846 vb->buffer_object = 0;
3847 LEAVE_GL();
3849 if (e->data) e->data += e->stride * SrcStartIndex;
3853 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3854 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3856 context_release(context);
3858 return hr;
3861 /*****
3862 * Get / Set Texture Stage States
3863 * TODO: Verify against dx9 definitions
3864 *****/
3865 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3867 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3868 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3870 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3872 if (Stage >= gl_info->limits.texture_stages)
3874 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3875 Stage, gl_info->limits.texture_stages - 1);
3876 return WINED3D_OK;
3879 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3880 This->updateStateBlock->textureState[Stage][Type] = Value;
3882 if (This->isRecordingState) {
3883 TRACE("Recording... not performing anything\n");
3884 return WINED3D_OK;
3887 /* Checked after the assignments to allow proper stateblock recording */
3888 if(oldValue == Value) {
3889 TRACE("App is setting the old value over, nothing to do\n");
3890 return WINED3D_OK;
3893 if(Stage > This->stateBlock->lowest_disabled_stage &&
3894 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3895 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3896 * Changes in other states are important on disabled stages too
3898 return WINED3D_OK;
3901 if(Type == WINED3DTSS_COLOROP) {
3902 unsigned int i;
3904 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3905 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3906 * they have to be disabled
3908 * The current stage is dirtified below.
3910 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3911 TRACE("Additionally dirtifying stage %u\n", i);
3912 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3914 This->stateBlock->lowest_disabled_stage = Stage;
3915 TRACE("New lowest disabled: %u\n", Stage);
3916 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3917 /* Previously disabled stage enabled. Stages above it may need enabling
3918 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3919 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3921 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3924 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
3926 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3927 break;
3929 TRACE("Additionally dirtifying stage %u due to enable\n", i);
3930 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3932 This->stateBlock->lowest_disabled_stage = i;
3933 TRACE("New lowest disabled: %u\n", i);
3937 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3939 return WINED3D_OK;
3942 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3944 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3945 *pValue = This->updateStateBlock->textureState[Stage][Type];
3946 return WINED3D_OK;
3949 /*****
3950 * Get / Set Texture
3951 *****/
3952 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
3953 DWORD stage, IWineD3DBaseTexture *texture)
3955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3956 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3957 IWineD3DBaseTexture *prev;
3959 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
3961 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
3962 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3964 /* Windows accepts overflowing this array... we do not. */
3965 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
3967 WARN("Ignoring invalid stage %u.\n", stage);
3968 return WINED3D_OK;
3971 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
3972 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
3974 WARN("Rejecting attempt to set scratch texture.\n");
3975 return WINED3DERR_INVALIDCALL;
3978 This->updateStateBlock->changed.textures |= 1 << stage;
3980 prev = This->updateStateBlock->textures[stage];
3981 TRACE("Previous texture %p.\n", prev);
3983 if (texture == prev)
3985 TRACE("App is setting the same texture again, nothing to do.\n");
3986 return WINED3D_OK;
3989 TRACE("Setting new texture to %p.\n", texture);
3990 This->updateStateBlock->textures[stage] = texture;
3992 if (This->isRecordingState)
3994 TRACE("Recording... not performing anything\n");
3996 if (texture) IWineD3DBaseTexture_AddRef(texture);
3997 if (prev) IWineD3DBaseTexture_Release(prev);
3999 return WINED3D_OK;
4002 if (texture)
4004 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4005 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4006 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4008 IWineD3DBaseTexture_AddRef(texture);
4010 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4012 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4015 if (!prev && stage < gl_info->limits.texture_stages)
4017 /* The source arguments for color and alpha ops have different
4018 * meanings when a NULL texture is bound, so the COLOROP and
4019 * ALPHAOP have to be dirtified. */
4020 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4021 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4024 if (bind_count == 1) t->baseTexture.sampler = stage;
4027 if (prev)
4029 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4030 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4032 IWineD3DBaseTexture_Release(prev);
4034 if (!texture && stage < gl_info->limits.texture_stages)
4036 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4037 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4040 if (bind_count && t->baseTexture.sampler == stage)
4042 unsigned int i;
4044 /* Search for other stages the texture is bound to. Shouldn't
4045 * happen if applications bind textures to a single stage only. */
4046 TRACE("Searching for other stages the texture is bound to.\n");
4047 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4049 if (This->updateStateBlock->textures[i] == prev)
4051 TRACE("Texture is also bound to stage %u.\n", i);
4052 t->baseTexture.sampler = i;
4053 break;
4059 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4061 return WINED3D_OK;
4064 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4067 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4069 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4070 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4073 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4074 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4075 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4078 *ppTexture=This->stateBlock->textures[Stage];
4079 if (*ppTexture)
4080 IWineD3DBaseTexture_AddRef(*ppTexture);
4082 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4084 return WINED3D_OK;
4087 /*****
4088 * Get Back Buffer
4089 *****/
4090 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4091 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4093 IWineD3DSwapChain *swapchain;
4094 HRESULT hr;
4096 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4097 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4099 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4100 if (FAILED(hr))
4102 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4103 return hr;
4106 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4107 IWineD3DSwapChain_Release(swapchain);
4108 if (FAILED(hr))
4110 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4111 return hr;
4114 return WINED3D_OK;
4117 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4119 WARN("(%p) : stub, calling idirect3d for now\n", This);
4120 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4123 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4125 IWineD3DSwapChain *swapChain;
4126 HRESULT hr;
4128 if(iSwapChain > 0) {
4129 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4130 if (hr == WINED3D_OK) {
4131 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4132 IWineD3DSwapChain_Release(swapChain);
4133 } else {
4134 FIXME("(%p) Error getting display mode\n", This);
4136 } else {
4137 /* Don't read the real display mode,
4138 but return the stored mode instead. X11 can't change the color
4139 depth, and some apps are pretty angry if they SetDisplayMode from
4140 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4142 Also don't relay to the swapchain because with ddraw it's possible
4143 that there isn't a swapchain at all */
4144 pMode->Width = This->ddraw_width;
4145 pMode->Height = This->ddraw_height;
4146 pMode->Format = This->ddraw_format;
4147 pMode->RefreshRate = 0;
4148 hr = WINED3D_OK;
4151 return hr;
4154 /*****
4155 * Stateblock related functions
4156 *****/
4158 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4160 IWineD3DStateBlock *stateblock;
4161 HRESULT hr;
4163 TRACE("(%p)\n", This);
4165 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4167 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4168 if (FAILED(hr)) return hr;
4170 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4171 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4172 This->isRecordingState = TRUE;
4174 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4176 return WINED3D_OK;
4179 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4181 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4183 if (!This->isRecordingState) {
4184 WARN("(%p) not recording! returning error\n", This);
4185 *ppStateBlock = NULL;
4186 return WINED3DERR_INVALIDCALL;
4189 stateblock_init_contained_states(object);
4191 *ppStateBlock = (IWineD3DStateBlock*) object;
4192 This->isRecordingState = FALSE;
4193 This->updateStateBlock = This->stateBlock;
4194 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4195 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4196 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4197 return WINED3D_OK;
4200 /*****
4201 * Scene related functions
4202 *****/
4203 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4204 /* At the moment we have no need for any functionality at the beginning
4205 of a scene */
4206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4207 TRACE("(%p)\n", This);
4209 if(This->inScene) {
4210 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4211 return WINED3DERR_INVALIDCALL;
4213 This->inScene = TRUE;
4214 return WINED3D_OK;
4217 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4219 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4220 struct wined3d_context *context;
4222 TRACE("(%p)\n", This);
4224 if(!This->inScene) {
4225 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4226 return WINED3DERR_INVALIDCALL;
4229 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4230 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4231 wglFlush();
4232 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4233 * fails. */
4234 context_release(context);
4236 This->inScene = FALSE;
4237 return WINED3D_OK;
4240 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4241 const RECT *pSourceRect, const RECT *pDestRect,
4242 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4244 IWineD3DSwapChain *swapChain = NULL;
4245 int i;
4246 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4248 TRACE("iface %p.\n", iface);
4250 for(i = 0 ; i < swapchains ; i ++) {
4252 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4253 TRACE("presentinng chain %d, %p\n", i, swapChain);
4254 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4255 IWineD3DSwapChain_Release(swapChain);
4258 return WINED3D_OK;
4261 /* Not called from the VTable (internal subroutine) */
4262 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4263 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4264 float Z, DWORD Stencil) {
4265 GLbitfield glMask = 0;
4266 unsigned int i;
4267 WINED3DRECT curRect;
4268 RECT vp_rect;
4269 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4270 UINT drawable_width, drawable_height;
4271 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4272 struct wined3d_context *context;
4274 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4275 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4276 * for the cleared parts, and the untouched parts.
4278 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4279 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4280 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4281 * checking all this if the dest surface is in the drawable anyway.
4283 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4284 while(1) {
4285 if(vp->X != 0 || vp->Y != 0 ||
4286 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4287 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4288 break;
4290 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4291 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4292 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4293 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4294 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4295 break;
4297 if(Count > 0 && pRects && (
4298 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4299 pRects[0].x2 < target->currentDesc.Width ||
4300 pRects[0].y2 < target->currentDesc.Height)) {
4301 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4302 break;
4304 break;
4308 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4310 target->get_drawable_size(context, &drawable_width, &drawable_height);
4312 ENTER_GL();
4314 /* Only set the values up once, as they are not changing */
4315 if (Flags & WINED3DCLEAR_STENCIL) {
4316 glClearStencil(Stencil);
4317 checkGLcall("glClearStencil");
4318 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4319 glStencilMask(0xFFFFFFFF);
4322 if (Flags & WINED3DCLEAR_ZBUFFER) {
4323 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4324 glDepthMask(GL_TRUE);
4325 glClearDepth(Z);
4326 checkGLcall("glClearDepth");
4327 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4328 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4330 if (vp->X != 0 || vp->Y != 0 ||
4331 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4332 surface_load_ds_location(This->stencilBufferTarget, context, location);
4334 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4335 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4336 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4337 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4338 surface_load_ds_location(This->stencilBufferTarget, context, location);
4340 else if (Count > 0 && pRects && (
4341 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4342 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4343 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4344 surface_load_ds_location(This->stencilBufferTarget, context, location);
4348 if (Flags & WINED3DCLEAR_TARGET) {
4349 TRACE("Clearing screen with glClear to color %x\n", Color);
4350 glClearColor(D3DCOLOR_R(Color),
4351 D3DCOLOR_G(Color),
4352 D3DCOLOR_B(Color),
4353 D3DCOLOR_A(Color));
4354 checkGLcall("glClearColor");
4356 /* Clear ALL colors! */
4357 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4358 glMask = glMask | GL_COLOR_BUFFER_BIT;
4361 vp_rect.left = vp->X;
4362 vp_rect.top = vp->Y;
4363 vp_rect.right = vp->X + vp->Width;
4364 vp_rect.bottom = vp->Y + vp->Height;
4365 if (!(Count > 0 && pRects)) {
4366 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4367 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4369 if (context->render_offscreen)
4371 glScissor(vp_rect.left, vp_rect.top,
4372 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4373 } else {
4374 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4375 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4377 checkGLcall("glScissor");
4378 glClear(glMask);
4379 checkGLcall("glClear");
4380 } else {
4381 /* Now process each rect in turn */
4382 for (i = 0; i < Count; i++) {
4383 /* Note gl uses lower left, width/height */
4384 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4385 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4386 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4388 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4389 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4390 curRect.x1, (target->currentDesc.Height - curRect.y2),
4391 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4393 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4394 * The rectangle is not cleared, no error is returned, but further rectanlges are
4395 * still cleared if they are valid
4397 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4398 TRACE("Rectangle with negative dimensions, ignoring\n");
4399 continue;
4402 if (context->render_offscreen)
4404 glScissor(curRect.x1, curRect.y1,
4405 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4406 } else {
4407 glScissor(curRect.x1, drawable_height - curRect.y2,
4408 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4410 checkGLcall("glScissor");
4412 glClear(glMask);
4413 checkGLcall("glClear");
4417 /* Restore the old values (why..?) */
4418 if (Flags & WINED3DCLEAR_STENCIL) {
4419 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4421 if (Flags & WINED3DCLEAR_TARGET) {
4422 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4423 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4424 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4425 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4426 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4428 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4429 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4431 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4433 if (Flags & WINED3DCLEAR_ZBUFFER) {
4434 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4435 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4436 surface_modify_ds_location(This->stencilBufferTarget, location);
4439 LEAVE_GL();
4441 wglFlush(); /* Flush to ensure ordering across contexts. */
4443 context_release(context);
4445 return WINED3D_OK;
4448 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4449 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4451 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4453 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4454 Count, pRects, Flags, Color, Z, Stencil);
4456 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4457 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4458 /* TODO: What about depth stencil buffers without stencil bits? */
4459 return WINED3DERR_INVALIDCALL;
4462 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4465 /*****
4466 * Drawing functions
4467 *****/
4469 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4470 WINED3DPRIMITIVETYPE primitive_type)
4472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4474 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4476 This->updateStateBlock->changed.primitive_type = TRUE;
4477 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4480 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4481 WINED3DPRIMITIVETYPE *primitive_type)
4483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4485 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4487 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4489 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4492 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4494 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4496 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4498 if(!This->stateBlock->vertexDecl) {
4499 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4500 return WINED3DERR_INVALIDCALL;
4503 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4504 if(This->stateBlock->streamIsUP) {
4505 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4506 This->stateBlock->streamIsUP = FALSE;
4509 if(This->stateBlock->loadBaseVertexIndex != 0) {
4510 This->stateBlock->loadBaseVertexIndex = 0;
4511 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4513 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4514 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4515 return WINED3D_OK;
4518 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4521 UINT idxStride = 2;
4522 IWineD3DBuffer *pIB;
4523 GLuint vbo;
4525 pIB = This->stateBlock->pIndexData;
4526 if (!pIB) {
4527 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4528 * without an index buffer set. (The first time at least...)
4529 * D3D8 simply dies, but I doubt it can do much harm to return
4530 * D3DERR_INVALIDCALL there as well. */
4531 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4532 return WINED3DERR_INVALIDCALL;
4535 if(!This->stateBlock->vertexDecl) {
4536 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4537 return WINED3DERR_INVALIDCALL;
4540 if(This->stateBlock->streamIsUP) {
4541 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4542 This->stateBlock->streamIsUP = FALSE;
4544 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4546 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4548 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4549 idxStride = 2;
4550 } else {
4551 idxStride = 4;
4554 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4555 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4556 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4559 drawPrimitive(iface, index_count, startIndex, idxStride,
4560 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4562 return WINED3D_OK;
4565 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4566 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4569 IWineD3DBuffer *vb;
4571 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4572 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4574 if(!This->stateBlock->vertexDecl) {
4575 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4576 return WINED3DERR_INVALIDCALL;
4579 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4580 vb = This->stateBlock->streamSource[0];
4581 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4582 if (vb) IWineD3DBuffer_Release(vb);
4583 This->stateBlock->streamOffset[0] = 0;
4584 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4585 This->stateBlock->streamIsUP = TRUE;
4586 This->stateBlock->loadBaseVertexIndex = 0;
4588 /* TODO: Only mark dirty if drawing from a different UP address */
4589 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4591 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4593 /* MSDN specifies stream zero settings must be set to NULL */
4594 This->stateBlock->streamStride[0] = 0;
4595 This->stateBlock->streamSource[0] = NULL;
4597 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4598 * the new stream sources or use UP drawing again
4600 return WINED3D_OK;
4603 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4604 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4605 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4607 int idxStride;
4608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4609 IWineD3DBuffer *vb;
4610 IWineD3DBuffer *ib;
4612 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4613 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4615 if(!This->stateBlock->vertexDecl) {
4616 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4617 return WINED3DERR_INVALIDCALL;
4620 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4621 idxStride = 2;
4622 } else {
4623 idxStride = 4;
4626 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4627 vb = This->stateBlock->streamSource[0];
4628 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4629 if (vb) IWineD3DBuffer_Release(vb);
4630 This->stateBlock->streamIsUP = TRUE;
4631 This->stateBlock->streamOffset[0] = 0;
4632 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4634 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4635 This->stateBlock->baseVertexIndex = 0;
4636 This->stateBlock->loadBaseVertexIndex = 0;
4637 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4638 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4639 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4641 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4643 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4644 This->stateBlock->streamSource[0] = NULL;
4645 This->stateBlock->streamStride[0] = 0;
4646 ib = This->stateBlock->pIndexData;
4647 if(ib) {
4648 IWineD3DBuffer_Release(ib);
4649 This->stateBlock->pIndexData = NULL;
4651 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4652 * SetStreamSource to specify a vertex buffer
4655 return WINED3D_OK;
4658 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4659 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4663 /* Mark the state dirty until we have nicer tracking
4664 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4665 * that value.
4667 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4668 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4669 This->stateBlock->baseVertexIndex = 0;
4670 This->up_strided = DrawPrimStrideData;
4671 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4672 This->up_strided = NULL;
4673 return WINED3D_OK;
4676 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4677 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4678 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4681 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4683 /* Mark the state dirty until we have nicer tracking
4684 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4685 * that value.
4687 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4688 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4689 This->stateBlock->streamIsUP = TRUE;
4690 This->stateBlock->baseVertexIndex = 0;
4691 This->up_strided = DrawPrimStrideData;
4692 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4693 This->up_strided = NULL;
4694 return WINED3D_OK;
4697 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4698 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4699 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4701 WINED3DLOCKED_BOX src;
4702 WINED3DLOCKED_BOX dst;
4703 HRESULT hr;
4705 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4706 iface, pSourceVolume, pDestinationVolume);
4708 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4709 * dirtification to improve loading performance.
4711 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4712 if(FAILED(hr)) return hr;
4713 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4714 if(FAILED(hr)) {
4715 IWineD3DVolume_UnlockBox(pSourceVolume);
4716 return hr;
4719 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4721 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4722 if(FAILED(hr)) {
4723 IWineD3DVolume_UnlockBox(pSourceVolume);
4724 } else {
4725 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4727 return hr;
4730 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4731 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4733 unsigned int level_count, i;
4734 WINED3DRESOURCETYPE type;
4735 HRESULT hr;
4737 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4739 /* Verify that the source and destination textures are non-NULL. */
4740 if (!src_texture || !dst_texture)
4742 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4743 return WINED3DERR_INVALIDCALL;
4746 if (src_texture == dst_texture)
4748 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4749 return WINED3DERR_INVALIDCALL;
4752 /* Verify that the source and destination textures are the same type. */
4753 type = IWineD3DBaseTexture_GetType(src_texture);
4754 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4756 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4757 return WINED3DERR_INVALIDCALL;
4760 /* Check that both textures have the identical numbers of levels. */
4761 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4762 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4764 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4765 return WINED3DERR_INVALIDCALL;
4768 /* Make sure that the destination texture is loaded. */
4769 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4771 /* Update every surface level of the texture. */
4772 switch (type)
4774 case WINED3DRTYPE_TEXTURE:
4776 IWineD3DSurface *src_surface;
4777 IWineD3DSurface *dst_surface;
4779 for (i = 0; i < level_count; ++i)
4781 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4782 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4783 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4784 IWineD3DSurface_Release(dst_surface);
4785 IWineD3DSurface_Release(src_surface);
4786 if (FAILED(hr))
4788 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4789 return hr;
4792 break;
4795 case WINED3DRTYPE_CUBETEXTURE:
4797 IWineD3DSurface *src_surface;
4798 IWineD3DSurface *dst_surface;
4799 WINED3DCUBEMAP_FACES face;
4801 for (i = 0; i < level_count; ++i)
4803 /* Update each cube face. */
4804 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4806 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4807 face, i, &src_surface);
4808 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4809 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4810 face, i, &dst_surface);
4811 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4812 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4813 IWineD3DSurface_Release(dst_surface);
4814 IWineD3DSurface_Release(src_surface);
4815 if (FAILED(hr))
4817 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4818 return hr;
4822 break;
4825 case WINED3DRTYPE_VOLUMETEXTURE:
4827 IWineD3DVolume *src_volume;
4828 IWineD3DVolume *dst_volume;
4830 for (i = 0; i < level_count; ++i)
4832 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4833 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4834 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4835 IWineD3DVolume_Release(dst_volume);
4836 IWineD3DVolume_Release(src_volume);
4837 if (FAILED(hr))
4839 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4840 return hr;
4843 break;
4846 default:
4847 FIXME("Unsupported texture type %#x.\n", type);
4848 return WINED3DERR_INVALIDCALL;
4851 return WINED3D_OK;
4854 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4855 IWineD3DSwapChain *swapChain;
4856 HRESULT hr;
4857 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4858 if(hr == WINED3D_OK) {
4859 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4860 IWineD3DSwapChain_Release(swapChain);
4862 return hr;
4865 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4867 IWineD3DBaseTextureImpl *texture;
4868 DWORD i;
4870 TRACE("(%p) : %p\n", This, pNumPasses);
4872 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4873 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
4874 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4875 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4877 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
4878 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4879 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4882 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
4883 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
4885 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
4886 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4887 return E_FAIL;
4889 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
4890 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4891 return E_FAIL;
4893 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
4894 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
4895 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4896 return E_FAIL;
4900 /* return a sensible default */
4901 *pNumPasses = 1;
4903 TRACE("returning D3D_OK\n");
4904 return WINED3D_OK;
4907 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
4909 int i;
4911 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4913 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
4914 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
4915 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
4917 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
4922 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4924 int j;
4925 UINT NewSize;
4926 PALETTEENTRY **palettes;
4928 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4930 if (PaletteNumber >= MAX_PALETTES) {
4931 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4932 return WINED3DERR_INVALIDCALL;
4935 if (PaletteNumber >= This->NumberOfPalettes) {
4936 NewSize = This->NumberOfPalettes;
4937 do {
4938 NewSize *= 2;
4939 } while(PaletteNumber >= NewSize);
4940 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
4941 if (!palettes) {
4942 ERR("Out of memory!\n");
4943 return E_OUTOFMEMORY;
4945 This->palettes = palettes;
4946 This->NumberOfPalettes = NewSize;
4949 if (!This->palettes[PaletteNumber]) {
4950 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
4951 if (!This->palettes[PaletteNumber]) {
4952 ERR("Out of memory!\n");
4953 return E_OUTOFMEMORY;
4957 for (j = 0; j < 256; ++j) {
4958 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4959 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4960 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4961 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4963 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
4964 TRACE("(%p) : returning\n", This);
4965 return WINED3D_OK;
4968 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4970 int j;
4971 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4972 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
4973 /* What happens in such situation isn't documented; Native seems to silently abort
4974 on such conditions. Return Invalid Call. */
4975 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
4976 return WINED3DERR_INVALIDCALL;
4978 for (j = 0; j < 256; ++j) {
4979 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4980 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4981 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4982 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4984 TRACE("(%p) : returning\n", This);
4985 return WINED3D_OK;
4988 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4989 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4990 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4991 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
4992 (tested with reference rasterizer). Return Invalid Call. */
4993 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
4994 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
4995 return WINED3DERR_INVALIDCALL;
4997 /*TODO: stateblocks */
4998 if (This->currentPalette != PaletteNumber) {
4999 This->currentPalette = PaletteNumber;
5000 dirtify_p8_texture_samplers(This);
5002 TRACE("(%p) : returning\n", This);
5003 return WINED3D_OK;
5006 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5008 if (PaletteNumber == NULL) {
5009 WARN("(%p) : returning Invalid Call\n", This);
5010 return WINED3DERR_INVALIDCALL;
5012 /*TODO: stateblocks */
5013 *PaletteNumber = This->currentPalette;
5014 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5015 return WINED3D_OK;
5018 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5020 static BOOL warned;
5021 if (!warned)
5023 FIXME("(%p) : stub\n", This);
5024 warned = TRUE;
5027 This->softwareVertexProcessing = bSoftware;
5028 return WINED3D_OK;
5032 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5034 static BOOL warned;
5035 if (!warned)
5037 FIXME("(%p) : stub\n", This);
5038 warned = TRUE;
5040 return This->softwareVertexProcessing;
5043 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5044 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5046 IWineD3DSwapChain *swapchain;
5047 HRESULT hr;
5049 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5050 iface, swapchain_idx, raster_status);
5052 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5053 if (FAILED(hr))
5055 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5056 return hr;
5059 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5060 IWineD3DSwapChain_Release(swapchain);
5061 if (FAILED(hr))
5063 WARN("Failed to get raster status, hr %#x.\n", hr);
5064 return hr;
5067 return WINED3D_OK;
5070 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5072 static BOOL warned;
5073 if(nSegments != 0.0f) {
5074 if (!warned)
5076 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5077 warned = TRUE;
5080 return WINED3D_OK;
5083 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5085 static BOOL warned;
5086 if (!warned)
5088 FIXME("iface %p stub!\n", iface);
5089 warned = TRUE;
5091 return 0.0f;
5094 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5096 /** TODO: remove casts to IWineD3DSurfaceImpl
5097 * NOTE: move code to surface to accomplish this
5098 ****************************************/
5099 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5100 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5101 int srcWidth, srcHeight;
5102 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5103 WINED3DFORMAT destFormat, srcFormat;
5104 UINT destSize;
5105 int srcLeft, destLeft, destTop;
5106 WINED3DPOOL srcPool, destPool;
5107 int offset = 0;
5108 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5109 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5110 GLenum dummy;
5111 DWORD sampler;
5112 int bpp;
5113 CONVERT_TYPES convert = NO_CONVERSION;
5114 struct wined3d_context *context;
5116 WINED3DSURFACE_DESC winedesc;
5118 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5120 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5121 srcSurfaceWidth = winedesc.width;
5122 srcSurfaceHeight = winedesc.height;
5123 srcPool = winedesc.pool;
5124 srcFormat = winedesc.format;
5126 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5127 destSurfaceWidth = winedesc.width;
5128 destSurfaceHeight = winedesc.height;
5129 destPool = winedesc.pool;
5130 destFormat = winedesc.format;
5131 destSize = winedesc.size;
5133 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5134 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5135 return WINED3DERR_INVALIDCALL;
5138 /* This call loads the opengl surface directly, instead of copying the surface to the
5139 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5140 * copy in sysmem and use regular surface loading.
5142 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5143 if(convert != NO_CONVERSION) {
5144 return IWineD3DSurface_BltFast(pDestinationSurface,
5145 pDestPoint ? pDestPoint->x : 0,
5146 pDestPoint ? pDestPoint->y : 0,
5147 pSourceSurface, pSourceRect, 0);
5150 if (destFormat == WINED3DFMT_UNKNOWN) {
5151 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5152 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5154 /* Get the update surface description */
5155 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5158 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5160 ENTER_GL();
5161 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5162 checkGLcall("glActiveTextureARB");
5163 LEAVE_GL();
5165 /* Make sure the surface is loaded and up to date */
5166 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5167 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5169 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5170 dst_format_desc = dst_impl->resource.format_desc;
5172 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5173 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5174 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5175 srcLeft = pSourceRect ? pSourceRect->left : 0;
5176 destLeft = pDestPoint ? pDestPoint->x : 0;
5177 destTop = pDestPoint ? pDestPoint->y : 0;
5180 /* This function doesn't support compressed textures
5181 the pitch is just bytesPerPixel * width */
5182 if(srcWidth != srcSurfaceWidth || srcLeft ){
5183 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5184 offset += srcLeft * src_format_desc->byte_count;
5185 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5187 /* TODO DXT formats */
5189 if(pSourceRect != NULL && pSourceRect->top != 0){
5190 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5192 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5193 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5194 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5196 /* Sanity check */
5197 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5199 /* need to lock the surface to get the data */
5200 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5203 ENTER_GL();
5205 /* TODO: Cube and volume support */
5206 if(rowoffset != 0){
5207 /* not a whole row so we have to do it a line at a time */
5208 int j;
5210 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5211 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5213 for (j = destTop; j < (srcHeight + destTop); ++j)
5215 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5216 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5217 data += rowoffset;
5220 } else { /* Full width, so just write out the whole texture */
5221 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5223 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5225 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5227 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5228 FIXME("Updating part of a compressed texture is not supported.\n");
5230 if (destFormat != srcFormat)
5232 FIXME("Updating mixed format compressed textures is not supported.\n");
5234 else
5236 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5237 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5240 else
5242 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5243 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5246 checkGLcall("glTexSubImage2D");
5248 LEAVE_GL();
5249 context_release(context);
5251 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5252 sampler = This->rev_tex_unit_map[0];
5253 if (sampler != WINED3D_UNMAPPED_STAGE)
5255 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5258 return WINED3D_OK;
5261 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5263 struct WineD3DRectPatch *patch;
5264 GLenum old_primitive_type;
5265 unsigned int i;
5266 struct list *e;
5267 BOOL found;
5268 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5270 if(!(Handle || pRectPatchInfo)) {
5271 /* TODO: Write a test for the return value, thus the FIXME */
5272 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5273 return WINED3DERR_INVALIDCALL;
5276 if(Handle) {
5277 i = PATCHMAP_HASHFUNC(Handle);
5278 found = FALSE;
5279 LIST_FOR_EACH(e, &This->patches[i]) {
5280 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5281 if(patch->Handle == Handle) {
5282 found = TRUE;
5283 break;
5287 if(!found) {
5288 TRACE("Patch does not exist. Creating a new one\n");
5289 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5290 patch->Handle = Handle;
5291 list_add_head(&This->patches[i], &patch->entry);
5292 } else {
5293 TRACE("Found existing patch %p\n", patch);
5295 } else {
5296 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5297 * attributes we have to tesselate, read back, and draw. This needs a patch
5298 * management structure instance. Create one.
5300 * A possible improvement is to check if a vertex shader is used, and if not directly
5301 * draw the patch.
5303 FIXME("Drawing an uncached patch. This is slow\n");
5304 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5307 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5308 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5309 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5310 HRESULT hr;
5311 TRACE("Tesselation density or patch info changed, retesselating\n");
5313 if(pRectPatchInfo) {
5314 patch->RectPatchInfo = *pRectPatchInfo;
5316 patch->numSegs[0] = pNumSegs[0];
5317 patch->numSegs[1] = pNumSegs[1];
5318 patch->numSegs[2] = pNumSegs[2];
5319 patch->numSegs[3] = pNumSegs[3];
5321 hr = tesselate_rectpatch(This, patch);
5322 if(FAILED(hr)) {
5323 WARN("Patch tesselation failed\n");
5325 /* Do not release the handle to store the params of the patch */
5326 if(!Handle) {
5327 HeapFree(GetProcessHeap(), 0, patch);
5329 return hr;
5333 This->currentPatch = patch;
5334 old_primitive_type = This->stateBlock->gl_primitive_type;
5335 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5336 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5337 This->stateBlock->gl_primitive_type = old_primitive_type;
5338 This->currentPatch = NULL;
5340 /* Destroy uncached patches */
5341 if(!Handle) {
5342 HeapFree(GetProcessHeap(), 0, patch->mem);
5343 HeapFree(GetProcessHeap(), 0, patch);
5345 return WINED3D_OK;
5348 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5349 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5351 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5352 iface, handle, segment_count, patch_info);
5354 return WINED3D_OK;
5357 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5359 int i;
5360 struct WineD3DRectPatch *patch;
5361 struct list *e;
5362 TRACE("(%p) Handle(%d)\n", This, Handle);
5364 i = PATCHMAP_HASHFUNC(Handle);
5365 LIST_FOR_EACH(e, &This->patches[i]) {
5366 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5367 if(patch->Handle == Handle) {
5368 TRACE("Deleting patch %p\n", patch);
5369 list_remove(&patch->entry);
5370 HeapFree(GetProcessHeap(), 0, patch->mem);
5371 HeapFree(GetProcessHeap(), 0, patch);
5372 return WINED3D_OK;
5376 /* TODO: Write a test for the return value */
5377 FIXME("Attempt to destroy nonexistent patch\n");
5378 return WINED3DERR_INVALIDCALL;
5381 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5382 HRESULT hr;
5383 IWineD3DSwapChain *swapchain;
5385 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5386 if (SUCCEEDED(hr)) {
5387 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5388 return swapchain;
5391 return NULL;
5394 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5395 const WINED3DRECT *rect, const float color[4])
5397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5398 struct wined3d_context *context;
5400 if (rect) IWineD3DSurface_LoadLocation(surface, SFLAG_INDRAWABLE, NULL);
5401 IWineD3DSurface_ModifyLocation(surface, SFLAG_INDRAWABLE, TRUE);
5403 if (!surface_is_offscreen(surface))
5405 TRACE("Surface %p is onscreen\n", surface);
5407 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5408 ENTER_GL();
5409 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5410 context_set_draw_buffer(context, surface_get_gl_buffer(surface));
5412 else
5414 TRACE("Surface %p is offscreen\n", surface);
5416 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5417 ENTER_GL();
5418 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5419 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5420 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5423 if (rect) {
5424 glEnable(GL_SCISSOR_TEST);
5425 if(surface_is_offscreen(surface)) {
5426 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5427 } else {
5428 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5429 rect->x2 - rect->x1, rect->y2 - rect->y1);
5431 checkGLcall("glScissor");
5432 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5433 } else {
5434 glDisable(GL_SCISSOR_TEST);
5436 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5438 glDisable(GL_BLEND);
5439 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5441 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5442 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5444 glClearColor(color[0], color[1], color[2], color[3]);
5445 glClear(GL_COLOR_BUFFER_BIT);
5446 checkGLcall("glClear");
5448 LEAVE_GL();
5450 wglFlush(); /* Flush to ensure ordering across contexts. */
5452 context_release(context);
5455 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5456 unsigned int r, g, b, a;
5457 DWORD ret;
5459 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5460 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5461 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5462 return color;
5464 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5466 a = (color & 0xff000000) >> 24;
5467 r = (color & 0x00ff0000) >> 16;
5468 g = (color & 0x0000ff00) >> 8;
5469 b = (color & 0x000000ff) >> 0;
5471 switch(destfmt)
5473 case WINED3DFMT_B5G6R5_UNORM:
5474 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5475 r = (r * 32) / 256;
5476 g = (g * 64) / 256;
5477 b = (b * 32) / 256;
5478 ret = r << 11;
5479 ret |= g << 5;
5480 ret |= b;
5481 TRACE("Returning %08x\n", ret);
5482 return ret;
5484 case WINED3DFMT_B5G5R5X1_UNORM:
5485 case WINED3DFMT_B5G5R5A1_UNORM:
5486 a = (a * 2) / 256;
5487 r = (r * 32) / 256;
5488 g = (g * 32) / 256;
5489 b = (b * 32) / 256;
5490 ret = a << 15;
5491 ret |= r << 10;
5492 ret |= g << 5;
5493 ret |= b << 0;
5494 TRACE("Returning %08x\n", ret);
5495 return ret;
5497 case WINED3DFMT_A8_UNORM:
5498 TRACE("Returning %08x\n", a);
5499 return a;
5501 case WINED3DFMT_B4G4R4X4_UNORM:
5502 case WINED3DFMT_B4G4R4A4_UNORM:
5503 a = (a * 16) / 256;
5504 r = (r * 16) / 256;
5505 g = (g * 16) / 256;
5506 b = (b * 16) / 256;
5507 ret = a << 12;
5508 ret |= r << 8;
5509 ret |= g << 4;
5510 ret |= b << 0;
5511 TRACE("Returning %08x\n", ret);
5512 return ret;
5514 case WINED3DFMT_B2G3R3_UNORM:
5515 r = (r * 8) / 256;
5516 g = (g * 8) / 256;
5517 b = (b * 4) / 256;
5518 ret = r << 5;
5519 ret |= g << 2;
5520 ret |= b << 0;
5521 TRACE("Returning %08x\n", ret);
5522 return ret;
5524 case WINED3DFMT_R8G8B8X8_UNORM:
5525 case WINED3DFMT_R8G8B8A8_UNORM:
5526 ret = a << 24;
5527 ret |= b << 16;
5528 ret |= g << 8;
5529 ret |= r << 0;
5530 TRACE("Returning %08x\n", ret);
5531 return ret;
5533 case WINED3DFMT_B10G10R10A2_UNORM:
5534 a = (a * 4) / 256;
5535 r = (r * 1024) / 256;
5536 g = (g * 1024) / 256;
5537 b = (b * 1024) / 256;
5538 ret = a << 30;
5539 ret |= r << 20;
5540 ret |= g << 10;
5541 ret |= b << 0;
5542 TRACE("Returning %08x\n", ret);
5543 return ret;
5545 case WINED3DFMT_R10G10B10A2_UNORM:
5546 a = (a * 4) / 256;
5547 r = (r * 1024) / 256;
5548 g = (g * 1024) / 256;
5549 b = (b * 1024) / 256;
5550 ret = a << 30;
5551 ret |= b << 20;
5552 ret |= g << 10;
5553 ret |= r << 0;
5554 TRACE("Returning %08x\n", ret);
5555 return ret;
5557 default:
5558 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5559 return 0;
5563 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5564 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5566 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5567 WINEDDBLTFX BltFx;
5569 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5571 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5572 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5573 return WINED3DERR_INVALIDCALL;
5576 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5577 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5578 color_fill_fbo(iface, pSurface, pRect, c);
5579 return WINED3D_OK;
5580 } else {
5581 /* Just forward this to the DirectDraw blitting engine */
5582 memset(&BltFx, 0, sizeof(BltFx));
5583 BltFx.dwSize = sizeof(BltFx);
5584 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5585 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5586 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5590 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5591 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5593 IWineD3DResource *resource;
5594 IWineD3DSurface *surface;
5595 HRESULT hr;
5597 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5598 if (FAILED(hr))
5600 ERR("Failed to get resource, hr %#x\n", hr);
5601 return;
5604 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5606 FIXME("Only supported on surface resources\n");
5607 IWineD3DResource_Release(resource);
5608 return;
5611 surface = (IWineD3DSurface *)resource;
5613 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5615 color_fill_fbo(iface, surface, NULL, color);
5617 else
5619 WINEDDBLTFX BltFx;
5620 WINED3DCOLOR c;
5622 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5624 c = ((DWORD)(color[2] * 255.0f));
5625 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5626 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5627 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5629 /* Just forward this to the DirectDraw blitting engine */
5630 memset(&BltFx, 0, sizeof(BltFx));
5631 BltFx.dwSize = sizeof(BltFx);
5632 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5633 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5634 if (FAILED(hr))
5636 ERR("Blt failed, hr %#x\n", hr);
5640 IWineD3DResource_Release(resource);
5643 /* rendertarget and depth stencil functions */
5644 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5647 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5649 ERR("(%p) : Only %d render targets are supported.\n",
5650 This, This->adapter->gl_info.limits.buffers);
5651 return WINED3DERR_INVALIDCALL;
5654 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5655 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5656 /* Note inc ref on returned surface */
5657 if(*ppRenderTarget != NULL)
5658 IWineD3DSurface_AddRef(*ppRenderTarget);
5659 return WINED3D_OK;
5662 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5663 IWineD3DSurface *Front, IWineD3DSurface *Back)
5665 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5666 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5667 IWineD3DSwapChainImpl *Swapchain;
5668 HRESULT hr;
5670 TRACE("iface %p, front %p, back %p.\n", iface, Front, Back);
5672 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5673 if(hr != WINED3D_OK) {
5674 ERR("Can't get the swapchain\n");
5675 return hr;
5678 /* Make sure to release the swapchain */
5679 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5681 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5682 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5683 return WINED3DERR_INVALIDCALL;
5685 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5686 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5687 return WINED3DERR_INVALIDCALL;
5690 if(Swapchain->frontBuffer != Front) {
5691 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5693 if(Swapchain->frontBuffer)
5695 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5696 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5698 Swapchain->frontBuffer = Front;
5700 if(Swapchain->frontBuffer) {
5701 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5702 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5706 if(Back && !Swapchain->backBuffer) {
5707 /* We need memory for the back buffer array - only one back buffer this way */
5708 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5709 if(!Swapchain->backBuffer) {
5710 ERR("Out of memory\n");
5711 return E_OUTOFMEMORY;
5715 if(Swapchain->backBuffer[0] != Back) {
5716 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5718 /* What to do about the context here in the case of multithreading? Not sure.
5719 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5721 WARN("No active context?\n");
5723 ENTER_GL();
5724 if(!Swapchain->backBuffer[0]) {
5725 /* GL was told to draw to the front buffer at creation,
5726 * undo that
5728 glDrawBuffer(GL_BACK);
5729 checkGLcall("glDrawBuffer(GL_BACK)");
5730 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5731 Swapchain->presentParms.BackBufferCount = 1;
5732 } else if (!Back) {
5733 /* That makes problems - disable for now */
5734 /* glDrawBuffer(GL_FRONT); */
5735 checkGLcall("glDrawBuffer(GL_FRONT)");
5736 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5737 Swapchain->presentParms.BackBufferCount = 0;
5739 LEAVE_GL();
5741 if(Swapchain->backBuffer[0])
5743 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5744 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5746 Swapchain->backBuffer[0] = Back;
5748 if(Swapchain->backBuffer[0]) {
5749 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5750 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
5751 Swapchain->presentParms.BackBufferWidth = BackImpl->currentDesc.Width;
5752 Swapchain->presentParms.BackBufferHeight = BackImpl->currentDesc.Height;
5753 Swapchain->presentParms.BackBufferFormat = BackImpl->resource.format_desc->format;
5754 } else {
5755 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5756 Swapchain->backBuffer = NULL;
5761 return WINED3D_OK;
5764 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5765 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5766 *ppZStencilSurface = This->stencilBufferTarget;
5767 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5769 if(*ppZStencilSurface != NULL) {
5770 /* Note inc ref on returned surface */
5771 IWineD3DSurface_AddRef(*ppZStencilSurface);
5772 return WINED3D_OK;
5773 } else {
5774 return WINED3DERR_NOTFOUND;
5778 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5779 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
5781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5782 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5783 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5784 const struct wined3d_gl_info *gl_info;
5785 struct wined3d_context *context;
5786 GLenum gl_filter;
5787 POINT offset = {0, 0};
5789 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5790 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5791 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5792 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5794 switch (filter) {
5795 case WINED3DTEXF_LINEAR:
5796 gl_filter = GL_LINEAR;
5797 break;
5799 default:
5800 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5801 case WINED3DTEXF_NONE:
5802 case WINED3DTEXF_POINT:
5803 gl_filter = GL_NEAREST;
5804 break;
5807 /* Make sure the drawables are up-to-date. Note that loading the
5808 * destination surface isn't strictly required if we overwrite the
5809 * entire surface. */
5810 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
5811 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
5813 /* Attach src surface to src fbo */
5814 src_swapchain = get_swapchain(src_surface);
5815 dst_swapchain = get_swapchain(dst_surface);
5817 if (src_swapchain) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
5818 else if (dst_swapchain) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5819 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5821 gl_info = context->gl_info;
5823 if (!surface_is_offscreen(src_surface))
5825 GLenum buffer = surface_get_gl_buffer(src_surface);
5827 TRACE("Source surface %p is onscreen\n", src_surface);
5829 if(buffer == GL_FRONT) {
5830 RECT windowsize;
5831 UINT h;
5832 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
5833 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
5834 h = windowsize.bottom - windowsize.top;
5835 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
5836 src_rect->y1 = offset.y + h - src_rect->y1;
5837 src_rect->y2 = offset.y + h - src_rect->y2;
5838 } else {
5839 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5840 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5843 ENTER_GL();
5844 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5845 glReadBuffer(buffer);
5846 checkGLcall("glReadBuffer()");
5847 } else {
5848 TRACE("Source surface %p is offscreen\n", src_surface);
5849 ENTER_GL();
5850 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5851 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
5852 glReadBuffer(GL_COLOR_ATTACHMENT0);
5853 checkGLcall("glReadBuffer()");
5854 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5856 LEAVE_GL();
5858 /* Attach dst surface to dst fbo */
5859 if (!surface_is_offscreen(dst_surface))
5861 GLenum buffer = surface_get_gl_buffer(dst_surface);
5863 TRACE("Destination surface %p is onscreen\n", dst_surface);
5865 if(buffer == GL_FRONT) {
5866 RECT windowsize;
5867 UINT h;
5868 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
5869 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
5870 h = windowsize.bottom - windowsize.top;
5871 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
5872 dst_rect->y1 = offset.y + h - dst_rect->y1;
5873 dst_rect->y2 = offset.y + h - dst_rect->y2;
5874 } else {
5875 /* Screen coords = window coords, surface height = window height */
5876 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5877 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5880 ENTER_GL();
5881 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5882 context_set_draw_buffer(context, buffer);
5884 else
5886 TRACE("Destination surface %p is offscreen\n", dst_surface);
5888 ENTER_GL();
5889 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5890 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
5891 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5892 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5894 glDisable(GL_SCISSOR_TEST);
5895 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5897 if (flip) {
5898 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5899 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
5900 checkGLcall("glBlitFramebuffer()");
5901 } else {
5902 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5903 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
5904 checkGLcall("glBlitFramebuffer()");
5907 LEAVE_GL();
5909 wglFlush(); /* Flush to ensure ordering across contexts. */
5911 context_release(context);
5913 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
5916 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5917 BOOL set_viewport) {
5918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5920 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5922 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5924 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5925 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5926 return WINED3DERR_INVALIDCALL;
5929 /* MSDN says that null disables the render target
5930 but a device must always be associated with a render target
5931 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5933 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5934 FIXME("Trying to set render target 0 to NULL\n");
5935 return WINED3DERR_INVALIDCALL;
5937 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5938 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);
5939 return WINED3DERR_INVALIDCALL;
5942 /* If we are trying to set what we already have, don't bother */
5943 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5944 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5945 return WINED3D_OK;
5947 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5948 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5949 This->render_targets[RenderTargetIndex] = pRenderTarget;
5951 /* Render target 0 is special */
5952 if(RenderTargetIndex == 0 && set_viewport) {
5953 /* Finally, reset the viewport and scissor rect as the MSDN states.
5954 * Tests show that stateblock recording is ignored, the change goes
5955 * directly into the primary stateblock.
5957 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5958 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5959 This->stateBlock->viewport.X = 0;
5960 This->stateBlock->viewport.Y = 0;
5961 This->stateBlock->viewport.MaxZ = 1.0f;
5962 This->stateBlock->viewport.MinZ = 0.0f;
5963 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5965 This->stateBlock->scissorRect.top = 0;
5966 This->stateBlock->scissorRect.left = 0;
5967 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5968 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5969 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5971 return WINED3D_OK;
5974 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5976 HRESULT hr = WINED3D_OK;
5977 IWineD3DSurface *tmp;
5979 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
5981 if (pNewZStencil == This->stencilBufferTarget) {
5982 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5983 } else {
5984 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
5985 * depending on the renter target implementation being used.
5986 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5987 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5988 * stencil buffer and incur an extra memory overhead
5989 ******************************************************/
5991 if (This->stencilBufferTarget) {
5992 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5993 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
5994 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
5995 } else {
5996 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5997 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
5998 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
5999 context_release(context);
6003 tmp = This->stencilBufferTarget;
6004 This->stencilBufferTarget = pNewZStencil;
6005 /* should we be calling the parent or the wined3d surface? */
6006 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6007 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6008 hr = WINED3D_OK;
6010 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6011 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6012 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6013 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6014 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6018 return hr;
6021 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6022 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6024 /* TODO: the use of Impl is deprecated. */
6025 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6026 WINED3DLOCKED_RECT lockedRect;
6028 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6030 /* some basic validation checks */
6031 if(This->cursorTexture) {
6032 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6033 ENTER_GL();
6034 glDeleteTextures(1, &This->cursorTexture);
6035 LEAVE_GL();
6036 context_release(context);
6037 This->cursorTexture = 0;
6040 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6041 This->haveHardwareCursor = TRUE;
6042 else
6043 This->haveHardwareCursor = FALSE;
6045 if(pCursorBitmap) {
6046 WINED3DLOCKED_RECT rect;
6048 /* MSDN: Cursor must be A8R8G8B8 */
6049 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6051 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6052 return WINED3DERR_INVALIDCALL;
6055 /* MSDN: Cursor must be smaller than the display mode */
6056 if(pSur->currentDesc.Width > This->ddraw_width ||
6057 pSur->currentDesc.Height > This->ddraw_height) {
6058 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);
6059 return WINED3DERR_INVALIDCALL;
6062 if (!This->haveHardwareCursor) {
6063 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6065 /* Do not store the surface's pointer because the application may
6066 * release it after setting the cursor image. Windows doesn't
6067 * addref the set surface, so we can't do this either without
6068 * creating circular refcount dependencies. Copy out the gl texture
6069 * instead.
6071 This->cursorWidth = pSur->currentDesc.Width;
6072 This->cursorHeight = pSur->currentDesc.Height;
6073 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6075 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6076 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6077 struct wined3d_context *context;
6078 char *mem, *bits = rect.pBits;
6079 GLint intfmt = glDesc->glInternal;
6080 GLint format = glDesc->glFormat;
6081 GLint type = glDesc->glType;
6082 INT height = This->cursorHeight;
6083 INT width = This->cursorWidth;
6084 INT bpp = glDesc->byte_count;
6085 DWORD sampler;
6086 INT i;
6088 /* Reformat the texture memory (pitch and width can be
6089 * different) */
6090 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6091 for(i = 0; i < height; i++)
6092 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6093 IWineD3DSurface_UnlockRect(pCursorBitmap);
6095 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6097 ENTER_GL();
6099 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6101 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6102 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6105 /* Make sure that a proper texture unit is selected */
6106 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6107 checkGLcall("glActiveTextureARB");
6108 sampler = This->rev_tex_unit_map[0];
6109 if (sampler != WINED3D_UNMAPPED_STAGE)
6111 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6113 /* Create a new cursor texture */
6114 glGenTextures(1, &This->cursorTexture);
6115 checkGLcall("glGenTextures");
6116 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6117 checkGLcall("glBindTexture");
6118 /* Copy the bitmap memory into the cursor texture */
6119 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6120 HeapFree(GetProcessHeap(), 0, mem);
6121 checkGLcall("glTexImage2D");
6123 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6125 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6126 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6129 LEAVE_GL();
6131 context_release(context);
6133 else
6135 FIXME("A cursor texture was not returned.\n");
6136 This->cursorTexture = 0;
6139 else
6141 /* Draw a hardware cursor */
6142 ICONINFO cursorInfo;
6143 HCURSOR cursor;
6144 /* Create and clear maskBits because it is not needed for
6145 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6146 * chunks. */
6147 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6148 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6149 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6150 WINED3DLOCK_NO_DIRTY_UPDATE |
6151 WINED3DLOCK_READONLY
6153 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6154 pSur->currentDesc.Height);
6156 cursorInfo.fIcon = FALSE;
6157 cursorInfo.xHotspot = XHotSpot;
6158 cursorInfo.yHotspot = YHotSpot;
6159 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6160 1, 1, maskBits);
6161 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6162 1, 32, lockedRect.pBits);
6163 IWineD3DSurface_UnlockRect(pCursorBitmap);
6164 /* Create our cursor and clean up. */
6165 cursor = CreateIconIndirect(&cursorInfo);
6166 SetCursor(cursor);
6167 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6168 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6169 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6170 This->hardwareCursor = cursor;
6171 HeapFree(GetProcessHeap(), 0, maskBits);
6175 This->xHotSpot = XHotSpot;
6176 This->yHotSpot = YHotSpot;
6177 return WINED3D_OK;
6180 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6182 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6184 This->xScreenSpace = XScreenSpace;
6185 This->yScreenSpace = YScreenSpace;
6187 return;
6191 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6193 BOOL oldVisible = This->bCursorVisible;
6194 POINT pt;
6196 TRACE("(%p) : visible(%d)\n", This, bShow);
6199 * When ShowCursor is first called it should make the cursor appear at the OS's last
6200 * known cursor position. Because of this, some applications just repetitively call
6201 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6203 GetCursorPos(&pt);
6204 This->xScreenSpace = pt.x;
6205 This->yScreenSpace = pt.y;
6207 if (This->haveHardwareCursor) {
6208 This->bCursorVisible = bShow;
6209 if (bShow)
6210 SetCursor(This->hardwareCursor);
6211 else
6212 SetCursor(NULL);
6214 else
6216 if (This->cursorTexture)
6217 This->bCursorVisible = bShow;
6220 return oldVisible;
6223 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6224 TRACE("checking resource %p for eviction\n", resource);
6225 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6226 TRACE("Evicting %p\n", resource);
6227 IWineD3DResource_UnLoad(resource);
6229 IWineD3DResource_Release(resource);
6230 return S_OK;
6233 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6235 TRACE("iface %p.\n", iface);
6237 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6238 return WINED3D_OK;
6241 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6243 IWineD3DDeviceImpl *device = surface->resource.device;
6244 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6246 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6247 if(surface->Flags & SFLAG_DIBSECTION) {
6248 /* Release the DC */
6249 SelectObject(surface->hDC, surface->dib.holdbitmap);
6250 DeleteDC(surface->hDC);
6251 /* Release the DIB section */
6252 DeleteObject(surface->dib.DIBsection);
6253 surface->dib.bitmap_data = NULL;
6254 surface->resource.allocatedMemory = NULL;
6255 surface->Flags &= ~SFLAG_DIBSECTION;
6257 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6258 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6259 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6260 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6262 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6263 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6264 } else {
6265 surface->pow2Width = surface->pow2Height = 1;
6266 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6267 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6269 surface->glRect.left = 0;
6270 surface->glRect.top = 0;
6271 surface->glRect.right = surface->pow2Width;
6272 surface->glRect.bottom = surface->pow2Height;
6274 if (surface->texture_name)
6276 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6277 ENTER_GL();
6278 glDeleteTextures(1, &surface->texture_name);
6279 LEAVE_GL();
6280 context_release(context);
6281 surface->texture_name = 0;
6282 surface->Flags &= ~SFLAG_CLIENT;
6284 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6285 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6286 surface->Flags |= SFLAG_NONPOW2;
6287 } else {
6288 surface->Flags &= ~SFLAG_NONPOW2;
6290 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6291 surface->resource.allocatedMemory = NULL;
6292 surface->resource.heapMemory = NULL;
6293 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6295 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6296 * to a FBO */
6297 if(!surface_init_sysmem((IWineD3DSurface *) surface))
6299 return E_OUTOFMEMORY;
6301 return WINED3D_OK;
6304 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6305 TRACE("Unloading resource %p\n", resource);
6306 IWineD3DResource_UnLoad(resource);
6307 IWineD3DResource_Release(resource);
6308 return S_OK;
6311 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6313 UINT i, count;
6314 WINED3DDISPLAYMODE m;
6315 HRESULT hr;
6317 /* All Windowed modes are supported, as is leaving the current mode */
6318 if(pp->Windowed) return TRUE;
6319 if(!pp->BackBufferWidth) return TRUE;
6320 if(!pp->BackBufferHeight) return TRUE;
6322 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6323 for(i = 0; i < count; i++) {
6324 memset(&m, 0, sizeof(m));
6325 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6326 if(FAILED(hr)) {
6327 ERR("EnumAdapterModes failed\n");
6329 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6330 /* Mode found, it is supported */
6331 return TRUE;
6334 /* Mode not found -> not supported */
6335 return FALSE;
6338 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6340 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6341 const struct wined3d_gl_info *gl_info;
6342 struct wined3d_context *context;
6343 IWineD3DBaseShaderImpl *shader;
6345 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6346 gl_info = context->gl_info;
6348 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6349 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6350 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6353 ENTER_GL();
6354 if(This->depth_blt_texture) {
6355 glDeleteTextures(1, &This->depth_blt_texture);
6356 This->depth_blt_texture = 0;
6358 if (This->depth_blt_rb) {
6359 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6360 This->depth_blt_rb = 0;
6361 This->depth_blt_rb_w = 0;
6362 This->depth_blt_rb_h = 0;
6364 LEAVE_GL();
6366 This->blitter->free_private(iface);
6367 This->frag_pipe->free_private(iface);
6368 This->shader_backend->shader_free_private(iface);
6369 destroy_dummy_textures(This, gl_info);
6371 context_release(context);
6373 while (This->numContexts)
6375 context_destroy(This, This->contexts[0]);
6377 HeapFree(GetProcessHeap(), 0, swapchain->context);
6378 swapchain->context = NULL;
6379 swapchain->num_contexts = 0;
6382 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6384 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6385 struct wined3d_context *context;
6386 HRESULT hr;
6387 IWineD3DSurfaceImpl *target;
6389 /* Recreate the primary swapchain's context */
6390 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6391 if (!swapchain->context)
6393 ERR("Failed to allocate memory for swapchain context array.\n");
6394 return E_OUTOFMEMORY;
6397 target = (IWineD3DSurfaceImpl *)(swapchain->backBuffer ? swapchain->backBuffer[0] : swapchain->frontBuffer);
6398 context = context_create(This, target, swapchain->win_handle, FALSE, &swapchain->presentParms);
6399 if (!context)
6401 WARN("Failed to create context.\n");
6402 HeapFree(GetProcessHeap(), 0, swapchain->context);
6403 return E_FAIL;
6406 swapchain->context[0] = context;
6407 swapchain->num_contexts = 1;
6408 create_dummy_textures(This);
6409 context_release(context);
6411 hr = This->shader_backend->shader_alloc_private(iface);
6412 if (FAILED(hr))
6414 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6415 goto err;
6418 hr = This->frag_pipe->alloc_private(iface);
6419 if (FAILED(hr))
6421 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6422 This->shader_backend->shader_free_private(iface);
6423 goto err;
6426 hr = This->blitter->alloc_private(iface);
6427 if (FAILED(hr))
6429 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6430 This->frag_pipe->free_private(iface);
6431 This->shader_backend->shader_free_private(iface);
6432 goto err;
6435 return WINED3D_OK;
6437 err:
6438 context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6439 destroy_dummy_textures(This, context->gl_info);
6440 context_release(context);
6441 context_destroy(This, context);
6442 HeapFree(GetProcessHeap(), 0, swapchain->context);
6443 swapchain->num_contexts = 0;
6444 return hr;
6447 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6449 IWineD3DSwapChainImpl *swapchain;
6450 HRESULT hr;
6451 BOOL DisplayModeChanged = FALSE;
6452 WINED3DDISPLAYMODE mode;
6453 TRACE("(%p)\n", This);
6455 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6456 if(FAILED(hr)) {
6457 ERR("Failed to get the first implicit swapchain\n");
6458 return hr;
6461 if(!is_display_mode_supported(This, pPresentationParameters)) {
6462 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6463 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6464 pPresentationParameters->BackBufferHeight);
6465 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6466 return WINED3DERR_INVALIDCALL;
6469 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6470 * on an existing gl context, so there's no real need for recreation.
6472 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6474 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6476 TRACE("New params:\n");
6477 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6478 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6479 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6480 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6481 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6482 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6483 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6484 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6485 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6486 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6487 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6488 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6489 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6491 /* No special treatment of these parameters. Just store them */
6492 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6493 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6494 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6495 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6497 /* What to do about these? */
6498 if(pPresentationParameters->BackBufferCount != 0 &&
6499 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6500 ERR("Cannot change the back buffer count yet\n");
6502 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6503 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6504 ERR("Cannot change the back buffer format yet\n");
6506 if(pPresentationParameters->hDeviceWindow != NULL &&
6507 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6508 ERR("Cannot change the device window yet\n");
6510 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6511 HRESULT hrc;
6513 TRACE("Creating the depth stencil buffer\n");
6515 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6516 This->parent,
6517 pPresentationParameters->BackBufferWidth,
6518 pPresentationParameters->BackBufferHeight,
6519 pPresentationParameters->AutoDepthStencilFormat,
6520 pPresentationParameters->MultiSampleType,
6521 pPresentationParameters->MultiSampleQuality,
6522 FALSE,
6523 &This->auto_depth_stencil_buffer);
6525 if (FAILED(hrc)) {
6526 ERR("Failed to create the depth stencil buffer\n");
6527 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6528 return WINED3DERR_INVALIDCALL;
6532 /* Reset the depth stencil */
6533 if (pPresentationParameters->EnableAutoDepthStencil)
6534 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6535 else
6536 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6538 TRACE("Resetting stateblock\n");
6539 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6540 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6542 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6544 if(pPresentationParameters->Windowed) {
6545 mode.Width = swapchain->orig_width;
6546 mode.Height = swapchain->orig_height;
6547 mode.RefreshRate = 0;
6548 mode.Format = swapchain->presentParms.BackBufferFormat;
6549 } else {
6550 mode.Width = pPresentationParameters->BackBufferWidth;
6551 mode.Height = pPresentationParameters->BackBufferHeight;
6552 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6553 mode.Format = swapchain->presentParms.BackBufferFormat;
6556 /* Should Width == 800 && Height == 0 set 800x600? */
6557 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6558 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6559 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6561 UINT i;
6563 if(!pPresentationParameters->Windowed) {
6564 DisplayModeChanged = TRUE;
6566 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6567 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6569 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6570 if(FAILED(hr))
6572 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6573 return hr;
6576 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6577 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6578 if(FAILED(hr))
6580 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6581 return hr;
6584 if(This->auto_depth_stencil_buffer) {
6585 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6586 if(FAILED(hr))
6588 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6589 return hr;
6594 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6595 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6596 DisplayModeChanged) {
6598 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6600 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
6601 if(swapchain->presentParms.Windowed) {
6602 /* switch from windowed to fs */
6603 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6604 pPresentationParameters->BackBufferHeight);
6605 } else {
6606 /* Fullscreen -> fullscreen mode change */
6607 MoveWindow(swapchain->win_handle, 0, 0,
6608 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6609 TRUE);
6611 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
6612 /* Fullscreen -> windowed switch */
6613 swapchain_restore_fullscreen_window(swapchain);
6615 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6616 } else if(!pPresentationParameters->Windowed) {
6617 DWORD style = This->style, exStyle = This->exStyle;
6618 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6619 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6620 * Reset to clear up their mess. Guild Wars also loses the device during that.
6622 This->style = 0;
6623 This->exStyle = 0;
6624 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6625 pPresentationParameters->BackBufferHeight);
6626 This->style = style;
6627 This->exStyle = exStyle;
6630 /* Note: No parent needed for initial internal stateblock */
6631 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6632 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6633 else TRACE("Created stateblock %p\n", This->stateBlock);
6634 This->updateStateBlock = This->stateBlock;
6635 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6637 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6638 if(FAILED(hr)) {
6639 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6642 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6644 RECT client_rect;
6645 GetClientRect(swapchain->win_handle, &client_rect);
6647 if(!swapchain->presentParms.BackBufferCount)
6649 TRACE("Single buffered rendering\n");
6650 swapchain->render_to_fbo = FALSE;
6652 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6653 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6655 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6656 swapchain->presentParms.BackBufferWidth,
6657 swapchain->presentParms.BackBufferHeight,
6658 client_rect.right, client_rect.bottom);
6659 swapchain->render_to_fbo = TRUE;
6661 else
6663 TRACE("Rendering directly to GL_BACK\n");
6664 swapchain->render_to_fbo = FALSE;
6668 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6669 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6671 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6672 * first use
6674 return hr;
6677 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6679 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6681 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6683 return WINED3D_OK;
6687 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6689 TRACE("(%p) : pParameters %p\n", This, pParameters);
6691 *pParameters = This->createParms;
6692 return WINED3D_OK;
6695 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6696 IWineD3DSwapChain *swapchain;
6698 TRACE("Relaying to swapchain\n");
6700 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6701 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6702 IWineD3DSwapChain_Release(swapchain);
6706 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6707 IWineD3DSwapChain *swapchain;
6709 TRACE("Relaying to swapchain\n");
6711 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6712 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6713 IWineD3DSwapChain_Release(swapchain);
6718 /** ********************************************************
6719 * Notification functions
6720 ** ********************************************************/
6721 /** This function must be called in the release of a resource when ref == 0,
6722 * the contents of resource must still be correct,
6723 * any handles to other resource held by the caller must be closed
6724 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6725 *****************************************************/
6726 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6728 TRACE("(%p) : Adding resource %p\n", This, resource);
6730 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6733 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6735 TRACE("(%p) : Removing resource %p\n", This, resource);
6737 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6740 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6742 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6743 int counter;
6745 TRACE("(%p) : resource %p\n", This, resource);
6747 context_resource_released((IWineD3DDevice *)This, resource, type);
6749 switch (type) {
6750 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6751 case WINED3DRTYPE_SURFACE: {
6752 unsigned int i;
6754 if (This->d3d_initialized)
6756 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6758 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6759 This->render_targets[i] = NULL;
6762 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6763 This->stencilBufferTarget = NULL;
6767 break;
6769 case WINED3DRTYPE_TEXTURE:
6770 case WINED3DRTYPE_CUBETEXTURE:
6771 case WINED3DRTYPE_VOLUMETEXTURE:
6772 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6773 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6774 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6775 This->stateBlock->textures[counter] = NULL;
6777 if (This->updateStateBlock != This->stateBlock ){
6778 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6779 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6780 This->updateStateBlock->textures[counter] = NULL;
6784 break;
6785 case WINED3DRTYPE_VOLUME:
6786 /* TODO: nothing really? */
6787 break;
6788 case WINED3DRTYPE_BUFFER:
6790 int streamNumber;
6791 TRACE("Cleaning up stream pointers\n");
6793 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6794 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6795 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6797 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6798 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6799 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6800 This->updateStateBlock->streamSource[streamNumber] = 0;
6801 /* Set changed flag? */
6804 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) */
6805 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6806 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6807 This->stateBlock->streamSource[streamNumber] = 0;
6812 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6813 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6814 This->updateStateBlock->pIndexData = NULL;
6817 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6818 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6819 This->stateBlock->pIndexData = NULL;
6823 break;
6825 default:
6826 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6827 break;
6831 /* Remove the resource from the resourceStore */
6832 device_resource_remove(This, resource);
6834 TRACE("Resource released\n");
6838 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6840 IWineD3DResourceImpl *resource, *cursor;
6841 HRESULT ret;
6842 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6844 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6845 TRACE("enumerating resource %p\n", resource);
6846 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6847 ret = pCallback((IWineD3DResource *) resource, pData);
6848 if(ret == S_FALSE) {
6849 TRACE("Canceling enumeration\n");
6850 break;
6853 return WINED3D_OK;
6856 /**********************************************************
6857 * IWineD3DDevice VTbl follows
6858 **********************************************************/
6860 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6862 /*** IUnknown methods ***/
6863 IWineD3DDeviceImpl_QueryInterface,
6864 IWineD3DDeviceImpl_AddRef,
6865 IWineD3DDeviceImpl_Release,
6866 /*** IWineD3DDevice methods ***/
6867 IWineD3DDeviceImpl_GetParent,
6868 /*** Creation methods**/
6869 IWineD3DDeviceImpl_CreateBuffer,
6870 IWineD3DDeviceImpl_CreateVertexBuffer,
6871 IWineD3DDeviceImpl_CreateIndexBuffer,
6872 IWineD3DDeviceImpl_CreateStateBlock,
6873 IWineD3DDeviceImpl_CreateSurface,
6874 IWineD3DDeviceImpl_CreateRendertargetView,
6875 IWineD3DDeviceImpl_CreateTexture,
6876 IWineD3DDeviceImpl_CreateVolumeTexture,
6877 IWineD3DDeviceImpl_CreateVolume,
6878 IWineD3DDeviceImpl_CreateCubeTexture,
6879 IWineD3DDeviceImpl_CreateQuery,
6880 IWineD3DDeviceImpl_CreateSwapChain,
6881 IWineD3DDeviceImpl_CreateVertexDeclaration,
6882 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6883 IWineD3DDeviceImpl_CreateVertexShader,
6884 IWineD3DDeviceImpl_CreateGeometryShader,
6885 IWineD3DDeviceImpl_CreatePixelShader,
6886 IWineD3DDeviceImpl_CreatePalette,
6887 /*** Odd functions **/
6888 IWineD3DDeviceImpl_Init3D,
6889 IWineD3DDeviceImpl_InitGDI,
6890 IWineD3DDeviceImpl_Uninit3D,
6891 IWineD3DDeviceImpl_UninitGDI,
6892 IWineD3DDeviceImpl_SetMultithreaded,
6893 IWineD3DDeviceImpl_EvictManagedResources,
6894 IWineD3DDeviceImpl_GetAvailableTextureMem,
6895 IWineD3DDeviceImpl_GetBackBuffer,
6896 IWineD3DDeviceImpl_GetCreationParameters,
6897 IWineD3DDeviceImpl_GetDeviceCaps,
6898 IWineD3DDeviceImpl_GetDirect3D,
6899 IWineD3DDeviceImpl_GetDisplayMode,
6900 IWineD3DDeviceImpl_SetDisplayMode,
6901 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6902 IWineD3DDeviceImpl_GetRasterStatus,
6903 IWineD3DDeviceImpl_GetSwapChain,
6904 IWineD3DDeviceImpl_Reset,
6905 IWineD3DDeviceImpl_SetDialogBoxMode,
6906 IWineD3DDeviceImpl_SetCursorProperties,
6907 IWineD3DDeviceImpl_SetCursorPosition,
6908 IWineD3DDeviceImpl_ShowCursor,
6909 /*** Getters and setters **/
6910 IWineD3DDeviceImpl_SetClipPlane,
6911 IWineD3DDeviceImpl_GetClipPlane,
6912 IWineD3DDeviceImpl_SetClipStatus,
6913 IWineD3DDeviceImpl_GetClipStatus,
6914 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6915 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6916 IWineD3DDeviceImpl_SetDepthStencilSurface,
6917 IWineD3DDeviceImpl_GetDepthStencilSurface,
6918 IWineD3DDeviceImpl_SetGammaRamp,
6919 IWineD3DDeviceImpl_GetGammaRamp,
6920 IWineD3DDeviceImpl_SetIndexBuffer,
6921 IWineD3DDeviceImpl_GetIndexBuffer,
6922 IWineD3DDeviceImpl_SetBaseVertexIndex,
6923 IWineD3DDeviceImpl_GetBaseVertexIndex,
6924 IWineD3DDeviceImpl_SetLight,
6925 IWineD3DDeviceImpl_GetLight,
6926 IWineD3DDeviceImpl_SetLightEnable,
6927 IWineD3DDeviceImpl_GetLightEnable,
6928 IWineD3DDeviceImpl_SetMaterial,
6929 IWineD3DDeviceImpl_GetMaterial,
6930 IWineD3DDeviceImpl_SetNPatchMode,
6931 IWineD3DDeviceImpl_GetNPatchMode,
6932 IWineD3DDeviceImpl_SetPaletteEntries,
6933 IWineD3DDeviceImpl_GetPaletteEntries,
6934 IWineD3DDeviceImpl_SetPixelShader,
6935 IWineD3DDeviceImpl_GetPixelShader,
6936 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6937 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6938 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6939 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6940 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6941 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6942 IWineD3DDeviceImpl_SetRenderState,
6943 IWineD3DDeviceImpl_GetRenderState,
6944 IWineD3DDeviceImpl_SetRenderTarget,
6945 IWineD3DDeviceImpl_GetRenderTarget,
6946 IWineD3DDeviceImpl_SetFrontBackBuffers,
6947 IWineD3DDeviceImpl_SetSamplerState,
6948 IWineD3DDeviceImpl_GetSamplerState,
6949 IWineD3DDeviceImpl_SetScissorRect,
6950 IWineD3DDeviceImpl_GetScissorRect,
6951 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6952 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6953 IWineD3DDeviceImpl_SetStreamSource,
6954 IWineD3DDeviceImpl_GetStreamSource,
6955 IWineD3DDeviceImpl_SetStreamSourceFreq,
6956 IWineD3DDeviceImpl_GetStreamSourceFreq,
6957 IWineD3DDeviceImpl_SetTexture,
6958 IWineD3DDeviceImpl_GetTexture,
6959 IWineD3DDeviceImpl_SetTextureStageState,
6960 IWineD3DDeviceImpl_GetTextureStageState,
6961 IWineD3DDeviceImpl_SetTransform,
6962 IWineD3DDeviceImpl_GetTransform,
6963 IWineD3DDeviceImpl_SetVertexDeclaration,
6964 IWineD3DDeviceImpl_GetVertexDeclaration,
6965 IWineD3DDeviceImpl_SetVertexShader,
6966 IWineD3DDeviceImpl_GetVertexShader,
6967 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6968 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6969 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6970 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6971 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6972 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6973 IWineD3DDeviceImpl_SetViewport,
6974 IWineD3DDeviceImpl_GetViewport,
6975 IWineD3DDeviceImpl_MultiplyTransform,
6976 IWineD3DDeviceImpl_ValidateDevice,
6977 IWineD3DDeviceImpl_ProcessVertices,
6978 /*** State block ***/
6979 IWineD3DDeviceImpl_BeginStateBlock,
6980 IWineD3DDeviceImpl_EndStateBlock,
6981 /*** Scene management ***/
6982 IWineD3DDeviceImpl_BeginScene,
6983 IWineD3DDeviceImpl_EndScene,
6984 IWineD3DDeviceImpl_Present,
6985 IWineD3DDeviceImpl_Clear,
6986 IWineD3DDeviceImpl_ClearRendertargetView,
6987 /*** Drawing ***/
6988 IWineD3DDeviceImpl_SetPrimitiveType,
6989 IWineD3DDeviceImpl_GetPrimitiveType,
6990 IWineD3DDeviceImpl_DrawPrimitive,
6991 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6992 IWineD3DDeviceImpl_DrawPrimitiveUP,
6993 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6994 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6995 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6996 IWineD3DDeviceImpl_DrawRectPatch,
6997 IWineD3DDeviceImpl_DrawTriPatch,
6998 IWineD3DDeviceImpl_DeletePatch,
6999 IWineD3DDeviceImpl_ColorFill,
7000 IWineD3DDeviceImpl_UpdateTexture,
7001 IWineD3DDeviceImpl_UpdateSurface,
7002 IWineD3DDeviceImpl_GetFrontBufferData,
7003 /*** object tracking ***/
7004 IWineD3DDeviceImpl_EnumResources
7007 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
7008 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
7009 IUnknown *parent, IWineD3DDeviceParent *device_parent)
7011 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
7012 const struct fragment_pipeline *fragment_pipeline;
7013 struct shader_caps shader_caps;
7014 struct fragment_caps ffp_caps;
7015 WINED3DDISPLAYMODE mode;
7016 unsigned int i;
7017 HRESULT hr;
7019 device->lpVtbl = &IWineD3DDevice_Vtbl;
7020 device->ref = 1;
7021 device->wined3d = (IWineD3D *)wined3d;
7022 IWineD3D_AddRef(device->wined3d);
7023 device->adapter = wined3d->adapter_count ? adapter : NULL;
7024 device->parent = parent;
7025 device->device_parent = device_parent;
7026 list_init(&device->resources);
7027 list_init(&device->shaders);
7029 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7030 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
7032 /* Get the initial screen setup for ddraw. */
7033 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
7034 if (FAILED(hr))
7036 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7037 IWineD3D_Release(device->wined3d);
7038 return hr;
7040 device->ddraw_width = mode.Width;
7041 device->ddraw_height = mode.Height;
7042 device->ddraw_format = mode.Format;
7044 /* Save the creation parameters. */
7045 device->createParms.AdapterOrdinal = adapter_idx;
7046 device->createParms.DeviceType = device_type;
7047 device->createParms.hFocusWindow = focus_window;
7048 device->createParms.BehaviorFlags = flags;
7050 device->devType = device_type;
7051 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7053 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7054 device->shader_backend = adapter->shader_backend;
7056 memset(&shader_caps, 0, sizeof(shader_caps));
7057 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7058 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7059 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7060 device->vs_clipping = shader_caps.VSClipping;
7062 memset(&ffp_caps, 0, sizeof(ffp_caps));
7063 fragment_pipeline = adapter->fragment_pipe;
7064 device->frag_pipe = fragment_pipeline;
7065 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7066 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7068 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7069 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7070 if (FAILED(hr))
7072 ERR("Failed to compile state table, hr %#x.\n", hr);
7073 IWineD3D_Release(device->wined3d);
7074 return hr;
7077 device->blitter = adapter->blitter;
7079 return WINED3D_OK;
7083 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7084 DWORD rep = This->StateTable[state].representative;
7085 struct wined3d_context *context;
7086 DWORD idx;
7087 BYTE shift;
7088 UINT i;
7090 for(i = 0; i < This->numContexts; i++) {
7091 context = This->contexts[i];
7092 if(isStateDirty(context, rep)) continue;
7094 context->dirtyArray[context->numDirtyEntries++] = rep;
7095 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7096 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7097 context->isStateDirty[idx] |= (1 << shift);
7101 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7103 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.device;
7104 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7105 *width = device->pbufferWidth;
7106 *height = device->pbufferHeight;
7109 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7111 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7112 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7113 *width = surface->pow2Width;
7114 *height = surface->pow2Height;
7117 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7119 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7120 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7121 * current context's drawable, which is the size of the back buffer of the swapchain
7122 * the active context belongs to. The back buffer of the swapchain is stored as the
7123 * surface the context belongs to. */
7124 *width = surface->currentDesc.Width;
7125 *height = surface->currentDesc.Height;
7128 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7129 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7131 if (device->filter_messages)
7133 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7134 window, message, wparam, lparam);
7135 return DefWindowProcW(window, message, wparam, lparam);
7138 if (message == WM_DESTROY)
7140 TRACE("unregister window %p.\n", window);
7141 wined3d_unregister_window(window);
7143 if (device->focus_window == window) device->focus_window = NULL;
7144 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7147 return CallWindowProcW(proc, window, message, wparam, lparam);