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
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 */
50 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
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:
75 case WINED3DPT_LINELIST:
78 case WINED3DPT_LINESTRIP:
81 case WINED3DPT_TRIANGLELIST:
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;
103 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
108 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
110 switch(primitive_type)
113 return WINED3DPT_POINTLIST;
116 return WINED3DPT_LINELIST;
119 return WINED3DPT_LINESTRIP;
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;
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;
168 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
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;
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;
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]);
211 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
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);
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");
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;
244 /* This may be bad with the fixed function pipeline. */
245 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
251 data += element->offset;
253 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
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);
267 idx = element->output_slot;
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));
281 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
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 wined3d_format_desc *format_desc = getFormatDescEntry(strided->format, gl_info);
338 e->format_desc = format_desc;
339 e->stride = strided->dwStride;
340 e->data = strided->lpData;
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)
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;
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);
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;
433 device->useDrawStridedSlow = FALSE;
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;
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;
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);
487 WORD ffu_map = device->fixed_function_usage_map;
489 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
492 device_preload_texture(stateblock, i);
497 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
499 struct wined3d_context **new_array;
501 TRACE("Adding context %p.\n", context);
503 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
504 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
508 ERR("Failed to grow the context array.\n");
512 new_array[device->numContexts++] = context;
513 device->contexts = new_array;
517 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
519 struct wined3d_context **new_array;
523 TRACE("Removing context %p.\n", context);
525 for (i = 0; i < device->numContexts; ++i)
527 if (device->contexts[i] == context)
536 ERR("Context %p doesn't exist in context array.\n", context);
540 if (!--device->numContexts)
542 HeapFree(GetProcessHeap(), 0, device->contexts);
543 device->contexts = NULL;
547 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
548 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
551 ERR("Failed to shrink context array. Oh well.\n");
555 device->contexts = new_array;
559 /**********************************************************
560 * IUnknown parts follows
561 **********************************************************/
563 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
567 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
568 if (IsEqualGUID(riid, &IID_IUnknown)
569 || IsEqualGUID(riid, &IID_IWineD3DBase)
570 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
571 IUnknown_AddRef(iface);
576 return E_NOINTERFACE;
579 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
581 ULONG refCount = InterlockedIncrement(&This->ref);
583 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
587 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
589 ULONG refCount = InterlockedDecrement(&This->ref);
591 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
596 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
597 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
598 This->multistate_funcs[i] = NULL;
601 /* TODO: Clean up all the surfaces and textures! */
602 /* NOTE: You must release the parent if the object was created via a callback
603 ** ***************************/
605 if (!list_empty(&This->resources)) {
606 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
607 dumpResources(&This->resources);
610 if(This->contexts) ERR("Context array not freed!\n");
611 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
612 This->haveHardwareCursor = FALSE;
614 IWineD3D_Release(This->wined3d);
615 This->wined3d = NULL;
616 HeapFree(GetProcessHeap(), 0, This);
617 TRACE("Freed device %p\n", This);
623 /**********************************************************
624 * IWineD3DDevice implementation follows
625 **********************************************************/
626 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
628 *pParent = This->parent;
629 IUnknown_AddRef(This->parent);
633 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
634 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
637 struct wined3d_buffer *object;
640 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
642 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
645 ERR("Failed to allocate memory\n");
646 return E_OUTOFMEMORY;
649 FIXME("Ignoring access flags (pool)\n");
651 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
652 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
655 WARN("Failed to initialize buffer, hr %#x.\n", hr);
656 HeapFree(GetProcessHeap(), 0, object);
659 object->desc = *desc;
661 TRACE("Created buffer %p.\n", object);
663 *buffer = (IWineD3DBuffer *)object;
668 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
669 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
670 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
673 struct wined3d_buffer *object;
676 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
677 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
679 if (Pool == WINED3DPOOL_SCRATCH)
681 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
682 * anyway, SCRATCH vertex buffers aren't usable anywhere
684 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
685 *ppVertexBuffer = NULL;
686 return WINED3DERR_INVALIDCALL;
689 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
692 ERR("Out of memory\n");
693 *ppVertexBuffer = NULL;
694 return WINED3DERR_OUTOFVIDEOMEMORY;
697 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
698 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
701 WARN("Failed to initialize buffer, hr %#x.\n", hr);
702 HeapFree(GetProcessHeap(), 0, object);
706 TRACE("Created buffer %p.\n", object);
707 *ppVertexBuffer = (IWineD3DBuffer *)object;
712 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
713 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
714 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
717 struct wined3d_buffer *object;
720 TRACE("(%p) Creating index buffer\n", This);
722 /* Allocate the storage for the device */
723 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
726 ERR("Out of memory\n");
727 *ppIndexBuffer = NULL;
728 return WINED3DERR_OUTOFVIDEOMEMORY;
731 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
732 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
736 WARN("Failed to initialize buffer, hr %#x\n", hr);
737 HeapFree(GetProcessHeap(), 0, object);
741 TRACE("Created buffer %p.\n", object);
743 *ppIndexBuffer = (IWineD3DBuffer *) object;
748 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
749 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
752 IWineD3DStateBlockImpl *object;
755 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
758 ERR("Failed to allocate stateblock memory.\n");
759 return E_OUTOFMEMORY;
762 hr = stateblock_init(object, This, type);
765 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
766 HeapFree(GetProcessHeap(), 0, object);
770 TRACE("Created stateblock %p.\n", object);
771 *stateblock = (IWineD3DStateBlock *)object;
776 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
777 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
778 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
779 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
782 IWineD3DSurfaceImpl *object;
785 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
786 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
787 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
788 ppSurface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
789 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
791 if (Impl == SURFACE_OPENGL && !This->adapter)
793 ERR("OpenGL surfaces are not available without OpenGL.\n");
794 return WINED3DERR_NOTAVAILABLE;
797 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
800 ERR("Failed to allocate surface memory.\n");
801 return WINED3DERR_OUTOFVIDEOMEMORY;
804 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
805 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
808 WARN("Failed to initialize surface, returning %#x.\n", hr);
809 HeapFree(GetProcessHeap(), 0, object);
813 TRACE("(%p) : Created surface %p\n", This, object);
815 *ppSurface = (IWineD3DSurface *)object;
820 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
821 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
823 struct wined3d_rendertarget_view *object;
825 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
828 ERR("Failed to allocate memory\n");
829 return E_OUTOFMEMORY;
832 object->vtbl = &wined3d_rendertarget_view_vtbl;
833 object->refcount = 1;
834 IWineD3DResource_AddRef(resource);
835 object->resource = resource;
836 object->parent = parent;
838 *rendertarget_view = (IWineD3DRendertargetView *)object;
843 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
844 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
845 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
848 IWineD3DTextureImpl *object;
851 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
852 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
853 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
855 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
858 ERR("Out of memory\n");
860 return WINED3DERR_OUTOFVIDEOMEMORY;
863 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
866 WARN("Failed to initialize texture, returning %#x\n", hr);
867 HeapFree(GetProcessHeap(), 0, object);
872 *ppTexture = (IWineD3DTexture *)object;
874 TRACE("(%p) : Created texture %p\n", This, object);
879 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
880 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
881 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
884 IWineD3DVolumeTextureImpl *object;
887 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
888 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
890 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
893 ERR("Out of memory\n");
894 *ppVolumeTexture = NULL;
895 return WINED3DERR_OUTOFVIDEOMEMORY;
898 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
901 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
902 HeapFree(GetProcessHeap(), 0, object);
903 *ppVolumeTexture = NULL;
907 TRACE("(%p) : Created volume texture %p.\n", This, object);
908 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
913 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
914 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
915 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
918 IWineD3DVolumeImpl *object;
921 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
922 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
924 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
927 ERR("Out of memory\n");
929 return WINED3DERR_OUTOFVIDEOMEMORY;
932 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
935 WARN("Failed to initialize volume, returning %#x.\n", hr);
936 HeapFree(GetProcessHeap(), 0, object);
940 TRACE("(%p) : Created volume %p.\n", This, object);
941 *ppVolume = (IWineD3DVolume *)object;
946 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
947 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
948 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
951 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
954 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
957 ERR("Out of memory\n");
958 *ppCubeTexture = NULL;
959 return WINED3DERR_OUTOFVIDEOMEMORY;
962 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
965 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
966 HeapFree(GetProcessHeap(), 0, object);
967 *ppCubeTexture = NULL;
971 TRACE("(%p) : Created Cube Texture %p\n", This, object);
972 *ppCubeTexture = (IWineD3DCubeTexture *)object;
977 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
978 WINED3DQUERYTYPE type, IWineD3DQuery **query, IUnknown *parent)
980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
981 IWineD3DQueryImpl *object;
984 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface, type, query, parent);
986 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
989 ERR("Failed to allocate query memory.\n");
990 return E_OUTOFMEMORY;
993 hr = query_init(object, This, type, parent);
996 WARN("Failed to initialize query, hr %#x.\n", hr);
997 HeapFree(GetProcessHeap(), 0, object);
1001 TRACE("Created query %p.\n", object);
1002 *query = (IWineD3DQuery *)object;
1007 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1008 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
1009 IUnknown *parent, WINED3DSURFTYPE surface_type)
1011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1012 IWineD3DSwapChainImpl *object;
1015 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1016 iface, present_parameters, swapchain, parent, surface_type);
1018 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1021 ERR("Failed to allocate swapchain memory.\n");
1022 return E_OUTOFMEMORY;
1025 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1028 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1029 HeapFree(GetProcessHeap(), 0, object);
1033 TRACE("Created swapchain %p.\n", object);
1034 *swapchain = (IWineD3DSwapChain *)object;
1039 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1040 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1042 TRACE("(%p)\n", This);
1044 return This->NumberOfSwapChains;
1047 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1048 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1049 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1051 if(iSwapChain < This->NumberOfSwapChains) {
1052 *pSwapChain = This->swapchains[iSwapChain];
1053 IWineD3DSwapChain_AddRef(*pSwapChain);
1054 TRACE("(%p) returning %p\n", This, *pSwapChain);
1057 TRACE("Swapchain out of range\n");
1059 return WINED3DERR_INVALIDCALL;
1063 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1064 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1065 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1068 IWineD3DVertexDeclarationImpl *object = NULL;
1071 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1072 iface, declaration, parent, elements, element_count);
1074 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1077 ERR("Failed to allocate vertex declaration memory.\n");
1078 return E_OUTOFMEMORY;
1081 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1084 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1085 HeapFree(GetProcessHeap(), 0, object);
1089 TRACE("Created vertex declaration %p.\n", object);
1090 *declaration = (IWineD3DVertexDeclaration *)object;
1095 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1096 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1098 unsigned int idx, idx2;
1099 unsigned int offset;
1100 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1101 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1102 BOOL has_blend_idx = has_blend &&
1103 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1104 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1105 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1106 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1107 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1108 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1109 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1111 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1112 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1113 WINED3DVERTEXELEMENT *elements = NULL;
1116 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1117 if (has_blend_idx) num_blends--;
1119 /* Compute declaration size */
1120 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1121 has_psize + has_diffuse + has_specular + num_textures;
1123 /* convert the declaration */
1124 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1125 if (!elements) return ~0U;
1129 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1130 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1131 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1133 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1134 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1135 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1138 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1139 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1141 elements[idx].usage_idx = 0;
1144 if (has_blend && (num_blends > 0)) {
1145 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1146 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1148 switch(num_blends) {
1149 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1150 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1151 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1152 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1154 ERR("Unexpected amount of blend values: %u\n", num_blends);
1157 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1158 elements[idx].usage_idx = 0;
1161 if (has_blend_idx) {
1162 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1163 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1164 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1165 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1166 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1168 elements[idx].format = WINED3DFMT_R32_FLOAT;
1169 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1170 elements[idx].usage_idx = 0;
1174 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1175 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1176 elements[idx].usage_idx = 0;
1180 elements[idx].format = WINED3DFMT_R32_FLOAT;
1181 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1182 elements[idx].usage_idx = 0;
1186 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1187 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1188 elements[idx].usage_idx = 0;
1192 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1193 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1194 elements[idx].usage_idx = 1;
1197 for (idx2 = 0; idx2 < num_textures; idx2++) {
1198 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1199 switch (numcoords) {
1200 case WINED3DFVF_TEXTUREFORMAT1:
1201 elements[idx].format = WINED3DFMT_R32_FLOAT;
1203 case WINED3DFVF_TEXTUREFORMAT2:
1204 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1206 case WINED3DFVF_TEXTUREFORMAT3:
1207 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1209 case WINED3DFVF_TEXTUREFORMAT4:
1210 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1213 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1214 elements[idx].usage_idx = idx2;
1218 /* Now compute offsets, and initialize the rest of the fields */
1219 for (idx = 0, offset = 0; idx < size; ++idx)
1221 const struct wined3d_format_desc *format_desc = getFormatDescEntry(elements[idx].format,
1222 &This->adapter->gl_info);
1223 elements[idx].input_slot = 0;
1224 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1225 elements[idx].offset = offset;
1226 offset += format_desc->component_count * format_desc->component_size;
1229 *ppVertexElements = elements;
1233 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1234 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1235 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1238 WINED3DVERTEXELEMENT *elements;
1242 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1244 size = ConvertFvfToDeclaration(This, fvf, &elements);
1245 if (size == ~0U) return E_OUTOFMEMORY;
1247 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1248 HeapFree(GetProcessHeap(), 0, elements);
1252 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1253 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1254 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1255 const struct wined3d_parent_ops *parent_ops)
1257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1258 IWineD3DVertexShaderImpl *object;
1261 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1264 ERR("Failed to allocate shader memory.\n");
1265 return E_OUTOFMEMORY;
1268 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1271 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1272 HeapFree(GetProcessHeap(), 0, object);
1276 TRACE("Created vertex shader %p.\n", object);
1277 *ppVertexShader = (IWineD3DVertexShader *)object;
1282 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1283 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1284 IWineD3DGeometryShader **shader, IUnknown *parent,
1285 const struct wined3d_parent_ops *parent_ops)
1287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1288 struct wined3d_geometryshader *object;
1291 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1294 ERR("Failed to allocate shader memory.\n");
1295 return E_OUTOFMEMORY;
1298 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1301 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1302 HeapFree(GetProcessHeap(), 0, object);
1306 TRACE("Created geometry shader %p.\n", object);
1307 *shader = (IWineD3DGeometryShader *)object;
1312 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1313 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1314 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1315 const struct wined3d_parent_ops *parent_ops)
1317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1318 IWineD3DPixelShaderImpl *object;
1321 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1324 ERR("Failed to allocate shader memory.\n");
1325 return E_OUTOFMEMORY;
1328 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1331 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1332 HeapFree(GetProcessHeap(), 0, object);
1336 TRACE("Created pixel shader %p.\n", object);
1337 *ppPixelShader = (IWineD3DPixelShader *)object;
1342 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1343 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1346 IWineD3DPaletteImpl *object;
1348 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1350 /* Create the new object */
1351 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1353 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1354 return E_OUTOFMEMORY;
1357 object->lpVtbl = &IWineD3DPalette_Vtbl;
1359 object->Flags = Flags;
1360 object->parent = Parent;
1361 object->device = This;
1362 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1363 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1366 HeapFree( GetProcessHeap(), 0, object);
1367 return E_OUTOFMEMORY;
1370 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1372 IWineD3DPalette_Release((IWineD3DPalette *) object);
1376 *Palette = (IWineD3DPalette *) object;
1381 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1385 HDC dcb = NULL, dcs = NULL;
1386 WINEDDCOLORKEY colorkey;
1388 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1391 GetObjectA(hbm, sizeof(BITMAP), &bm);
1392 dcb = CreateCompatibleDC(NULL);
1394 SelectObject(dcb, hbm);
1398 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1399 * couldn't be loaded
1401 memset(&bm, 0, sizeof(bm));
1406 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1407 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1408 NULL, &wined3d_null_parent_ops);
1410 ERR("Wine logo requested, but failed to create surface\n");
1415 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1416 if(FAILED(hr)) goto out;
1417 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1418 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1420 colorkey.dwColorSpaceLowValue = 0;
1421 colorkey.dwColorSpaceHighValue = 0;
1422 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1424 /* Fill the surface with a white color to show that wined3d is there */
1425 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1429 if (dcb) DeleteDC(dcb);
1430 if (hbm) DeleteObject(hbm);
1433 /* Context activation is done by the caller. */
1434 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1436 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1438 /* Under DirectX you can have texture stage operations even if no texture is
1439 bound, whereas opengl will only do texture operations when a valid texture is
1440 bound. We emulate this by creating dummy textures and binding them to each
1441 texture stage, but disable all stages by default. Hence if a stage is enabled
1442 then the default texture will kick in until replaced by a SetTexture call */
1445 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1447 /* The dummy texture does not have client storage backing */
1448 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1449 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1452 for (i = 0; i < gl_info->limits.textures; ++i)
1454 GLubyte white = 255;
1456 /* Make appropriate texture active */
1457 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1458 checkGLcall("glActiveTextureARB");
1460 /* Generate an opengl texture name */
1461 glGenTextures(1, &This->dummyTextureName[i]);
1462 checkGLcall("glGenTextures");
1463 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1465 /* Generate a dummy 2d texture (not using 1d because they cause many
1466 * DRI drivers fall back to sw) */
1467 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1468 checkGLcall("glBindTexture");
1470 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1471 checkGLcall("glTexImage2D");
1474 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1476 /* Reenable because if supported it is enabled by default */
1477 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1478 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1484 /* Context activation is done by the caller. */
1485 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1488 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1489 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1492 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1495 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1497 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1499 if (!wined3d_register_window(window, device))
1501 ERR("Failed to register window %p.\n", window);
1505 device->focus_window = window;
1506 SetForegroundWindow(window);
1511 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1513 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1515 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1516 device->focus_window = NULL;
1519 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1520 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1523 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1524 IWineD3DSwapChainImpl *swapchain = NULL;
1525 struct wined3d_context *context;
1530 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1532 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1533 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1535 TRACE("(%p) : Creating stateblock\n", This);
1536 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1537 hr = IWineD3DDevice_CreateStateBlock(iface,
1539 (IWineD3DStateBlock **)&This->stateBlock,
1541 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1542 WARN("Failed to create stateblock\n");
1545 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1546 This->updateStateBlock = This->stateBlock;
1547 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1549 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1550 sizeof(IWineD3DSurface *) * gl_info->limits.buffers);
1551 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1552 sizeof(GLenum) * gl_info->limits.buffers);
1554 This->NumberOfPalettes = 1;
1555 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1556 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1557 ERR("Out of memory!\n");
1561 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1562 if(!This->palettes[0]) {
1563 ERR("Out of memory!\n");
1567 for (i = 0; i < 256; ++i) {
1568 This->palettes[0][i].peRed = 0xFF;
1569 This->palettes[0][i].peGreen = 0xFF;
1570 This->palettes[0][i].peBlue = 0xFF;
1571 This->palettes[0][i].peFlags = 0xFF;
1573 This->currentPalette = 0;
1575 /* Initialize the texture unit mapping to a 1:1 mapping */
1576 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1578 if (state < gl_info->limits.fragment_samplers)
1580 This->texUnitMap[state] = state;
1581 This->rev_tex_unit_map[state] = state;
1583 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1584 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1588 /* Setup the implicit swapchain. This also initializes a context. */
1589 TRACE("Creating implicit swapchain\n");
1590 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1591 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1594 WARN("Failed to create implicit swapchain\n");
1598 This->NumberOfSwapChains = 1;
1599 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1600 if(!This->swapchains) {
1601 ERR("Out of memory!\n");
1604 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1606 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1607 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1608 This->render_targets[0] = swapchain->backBuffer[0];
1611 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1612 This->render_targets[0] = swapchain->frontBuffer;
1614 IWineD3DSurface_AddRef(This->render_targets[0]);
1616 /* Depth Stencil support */
1617 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1618 if (NULL != This->stencilBufferTarget) {
1619 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1622 hr = This->shader_backend->shader_alloc_private(iface);
1624 TRACE("Shader private data couldn't be allocated\n");
1627 hr = This->frag_pipe->alloc_private(iface);
1629 TRACE("Fragment pipeline private data couldn't be allocated\n");
1632 hr = This->blitter->alloc_private(iface);
1634 TRACE("Blitter private data couldn't be allocated\n");
1638 /* Set up some starting GL setup */
1640 /* Setup all the devices defaults */
1641 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1643 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1645 create_dummy_textures(This);
1649 /* Initialize the current view state */
1650 This->view_ident = 1;
1651 This->contexts[0]->last_was_rhw = 0;
1652 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1653 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1655 switch(wined3d_settings.offscreen_rendering_mode) {
1657 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1660 case ORM_BACKBUFFER:
1662 if (context_get_current()->aux_buffers > 0)
1664 TRACE("Using auxilliary buffer for offscreen rendering\n");
1665 This->offscreenBuffer = GL_AUX0;
1667 TRACE("Using back buffer for offscreen rendering\n");
1668 This->offscreenBuffer = GL_BACK;
1673 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1676 context_release(context);
1678 /* Clear the screen */
1679 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1680 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1683 This->d3d_initialized = TRUE;
1685 if(wined3d_settings.logo) {
1686 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1688 This->highest_dirty_ps_const = 0;
1689 This->highest_dirty_vs_const = 0;
1693 HeapFree(GetProcessHeap(), 0, This->render_targets);
1694 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1695 HeapFree(GetProcessHeap(), 0, This->swapchains);
1696 This->NumberOfSwapChains = 0;
1697 if(This->palettes) {
1698 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1699 HeapFree(GetProcessHeap(), 0, This->palettes);
1701 This->NumberOfPalettes = 0;
1703 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1705 if(This->stateBlock) {
1706 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1707 This->stateBlock = NULL;
1709 if (This->blit_priv) {
1710 This->blitter->free_private(iface);
1712 if (This->fragment_priv) {
1713 This->frag_pipe->free_private(iface);
1715 if (This->shader_priv) {
1716 This->shader_backend->shader_free_private(iface);
1721 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1722 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1725 IWineD3DSwapChainImpl *swapchain = NULL;
1728 /* Setup the implicit swapchain */
1729 TRACE("Creating implicit swapchain\n");
1730 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1731 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1734 WARN("Failed to create implicit swapchain\n");
1738 This->NumberOfSwapChains = 1;
1739 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1740 if(!This->swapchains) {
1741 ERR("Out of memory!\n");
1744 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1748 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1752 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1754 IWineD3DResource_UnLoad(resource);
1755 IWineD3DResource_Release(resource);
1759 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1760 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1763 const struct wined3d_gl_info *gl_info;
1764 struct wined3d_context *context;
1767 TRACE("(%p)\n", This);
1769 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1771 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1772 * it was created. Thus make sure a context is active for the glDelete* calls
1774 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1775 gl_info = context->gl_info;
1777 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1779 /* Unload resources */
1780 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1782 TRACE("Deleting high order patches\n");
1783 for(i = 0; i < PATCHMAP_SIZE; i++) {
1784 struct list *e1, *e2;
1785 struct WineD3DRectPatch *patch;
1786 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1787 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1788 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1792 /* Delete the mouse cursor texture */
1793 if(This->cursorTexture) {
1795 glDeleteTextures(1, &This->cursorTexture);
1797 This->cursorTexture = 0;
1800 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1801 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1803 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1804 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1807 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1808 * private data, it might contain opengl pointers
1810 if(This->depth_blt_texture) {
1812 glDeleteTextures(1, &This->depth_blt_texture);
1814 This->depth_blt_texture = 0;
1816 if (This->depth_blt_rb) {
1818 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1820 This->depth_blt_rb = 0;
1821 This->depth_blt_rb_w = 0;
1822 This->depth_blt_rb_h = 0;
1825 /* Release the update stateblock */
1826 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1827 if(This->updateStateBlock != This->stateBlock)
1828 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1830 This->updateStateBlock = NULL;
1832 { /* because were not doing proper internal refcounts releasing the primary state block
1833 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1834 to set this->stateBlock = NULL; first */
1835 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1836 This->stateBlock = NULL;
1838 /* Release the stateblock */
1839 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1840 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1844 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1845 This->blitter->free_private(iface);
1846 This->frag_pipe->free_private(iface);
1847 This->shader_backend->shader_free_private(iface);
1849 /* Release the buffers (with sanity checks)*/
1850 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1851 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1852 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
1853 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
1855 This->stencilBufferTarget = NULL;
1857 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1858 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1859 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1861 TRACE("Setting rendertarget to NULL\n");
1862 This->render_targets[0] = NULL;
1864 if (This->auto_depth_stencil_buffer) {
1865 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
1867 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1869 This->auto_depth_stencil_buffer = NULL;
1872 context_release(context);
1874 for(i=0; i < This->NumberOfSwapChains; i++) {
1875 TRACE("Releasing the implicit swapchain %d\n", i);
1876 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1877 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1881 HeapFree(GetProcessHeap(), 0, This->swapchains);
1882 This->swapchains = NULL;
1883 This->NumberOfSwapChains = 0;
1885 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1886 HeapFree(GetProcessHeap(), 0, This->palettes);
1887 This->palettes = NULL;
1888 This->NumberOfPalettes = 0;
1890 HeapFree(GetProcessHeap(), 0, This->render_targets);
1891 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1892 This->render_targets = NULL;
1893 This->draw_buffers = NULL;
1895 This->d3d_initialized = FALSE;
1900 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1904 for(i=0; i < This->NumberOfSwapChains; i++) {
1905 TRACE("Releasing the implicit swapchain %d\n", i);
1906 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1907 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1911 HeapFree(GetProcessHeap(), 0, This->swapchains);
1912 This->swapchains = NULL;
1913 This->NumberOfSwapChains = 0;
1917 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1918 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1919 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1921 * There is no way to deactivate thread safety once it is enabled.
1923 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1926 /*For now just store the flag(needed in case of ddraw) */
1927 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1930 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1931 const WINED3DDISPLAYMODE* pMode) {
1933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1934 const struct wined3d_format_desc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1938 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1940 /* Resize the screen even without a window:
1941 * The app could have unset it with SetCooperativeLevel, but not called
1942 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1943 * but we don't have any hwnd
1946 memset(&devmode, 0, sizeof(devmode));
1947 devmode.dmSize = sizeof(devmode);
1948 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1949 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1950 devmode.dmPelsWidth = pMode->Width;
1951 devmode.dmPelsHeight = pMode->Height;
1953 devmode.dmDisplayFrequency = pMode->RefreshRate;
1954 if (pMode->RefreshRate != 0) {
1955 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1958 /* Only change the mode if necessary */
1959 if( (This->ddraw_width == pMode->Width) &&
1960 (This->ddraw_height == pMode->Height) &&
1961 (This->ddraw_format == pMode->Format) &&
1962 (pMode->RefreshRate == 0) ) {
1966 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1967 if (ret != DISP_CHANGE_SUCCESSFUL) {
1968 if(devmode.dmDisplayFrequency != 0) {
1969 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1970 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1971 devmode.dmDisplayFrequency = 0;
1972 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1974 if(ret != DISP_CHANGE_SUCCESSFUL) {
1975 return WINED3DERR_NOTAVAILABLE;
1979 /* Store the new values */
1980 This->ddraw_width = pMode->Width;
1981 This->ddraw_height = pMode->Height;
1982 This->ddraw_format = pMode->Format;
1984 /* And finally clip mouse to our screen */
1985 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1986 ClipCursor(&clip_rc);
1991 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1992 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1993 *ppD3D = This->wined3d;
1994 TRACE("Returning %p.\n", *ppD3D);
1995 IWineD3D_AddRef(*ppD3D);
1999 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2002 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2003 (This->adapter->TextureRam/(1024*1024)),
2004 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2005 /* return simulated texture memory left */
2006 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2010 * Get / Set Stream Source
2012 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2013 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2016 IWineD3DBuffer *oldSrc;
2018 if (StreamNumber >= MAX_STREAMS) {
2019 WARN("Stream out of range %d\n", StreamNumber);
2020 return WINED3DERR_INVALIDCALL;
2021 } else if(OffsetInBytes & 0x3) {
2022 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2023 return WINED3DERR_INVALIDCALL;
2026 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2027 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2029 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2031 if(oldSrc == pStreamData &&
2032 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2033 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2034 TRACE("Application is setting the old values over, nothing to do\n");
2038 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2040 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2041 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2044 /* Handle recording of state blocks */
2045 if (This->isRecordingState) {
2046 TRACE("Recording... not performing anything\n");
2047 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2048 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2052 if (pStreamData != NULL) {
2053 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2054 IWineD3DBuffer_AddRef(pStreamData);
2056 if (oldSrc != NULL) {
2057 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2058 IWineD3DBuffer_Release(oldSrc);
2061 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2066 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2067 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2071 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2072 This->stateBlock->streamSource[StreamNumber],
2073 This->stateBlock->streamOffset[StreamNumber],
2074 This->stateBlock->streamStride[StreamNumber]);
2076 if (StreamNumber >= MAX_STREAMS) {
2077 WARN("Stream out of range %d\n", StreamNumber);
2078 return WINED3DERR_INVALIDCALL;
2080 *pStream = This->stateBlock->streamSource[StreamNumber];
2081 *pStride = This->stateBlock->streamStride[StreamNumber];
2083 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2086 if (*pStream != NULL) {
2087 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2092 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2094 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2095 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2097 /* Verify input at least in d3d9 this is invalid*/
2098 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2099 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2100 return WINED3DERR_INVALIDCALL;
2102 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2103 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2104 return WINED3DERR_INVALIDCALL;
2107 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2108 return WINED3DERR_INVALIDCALL;
2111 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2112 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2114 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2115 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2117 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2118 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2119 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2125 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2128 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2129 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2131 TRACE("(%p) : returning %d\n", This, *Divider);
2137 * Get / Set & Multiply Transform
2139 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2142 /* Most of this routine, comments included copied from ddraw tree initially: */
2143 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2145 /* Handle recording of state blocks */
2146 if (This->isRecordingState) {
2147 TRACE("Recording... not performing anything\n");
2148 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2149 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2154 * If the new matrix is the same as the current one,
2155 * we cut off any further processing. this seems to be a reasonable
2156 * optimization because as was noticed, some apps (warcraft3 for example)
2157 * tend towards setting the same matrix repeatedly for some reason.
2159 * From here on we assume that the new matrix is different, wherever it matters.
2161 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2162 TRACE("The app is setting the same matrix over again\n");
2165 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2169 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2170 where ViewMat = Camera space, WorldMat = world space.
2172 In OpenGL, camera and world space is combined into GL_MODELVIEW
2173 matrix. The Projection matrix stay projection matrix.
2176 /* Capture the times we can just ignore the change for now */
2177 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2178 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2179 /* Handled by the state manager */
2182 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2186 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2188 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2189 *pMatrix = This->stateBlock->transforms[State];
2193 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2194 const WINED3DMATRIX *mat = NULL;
2197 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2198 * below means it will be recorded in a state block change, but it
2199 * works regardless where it is recorded.
2200 * If this is found to be wrong, change to StateBlock.
2202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2203 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2205 if (State <= HIGHEST_TRANSFORMSTATE)
2207 mat = &This->updateStateBlock->transforms[State];
2209 FIXME("Unhandled transform state!!\n");
2212 multiply_matrix(&temp, mat, pMatrix);
2214 /* Apply change via set transform - will reapply to eg. lights this way */
2215 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2221 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2222 you can reference any indexes you want as long as that number max are enabled at any
2223 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2224 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2225 but when recording, just build a chain pretty much of commands to be replayed. */
2227 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2229 struct wined3d_light_info *object = NULL;
2230 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2234 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2236 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2240 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2241 return WINED3DERR_INVALIDCALL;
2244 switch(pLight->Type) {
2245 case WINED3DLIGHT_POINT:
2246 case WINED3DLIGHT_SPOT:
2247 case WINED3DLIGHT_PARALLELPOINT:
2248 case WINED3DLIGHT_GLSPOT:
2249 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2252 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2254 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2255 return WINED3DERR_INVALIDCALL;
2259 case WINED3DLIGHT_DIRECTIONAL:
2260 /* Ignores attenuation */
2264 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2265 return WINED3DERR_INVALIDCALL;
2268 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2270 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2271 if(object->OriginalIndex == Index) break;
2276 TRACE("Adding new light\n");
2277 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2279 ERR("Out of memory error when allocating a light\n");
2280 return E_OUTOFMEMORY;
2282 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2283 object->glIndex = -1;
2284 object->OriginalIndex = Index;
2287 /* Initialize the object */
2288 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,
2289 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2290 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2291 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2292 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2293 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2294 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2296 /* Save away the information */
2297 object->OriginalParms = *pLight;
2299 switch (pLight->Type) {
2300 case WINED3DLIGHT_POINT:
2302 object->lightPosn[0] = pLight->Position.x;
2303 object->lightPosn[1] = pLight->Position.y;
2304 object->lightPosn[2] = pLight->Position.z;
2305 object->lightPosn[3] = 1.0f;
2306 object->cutoff = 180.0f;
2310 case WINED3DLIGHT_DIRECTIONAL:
2312 object->lightPosn[0] = -pLight->Direction.x;
2313 object->lightPosn[1] = -pLight->Direction.y;
2314 object->lightPosn[2] = -pLight->Direction.z;
2315 object->lightPosn[3] = 0.0f;
2316 object->exponent = 0.0f;
2317 object->cutoff = 180.0f;
2320 case WINED3DLIGHT_SPOT:
2322 object->lightPosn[0] = pLight->Position.x;
2323 object->lightPosn[1] = pLight->Position.y;
2324 object->lightPosn[2] = pLight->Position.z;
2325 object->lightPosn[3] = 1.0f;
2328 object->lightDirn[0] = pLight->Direction.x;
2329 object->lightDirn[1] = pLight->Direction.y;
2330 object->lightDirn[2] = pLight->Direction.z;
2331 object->lightDirn[3] = 1.0f;
2334 * opengl-ish and d3d-ish spot lights use too different models for the
2335 * light "intensity" as a function of the angle towards the main light direction,
2336 * so we only can approximate very roughly.
2337 * however spot lights are rather rarely used in games (if ever used at all).
2338 * furthermore if still used, probably nobody pays attention to such details.
2340 if (pLight->Falloff == 0) {
2341 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2342 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2343 * will always be 1.0 for both of them, and we don't have to care for the
2344 * rest of the rather complex calculation
2346 object->exponent = 0.0f;
2348 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2349 if (rho < 0.0001f) rho = 0.0001f;
2350 object->exponent = -0.3f/logf(cosf(rho/2));
2352 if (object->exponent > 128.0f)
2354 object->exponent = 128.0f;
2356 object->cutoff = pLight->Phi*90/M_PI;
2362 FIXME("Unrecognized light type %d\n", pLight->Type);
2365 /* Update the live definitions if the light is currently assigned a glIndex */
2366 if (object->glIndex != -1 && !This->isRecordingState) {
2367 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2372 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2374 struct wined3d_light_info *lightInfo = NULL;
2375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2376 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2378 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2380 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2382 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2383 if(lightInfo->OriginalIndex == Index) break;
2387 if (lightInfo == NULL) {
2388 TRACE("Light information requested but light not defined\n");
2389 return WINED3DERR_INVALIDCALL;
2392 *pLight = lightInfo->OriginalParms;
2397 * Get / Set Light Enable
2398 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2400 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2402 struct wined3d_light_info *lightInfo = NULL;
2403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2404 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2406 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2408 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2410 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2411 if(lightInfo->OriginalIndex == Index) break;
2414 TRACE("Found light: %p\n", lightInfo);
2416 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2417 if (lightInfo == NULL) {
2419 TRACE("Light enabled requested but light not defined, so defining one!\n");
2420 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2422 /* Search for it again! Should be fairly quick as near head of list */
2423 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2425 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2426 if(lightInfo->OriginalIndex == Index) break;
2429 if (lightInfo == NULL) {
2430 FIXME("Adding default lights has failed dismally\n");
2431 return WINED3DERR_INVALIDCALL;
2436 if(lightInfo->glIndex != -1) {
2437 if(!This->isRecordingState) {
2438 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2441 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2442 lightInfo->glIndex = -1;
2444 TRACE("Light already disabled, nothing to do\n");
2446 lightInfo->enabled = FALSE;
2448 lightInfo->enabled = TRUE;
2449 if (lightInfo->glIndex != -1) {
2451 TRACE("Nothing to do as light was enabled\n");
2454 /* Find a free gl light */
2455 for(i = 0; i < This->maxConcurrentLights; i++) {
2456 if(This->updateStateBlock->activeLights[i] == NULL) {
2457 This->updateStateBlock->activeLights[i] = lightInfo;
2458 lightInfo->glIndex = i;
2462 if(lightInfo->glIndex == -1) {
2463 /* Our tests show that Windows returns D3D_OK in this situation, even with
2464 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2465 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2466 * as well for those lights.
2468 * TODO: Test how this affects rendering
2470 WARN("Too many concurrently active lights\n");
2474 /* i == lightInfo->glIndex */
2475 if(!This->isRecordingState) {
2476 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2484 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2486 struct wined3d_light_info *lightInfo = NULL;
2487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2489 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2490 TRACE("(%p) : for idx(%d)\n", This, Index);
2492 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2494 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2495 if(lightInfo->OriginalIndex == Index) break;
2499 if (lightInfo == NULL) {
2500 TRACE("Light enabled state requested but light not defined\n");
2501 return WINED3DERR_INVALIDCALL;
2503 /* true is 128 according to SetLightEnable */
2504 *pEnable = lightInfo->enabled ? 128 : 0;
2509 * Get / Set Clip Planes
2511 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2513 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2515 /* Validate Index */
2516 if (Index >= This->adapter->gl_info.limits.clipplanes)
2518 TRACE("Application has requested clipplane this device doesn't support\n");
2519 return WINED3DERR_INVALIDCALL;
2522 This->updateStateBlock->changed.clipplane |= 1 << Index;
2524 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2525 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2526 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2527 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2528 TRACE("Application is setting old values over, nothing to do\n");
2532 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2533 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2534 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2535 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2537 /* Handle recording of state blocks */
2538 if (This->isRecordingState) {
2539 TRACE("Recording... not performing anything\n");
2543 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2548 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2550 TRACE("(%p) : for idx %d\n", This, Index);
2552 /* Validate Index */
2553 if (Index >= This->adapter->gl_info.limits.clipplanes)
2555 TRACE("Application has requested clipplane this device doesn't support\n");
2556 return WINED3DERR_INVALIDCALL;
2559 pPlane[0] = This->stateBlock->clipplane[Index][0];
2560 pPlane[1] = This->stateBlock->clipplane[Index][1];
2561 pPlane[2] = This->stateBlock->clipplane[Index][2];
2562 pPlane[3] = This->stateBlock->clipplane[Index][3];
2567 * Get / Set Clip Plane Status
2568 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2570 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2572 FIXME("(%p) : stub\n", This);
2573 if (NULL == pClipStatus) {
2574 return WINED3DERR_INVALIDCALL;
2576 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2577 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2581 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2583 FIXME("(%p) : stub\n", This);
2584 if (NULL == pClipStatus) {
2585 return WINED3DERR_INVALIDCALL;
2587 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2588 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2593 * Get / Set Material
2595 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2598 This->updateStateBlock->changed.material = TRUE;
2599 This->updateStateBlock->material = *pMaterial;
2601 /* Handle recording of state blocks */
2602 if (This->isRecordingState) {
2603 TRACE("Recording... not performing anything\n");
2607 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2611 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2613 *pMaterial = This->updateStateBlock->material;
2614 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2615 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2616 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2617 pMaterial->Ambient.b, pMaterial->Ambient.a);
2618 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2619 pMaterial->Specular.b, pMaterial->Specular.a);
2620 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2621 pMaterial->Emissive.b, pMaterial->Emissive.a);
2622 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2630 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2631 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2634 IWineD3DBuffer *oldIdxs;
2636 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2637 oldIdxs = This->updateStateBlock->pIndexData;
2639 This->updateStateBlock->changed.indices = TRUE;
2640 This->updateStateBlock->pIndexData = pIndexData;
2641 This->updateStateBlock->IndexFmt = fmt;
2643 /* Handle recording of state blocks */
2644 if (This->isRecordingState) {
2645 TRACE("Recording... not performing anything\n");
2646 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2647 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2651 if(oldIdxs != pIndexData) {
2652 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2654 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2655 IWineD3DBuffer_AddRef(pIndexData);
2658 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2659 IWineD3DBuffer_Release(oldIdxs);
2666 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2670 *ppIndexData = This->stateBlock->pIndexData;
2672 /* up ref count on ppindexdata */
2674 IWineD3DBuffer_AddRef(*ppIndexData);
2675 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2677 TRACE("(%p) No index data set\n", This);
2679 TRACE("Returning %p\n", *ppIndexData);
2684 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2685 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2687 TRACE("(%p)->(%d)\n", This, BaseIndex);
2689 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2690 TRACE("Application is setting the old value over, nothing to do\n");
2694 This->updateStateBlock->baseVertexIndex = BaseIndex;
2696 if (This->isRecordingState) {
2697 TRACE("Recording... not performing anything\n");
2700 /* The base vertex index affects the stream sources */
2701 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2705 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2707 TRACE("(%p) : base_index %p\n", This, base_index);
2709 *base_index = This->stateBlock->baseVertexIndex;
2711 TRACE("Returning %u\n", *base_index);
2717 * Get / Set Viewports
2719 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2722 TRACE("(%p)\n", This);
2723 This->updateStateBlock->changed.viewport = TRUE;
2724 This->updateStateBlock->viewport = *pViewport;
2726 /* Handle recording of state blocks */
2727 if (This->isRecordingState) {
2728 TRACE("Recording... not performing anything\n");
2732 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2733 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2735 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2740 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2742 TRACE("(%p)\n", This);
2743 *pViewport = This->stateBlock->viewport;
2748 * Get / Set Render States
2749 * TODO: Verify against dx9 definitions
2751 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2754 DWORD oldValue = This->stateBlock->renderState[State];
2756 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2758 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2759 This->updateStateBlock->renderState[State] = Value;
2761 /* Handle recording of state blocks */
2762 if (This->isRecordingState) {
2763 TRACE("Recording... not performing anything\n");
2767 /* Compared here and not before the assignment to allow proper stateblock recording */
2768 if(Value == oldValue) {
2769 TRACE("Application is setting the old value over, nothing to do\n");
2771 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2777 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2779 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2780 *pValue = This->stateBlock->renderState[State];
2785 * Get / Set Sampler States
2786 * TODO: Verify against dx9 definitions
2789 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2793 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2794 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2796 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2797 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2800 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2801 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2802 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2805 * SetSampler is designed to allow for more than the standard up to 8 textures
2806 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2807 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2809 * http://developer.nvidia.com/object/General_FAQ.html#t6
2811 * There are two new settings for GForce
2813 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2814 * and the texture one:
2815 * GL_MAX_TEXTURE_COORDS_ARB.
2816 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2819 oldValue = This->stateBlock->samplerState[Sampler][Type];
2820 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2821 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2823 /* Handle recording of state blocks */
2824 if (This->isRecordingState) {
2825 TRACE("Recording... not performing anything\n");
2829 if(oldValue == Value) {
2830 TRACE("Application is setting the old value over, nothing to do\n");
2834 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2839 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2840 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2842 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2843 This, Sampler, debug_d3dsamplerstate(Type), Type);
2845 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2846 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2849 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2850 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2851 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2853 *Value = This->stateBlock->samplerState[Sampler][Type];
2854 TRACE("(%p) : Returning %#x\n", This, *Value);
2859 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2862 This->updateStateBlock->changed.scissorRect = TRUE;
2863 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2864 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2867 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2869 if(This->isRecordingState) {
2870 TRACE("Recording... not performing anything\n");
2874 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2879 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2882 *pRect = This->updateStateBlock->scissorRect;
2883 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2887 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2889 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2891 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2893 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2894 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2896 This->updateStateBlock->vertexDecl = pDecl;
2897 This->updateStateBlock->changed.vertexDecl = TRUE;
2899 if (This->isRecordingState) {
2900 TRACE("Recording... not performing anything\n");
2902 } else if(pDecl == oldDecl) {
2903 /* Checked after the assignment to allow proper stateblock recording */
2904 TRACE("Application is setting the old declaration over, nothing to do\n");
2908 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2912 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2915 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2917 *ppDecl = This->stateBlock->vertexDecl;
2918 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2922 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2924 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2926 This->updateStateBlock->vertexShader = pShader;
2927 This->updateStateBlock->changed.vertexShader = TRUE;
2929 if (This->isRecordingState) {
2930 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2931 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2932 TRACE("Recording... not performing anything\n");
2934 } else if(oldShader == pShader) {
2935 /* Checked here to allow proper stateblock recording */
2936 TRACE("App is setting the old shader over, nothing to do\n");
2940 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2941 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2942 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2944 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2949 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2952 if (NULL == ppShader) {
2953 return WINED3DERR_INVALIDCALL;
2955 *ppShader = This->stateBlock->vertexShader;
2956 if( NULL != *ppShader)
2957 IWineD3DVertexShader_AddRef(*ppShader);
2959 TRACE("(%p) : returning %p\n", This, *ppShader);
2963 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2964 IWineD3DDevice *iface,
2966 CONST BOOL *srcData,
2969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2970 unsigned int i, cnt = min(count, MAX_CONST_B - start);
2972 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2973 iface, srcData, start, count);
2975 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
2977 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2978 for (i = 0; i < cnt; i++)
2979 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2981 for (i = start; i < cnt + start; ++i) {
2982 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
2985 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2990 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2991 IWineD3DDevice *iface,
2996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2997 int cnt = min(count, MAX_CONST_B - start);
2999 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3000 iface, dstData, start, count);
3002 if (dstData == NULL || cnt < 0)
3003 return WINED3DERR_INVALIDCALL;
3005 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3009 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3010 IWineD3DDevice *iface,
3015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3016 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3018 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3019 iface, srcData, start, count);
3021 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3023 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3024 for (i = 0; i < cnt; i++)
3025 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3026 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3028 for (i = start; i < cnt + start; ++i) {
3029 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3032 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3037 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3038 IWineD3DDevice *iface,
3043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3044 int cnt = min(count, MAX_CONST_I - start);
3046 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3047 iface, dstData, start, count);
3049 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3050 return WINED3DERR_INVALIDCALL;
3052 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3056 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3057 IWineD3DDevice *iface,
3059 CONST float *srcData,
3062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3065 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3066 iface, srcData, start, count);
3068 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3069 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3070 return WINED3DERR_INVALIDCALL;
3072 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3074 for (i = 0; i < count; i++)
3075 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3076 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3079 if (!This->isRecordingState)
3081 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3082 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3085 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3086 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3091 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3092 IWineD3DDevice *iface,
3097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3098 int cnt = min(count, This->d3d_vshader_constantF - start);
3100 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3101 iface, dstData, start, count);
3103 if (dstData == NULL || cnt < 0)
3104 return WINED3DERR_INVALIDCALL;
3106 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3110 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3112 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3114 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3118 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3120 DWORD i = This->rev_tex_unit_map[unit];
3121 DWORD j = This->texUnitMap[stage];
3123 This->texUnitMap[stage] = unit;
3124 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3126 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3129 This->rev_tex_unit_map[unit] = stage;
3130 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3132 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3136 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3139 This->fixed_function_usage_map = 0;
3140 for (i = 0; i < MAX_TEXTURES; ++i) {
3141 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3142 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3143 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3144 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3145 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3146 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3147 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3148 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3150 if (color_op == WINED3DTOP_DISABLE) {
3151 /* Not used, and disable higher stages */
3155 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3156 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3157 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3158 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3159 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3160 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3161 This->fixed_function_usage_map |= (1 << i);
3164 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3165 This->fixed_function_usage_map |= (1 << (i + 1));
3170 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3172 unsigned int i, tex;
3175 device_update_fixed_function_usage_map(This);
3176 ffu_map = This->fixed_function_usage_map;
3178 if (This->max_ffp_textures == gl_info->limits.texture_stages
3179 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3181 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3183 if (!(ffu_map & 1)) continue;
3185 if (This->texUnitMap[i] != i) {
3186 device_map_stage(This, i, i);
3187 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3188 markTextureStagesDirty(This, i);
3194 /* Now work out the mapping */
3196 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3198 if (!(ffu_map & 1)) continue;
3200 if (This->texUnitMap[i] != tex) {
3201 device_map_stage(This, i, tex);
3202 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3203 markTextureStagesDirty(This, i);
3210 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3212 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3213 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3216 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3217 if (sampler_type[i] && This->texUnitMap[i] != i)
3219 device_map_stage(This, i, i);
3220 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3221 if (i < gl_info->limits.texture_stages)
3223 markTextureStagesDirty(This, i);
3229 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3230 const DWORD *vshader_sampler_tokens, DWORD unit)
3232 DWORD current_mapping = This->rev_tex_unit_map[unit];
3234 /* Not currently used */
3235 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3237 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3238 /* Used by a fragment sampler */
3240 if (!pshader_sampler_tokens) {
3241 /* No pixel shader, check fixed function */
3242 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3245 /* Pixel shader, check the shader's sampler map */
3246 return !pshader_sampler_tokens[current_mapping];
3249 /* Used by a vertex sampler */
3250 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3253 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3255 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3256 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3257 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3258 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3262 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3264 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3265 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3266 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3269 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3270 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3271 if (vshader_sampler_type[i])
3273 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3275 /* Already mapped somewhere */
3279 while (start >= 0) {
3280 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3282 device_map_stage(This, vsampler_idx, start);
3283 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3295 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3297 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3298 BOOL vs = use_vs(This->stateBlock);
3299 BOOL ps = use_ps(This->stateBlock);
3302 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3303 * that would be really messy and require shader recompilation
3304 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3305 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3307 if (ps) device_map_psamplers(This, gl_info);
3308 else device_map_fixed_function_samplers(This, gl_info);
3310 if (vs) device_map_vsamplers(This, ps, gl_info);
3313 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3315 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3316 This->updateStateBlock->pixelShader = pShader;
3317 This->updateStateBlock->changed.pixelShader = TRUE;
3319 /* Handle recording of state blocks */
3320 if (This->isRecordingState) {
3321 TRACE("Recording... not performing anything\n");
3324 if (This->isRecordingState) {
3325 TRACE("Recording... not performing anything\n");
3326 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3327 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3331 if(pShader == oldShader) {
3332 TRACE("App is setting the old pixel shader over, nothing to do\n");
3336 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3337 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3339 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3340 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3345 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3348 if (NULL == ppShader) {
3349 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3350 return WINED3DERR_INVALIDCALL;
3353 *ppShader = This->stateBlock->pixelShader;
3354 if (NULL != *ppShader) {
3355 IWineD3DPixelShader_AddRef(*ppShader);
3357 TRACE("(%p) : returning %p\n", This, *ppShader);
3361 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3362 IWineD3DDevice *iface,
3364 CONST BOOL *srcData,
3367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3368 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3370 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3371 iface, srcData, start, count);
3373 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3375 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3376 for (i = 0; i < cnt; i++)
3377 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3379 for (i = start; i < cnt + start; ++i) {
3380 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3383 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3388 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3389 IWineD3DDevice *iface,
3394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3395 int cnt = min(count, MAX_CONST_B - start);
3397 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3398 iface, dstData, start, count);
3400 if (dstData == NULL || cnt < 0)
3401 return WINED3DERR_INVALIDCALL;
3403 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3407 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3408 IWineD3DDevice *iface,
3413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3414 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3416 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3417 iface, srcData, start, count);
3419 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3421 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3422 for (i = 0; i < cnt; i++)
3423 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3424 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3426 for (i = start; i < cnt + start; ++i) {
3427 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3430 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3435 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3436 IWineD3DDevice *iface,
3441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3442 int cnt = min(count, MAX_CONST_I - start);
3444 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3445 iface, dstData, start, count);
3447 if (dstData == NULL || cnt < 0)
3448 return WINED3DERR_INVALIDCALL;
3450 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3454 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3455 IWineD3DDevice *iface,
3457 CONST float *srcData,
3460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3463 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3464 iface, srcData, start, count);
3466 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3467 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3468 return WINED3DERR_INVALIDCALL;
3470 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3472 for (i = 0; i < count; i++)
3473 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3474 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3477 if (!This->isRecordingState)
3479 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3480 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3483 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3484 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3489 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3490 IWineD3DDevice *iface,
3495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3496 int cnt = min(count, This->d3d_pshader_constantF - start);
3498 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3499 iface, dstData, start, count);
3501 if (dstData == NULL || cnt < 0)
3502 return WINED3DERR_INVALIDCALL;
3504 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3508 /* Context activation is done by the caller. */
3509 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3510 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3511 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3514 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3515 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3518 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3522 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3524 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3527 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3529 ERR("Source has no position mask\n");
3530 return WINED3DERR_INVALIDCALL;
3533 /* We might access VBOs from this code, so hold the lock */
3536 if (dest->resource.allocatedMemory == NULL) {
3537 buffer_get_sysmem(dest);
3540 /* Get a pointer into the destination vbo(create one if none exists) and
3541 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3543 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3545 dest->flags |= WINED3D_BUFFER_CREATEBO;
3546 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3549 if (dest->buffer_object)
3551 unsigned char extrabytes = 0;
3552 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3553 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3554 * this may write 4 extra bytes beyond the area that should be written
3556 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3557 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3558 if(!dest_conv_addr) {
3559 ERR("Out of memory\n");
3560 /* Continue without storing converted vertices */
3562 dest_conv = dest_conv_addr;
3566 * a) WINED3DRS_CLIPPING is enabled
3567 * b) WINED3DVOP_CLIP is passed
3569 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3570 static BOOL warned = FALSE;
3572 * The clipping code is not quite correct. Some things need
3573 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3574 * so disable clipping for now.
3575 * (The graphics in Half-Life are broken, and my processvertices
3576 * test crashes with IDirect3DDevice3)
3582 FIXME("Clipping is broken and disabled for now\n");
3584 } else doClip = FALSE;
3585 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3587 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3590 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3591 WINED3DTS_PROJECTION,
3593 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3594 WINED3DTS_WORLDMATRIX(0),
3597 TRACE("View mat:\n");
3598 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);
3599 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);
3600 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);
3601 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);
3603 TRACE("Proj mat:\n");
3604 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);
3605 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);
3606 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);
3607 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);
3609 TRACE("World mat:\n");
3610 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);
3611 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);
3612 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);
3613 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);
3615 /* Get the viewport */
3616 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3617 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3618 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3620 multiply_matrix(&mat,&view_mat,&world_mat);
3621 multiply_matrix(&mat,&proj_mat,&mat);
3623 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3625 for (i = 0; i < dwCount; i+= 1) {
3626 unsigned int tex_index;
3628 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3629 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3630 /* The position first */
3631 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3632 const float *p = (const float *)(element->data + i * element->stride);
3634 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3636 /* Multiplication with world, view and projection matrix */
3637 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);
3638 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);
3639 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);
3640 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);
3642 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3644 /* WARNING: The following things are taken from d3d7 and were not yet checked
3645 * against d3d8 or d3d9!
3648 /* Clipping conditions: From msdn
3650 * A vertex is clipped if it does not match the following requirements
3654 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3656 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3657 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3662 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3663 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3666 /* "Normal" viewport transformation (not clipped)
3667 * 1) The values are divided by rhw
3668 * 2) The y axis is negative, so multiply it with -1
3669 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3670 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3671 * 4) Multiply x with Width/2 and add Width/2
3672 * 5) The same for the height
3673 * 6) Add the viewpoint X and Y to the 2D coordinates and
3674 * The minimum Z value to z
3675 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3677 * Well, basically it's simply a linear transformation into viewport
3689 z *= vp.MaxZ - vp.MinZ;
3691 x += vp.Width / 2 + vp.X;
3692 y += vp.Height / 2 + vp.Y;
3697 /* That vertex got clipped
3698 * Contrary to OpenGL it is not dropped completely, it just
3699 * undergoes a different calculation.
3701 TRACE("Vertex got clipped\n");
3708 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3709 * outside of the main vertex buffer memory. That needs some more
3714 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3717 ( (float *) dest_ptr)[0] = x;
3718 ( (float *) dest_ptr)[1] = y;
3719 ( (float *) dest_ptr)[2] = z;
3720 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3722 dest_ptr += 3 * sizeof(float);
3724 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3725 dest_ptr += sizeof(float);
3730 ( (float *) dest_conv)[0] = x * w;
3731 ( (float *) dest_conv)[1] = y * w;
3732 ( (float *) dest_conv)[2] = z * w;
3733 ( (float *) dest_conv)[3] = w;
3735 dest_conv += 3 * sizeof(float);
3737 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3738 dest_conv += sizeof(float);
3742 if (DestFVF & WINED3DFVF_PSIZE) {
3743 dest_ptr += sizeof(DWORD);
3744 if(dest_conv) dest_conv += sizeof(DWORD);
3746 if (DestFVF & WINED3DFVF_NORMAL) {
3747 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3748 const float *normal = (const float *)(element->data + i * element->stride);
3749 /* AFAIK this should go into the lighting information */
3750 FIXME("Didn't expect the destination to have a normal\n");
3751 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3753 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3757 if (DestFVF & WINED3DFVF_DIFFUSE) {
3758 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3759 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3760 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3762 static BOOL warned = FALSE;
3765 ERR("No diffuse color in source, but destination has one\n");
3769 *( (DWORD *) dest_ptr) = 0xffffffff;
3770 dest_ptr += sizeof(DWORD);
3773 *( (DWORD *) dest_conv) = 0xffffffff;
3774 dest_conv += sizeof(DWORD);
3778 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3780 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3781 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3782 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3783 dest_conv += sizeof(DWORD);
3788 if (DestFVF & WINED3DFVF_SPECULAR)
3790 /* What's the color value in the feedback buffer? */
3791 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3792 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3793 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3795 static BOOL warned = FALSE;
3798 ERR("No specular color in source, but destination has one\n");
3802 *( (DWORD *) dest_ptr) = 0xFF000000;
3803 dest_ptr += sizeof(DWORD);
3806 *( (DWORD *) dest_conv) = 0xFF000000;
3807 dest_conv += sizeof(DWORD);
3811 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3813 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3814 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3815 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3816 dest_conv += sizeof(DWORD);
3821 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3822 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3823 const float *tex_coord = (const float *)(element->data + i * element->stride);
3824 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3826 ERR("No source texture, but destination requests one\n");
3827 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3828 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3831 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3833 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3840 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3841 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3842 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3843 dwCount * get_flexible_vertex_size(DestFVF),
3845 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3846 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3853 #undef copy_and_next
3855 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3856 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3860 struct wined3d_stream_info stream_info;
3861 struct wined3d_context *context;
3862 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3865 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3868 ERR("Output vertex declaration not implemented yet\n");
3871 /* Need any context to write to the vbo. */
3872 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
3874 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3875 * control the streamIsUP flag, thus restore it afterwards.
3877 This->stateBlock->streamIsUP = FALSE;
3878 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3879 This->stateBlock->streamIsUP = streamWasUP;
3881 if(vbo || SrcStartIndex) {
3883 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3884 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3886 * Also get the start index in, but only loop over all elements if there's something to add at all.
3888 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3890 struct wined3d_stream_info_element *e;
3892 if (!(stream_info.use_map & (1 << i))) continue;
3894 e = &stream_info.elements[i];
3895 if (e->buffer_object)
3897 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3898 e->buffer_object = 0;
3899 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3901 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3902 vb->buffer_object = 0;
3905 if (e->data) e->data += e->stride * SrcStartIndex;
3909 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3910 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3912 context_release(context);
3918 * Get / Set Texture Stage States
3919 * TODO: Verify against dx9 definitions
3921 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3923 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3924 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3926 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3928 if (Stage >= gl_info->limits.texture_stages)
3930 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3931 Stage, gl_info->limits.texture_stages - 1);
3935 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3936 This->updateStateBlock->textureState[Stage][Type] = Value;
3938 if (This->isRecordingState) {
3939 TRACE("Recording... not performing anything\n");
3943 /* Checked after the assignments to allow proper stateblock recording */
3944 if(oldValue == Value) {
3945 TRACE("App is setting the old value over, nothing to do\n");
3949 if(Stage > This->stateBlock->lowest_disabled_stage &&
3950 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3951 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3952 * Changes in other states are important on disabled stages too
3957 if(Type == WINED3DTSS_COLOROP) {
3960 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3961 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3962 * they have to be disabled
3964 * The current stage is dirtified below.
3966 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3967 TRACE("Additionally dirtifying stage %u\n", i);
3968 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3970 This->stateBlock->lowest_disabled_stage = Stage;
3971 TRACE("New lowest disabled: %u\n", Stage);
3972 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3973 /* Previously disabled stage enabled. Stages above it may need enabling
3974 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3975 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3977 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3980 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
3982 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3985 TRACE("Additionally dirtifying stage %u due to enable\n", i);
3986 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3988 This->stateBlock->lowest_disabled_stage = i;
3989 TRACE("New lowest disabled: %u\n", i);
3993 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3998 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4000 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4001 *pValue = This->updateStateBlock->textureState[Stage][Type];
4008 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4009 DWORD stage, IWineD3DBaseTexture *texture)
4011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4012 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4013 IWineD3DBaseTexture *prev;
4015 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4017 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4018 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4020 /* Windows accepts overflowing this array... we do not. */
4021 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4023 WARN("Ignoring invalid stage %u.\n", stage);
4027 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4028 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4030 WARN("Rejecting attempt to set scratch texture.\n");
4031 return WINED3DERR_INVALIDCALL;
4034 This->updateStateBlock->changed.textures |= 1 << stage;
4036 prev = This->updateStateBlock->textures[stage];
4037 TRACE("Previous texture %p.\n", prev);
4039 if (texture == prev)
4041 TRACE("App is setting the same texture again, nothing to do.\n");
4045 TRACE("Setting new texture to %p.\n", texture);
4046 This->updateStateBlock->textures[stage] = texture;
4048 if (This->isRecordingState)
4050 TRACE("Recording... not performing anything\n");
4052 if (texture) IWineD3DBaseTexture_AddRef(texture);
4053 if (prev) IWineD3DBaseTexture_Release(prev);
4060 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4061 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4062 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4064 IWineD3DBaseTexture_AddRef(texture);
4066 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4068 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4071 if (!prev && stage < gl_info->limits.texture_stages)
4073 /* The source arguments for color and alpha ops have different
4074 * meanings when a NULL texture is bound, so the COLOROP and
4075 * ALPHAOP have to be dirtified. */
4076 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4077 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4080 if (bind_count == 1) t->baseTexture.sampler = stage;
4085 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4086 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4088 IWineD3DBaseTexture_Release(prev);
4090 if (!texture && stage < gl_info->limits.texture_stages)
4092 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4093 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4096 if (bind_count && t->baseTexture.sampler == stage)
4100 /* Search for other stages the texture is bound to. Shouldn't
4101 * happen if applications bind textures to a single stage only. */
4102 TRACE("Searching for other stages the texture is bound to.\n");
4103 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4105 if (This->updateStateBlock->textures[i] == prev)
4107 TRACE("Texture is also bound to stage %u.\n", i);
4108 t->baseTexture.sampler = i;
4115 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4120 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4123 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4125 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4126 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4129 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4130 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4131 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4134 *ppTexture=This->stateBlock->textures[Stage];
4136 IWineD3DBaseTexture_AddRef(*ppTexture);
4138 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4146 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4147 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4149 IWineD3DSwapChain *swapchain;
4152 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4153 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4155 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4158 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4162 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4163 IWineD3DSwapChain_Release(swapchain);
4166 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4173 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4175 WARN("(%p) : stub, calling idirect3d for now\n", This);
4176 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4179 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4181 IWineD3DSwapChain *swapChain;
4184 if(iSwapChain > 0) {
4185 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4186 if (hr == WINED3D_OK) {
4187 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4188 IWineD3DSwapChain_Release(swapChain);
4190 FIXME("(%p) Error getting display mode\n", This);
4193 /* Don't read the real display mode,
4194 but return the stored mode instead. X11 can't change the color
4195 depth, and some apps are pretty angry if they SetDisplayMode from
4196 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4198 Also don't relay to the swapchain because with ddraw it's possible
4199 that there isn't a swapchain at all */
4200 pMode->Width = This->ddraw_width;
4201 pMode->Height = This->ddraw_height;
4202 pMode->Format = This->ddraw_format;
4203 pMode->RefreshRate = 0;
4211 * Stateblock related functions
4214 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4216 IWineD3DStateBlock *stateblock;
4219 TRACE("(%p)\n", This);
4221 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4223 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4224 if (FAILED(hr)) return hr;
4226 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4227 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4228 This->isRecordingState = TRUE;
4230 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4235 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4237 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4239 if (!This->isRecordingState) {
4240 WARN("(%p) not recording! returning error\n", This);
4241 *ppStateBlock = NULL;
4242 return WINED3DERR_INVALIDCALL;
4245 stateblock_init_contained_states(object);
4247 *ppStateBlock = (IWineD3DStateBlock*) object;
4248 This->isRecordingState = FALSE;
4249 This->updateStateBlock = This->stateBlock;
4250 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4251 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4252 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4257 * Scene related functions
4259 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4260 /* At the moment we have no need for any functionality at the beginning
4262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4263 TRACE("(%p)\n", This);
4266 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4267 return WINED3DERR_INVALIDCALL;
4269 This->inScene = TRUE;
4273 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4276 struct wined3d_context *context;
4278 TRACE("(%p)\n", This);
4280 if(!This->inScene) {
4281 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4282 return WINED3DERR_INVALIDCALL;
4285 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4286 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4288 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4290 context_release(context);
4292 This->inScene = FALSE;
4296 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4297 const RECT *pSourceRect, const RECT *pDestRect,
4298 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4300 IWineD3DSwapChain *swapChain = NULL;
4302 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4304 TRACE("iface %p.\n", iface);
4306 for(i = 0 ; i < swapchains ; i ++) {
4308 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4309 TRACE("presentinng chain %d, %p\n", i, swapChain);
4310 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4311 IWineD3DSwapChain_Release(swapChain);
4317 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const WINED3DVIEWPORT *viewport,
4318 const RECT *scissor_rect, const WINED3DRECT *clear_rect)
4320 /* partial viewport*/
4321 if (viewport->X != 0 || viewport->Y != 0
4322 || viewport->Width < target->currentDesc.Width
4323 || viewport->Height < target->currentDesc.Height)
4326 /* partial scissor rect */
4327 if (scissor_rect && (scissor_rect->left > 0 || scissor_rect->top > 0
4328 || scissor_rect->right < target->currentDesc.Width
4329 || scissor_rect->bottom < target->currentDesc.Height))
4332 /* partial clear rect */
4333 if (clear_rect && (clear_rect->x1 > 0 || clear_rect->y1 > 0
4334 || clear_rect->x2 < target->currentDesc.Width
4335 || clear_rect->y2 < target->currentDesc.Height))
4341 /* Not called from the VTable (internal subroutine) */
4342 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4343 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil)
4345 IWineD3DStateBlockImpl *stateblock = This->stateBlock;
4346 const RECT *scissor_rect = stateblock->renderState[WINED3DRS_SCISSORTESTENABLE] ? &stateblock->scissorRect : NULL;
4347 const WINED3DRECT *clear_rect = (Count > 0 && pRects) ? pRects : NULL;
4348 const WINED3DVIEWPORT *vp = &stateblock->viewport;
4349 GLbitfield glMask = 0;
4351 WINED3DRECT curRect;
4353 UINT drawable_width, drawable_height;
4354 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4355 struct wined3d_context *context;
4357 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4358 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4359 * for the cleared parts, and the untouched parts.
4361 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4362 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4363 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4364 * checking all this if the dest surface is in the drawable anyway.
4366 if (Flags & WINED3DCLEAR_TARGET && !(target->Flags & SFLAG_INDRAWABLE))
4368 if (!is_full_clear(target, vp, scissor_rect, clear_rect))
4369 IWineD3DSurface_LoadLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, NULL);
4372 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4373 if (!context->valid)
4375 context_release(context);
4376 WARN("Invalid context, skipping clear.\n");
4380 target->get_drawable_size(context, &drawable_width, &drawable_height);
4384 /* Only set the values up once, as they are not changing */
4385 if (Flags & WINED3DCLEAR_STENCIL) {
4386 glClearStencil(Stencil);
4387 checkGLcall("glClearStencil");
4388 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4389 glStencilMask(0xFFFFFFFF);
4392 if (Flags & WINED3DCLEAR_ZBUFFER) {
4393 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4394 glDepthMask(GL_TRUE);
4396 checkGLcall("glClearDepth");
4397 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4398 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4400 if (!(depth_stencil->Flags & location) && !is_full_clear(depth_stencil, vp, scissor_rect, clear_rect))
4401 surface_load_ds_location(This->stencilBufferTarget, context, location);
4404 if (Flags & WINED3DCLEAR_TARGET) {
4405 TRACE("Clearing screen with glClear to color %x\n", Color);
4406 glClearColor(D3DCOLOR_R(Color),
4410 checkGLcall("glClearColor");
4412 /* Clear ALL colors! */
4413 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4414 glMask = glMask | GL_COLOR_BUFFER_BIT;
4417 vp_rect.left = vp->X;
4418 vp_rect.top = vp->Y;
4419 vp_rect.right = vp->X + vp->Width;
4420 vp_rect.bottom = vp->Y + vp->Height;
4421 if (!(Count > 0 && pRects)) {
4422 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4423 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4425 if (context->render_offscreen)
4427 glScissor(vp_rect.left, vp_rect.top,
4428 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4430 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4431 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4433 checkGLcall("glScissor");
4435 checkGLcall("glClear");
4437 /* Now process each rect in turn */
4438 for (i = 0; i < Count; i++) {
4439 /* Note gl uses lower left, width/height */
4440 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4441 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4442 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4444 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4445 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4446 curRect.x1, (target->currentDesc.Height - curRect.y2),
4447 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4449 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4450 * The rectangle is not cleared, no error is returned, but further rectanlges are
4451 * still cleared if they are valid
4453 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4454 TRACE("Rectangle with negative dimensions, ignoring\n");
4458 if (context->render_offscreen)
4460 glScissor(curRect.x1, curRect.y1,
4461 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4463 glScissor(curRect.x1, drawable_height - curRect.y2,
4464 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4466 checkGLcall("glScissor");
4469 checkGLcall("glClear");
4473 /* Restore the old values (why..?) */
4474 if (Flags & WINED3DCLEAR_STENCIL) {
4475 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4477 if (Flags & WINED3DCLEAR_TARGET) {
4478 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4479 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4480 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4481 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4482 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4484 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4485 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4487 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4489 if (Flags & WINED3DCLEAR_ZBUFFER) {
4490 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4491 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4492 surface_modify_ds_location(This->stencilBufferTarget, location);
4497 wglFlush(); /* Flush to ensure ordering across contexts. */
4499 context_release(context);
4504 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4505 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4507 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4509 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4510 Count, pRects, Flags, Color, Z, Stencil);
4512 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4513 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4514 /* TODO: What about depth stencil buffers without stencil bits? */
4515 return WINED3DERR_INVALIDCALL;
4518 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4525 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4526 WINED3DPRIMITIVETYPE primitive_type)
4528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4530 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4532 This->updateStateBlock->changed.primitive_type = TRUE;
4533 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4536 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4537 WINED3DPRIMITIVETYPE *primitive_type)
4539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4541 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4543 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4545 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4548 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4552 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4554 if(!This->stateBlock->vertexDecl) {
4555 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4556 return WINED3DERR_INVALIDCALL;
4559 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4560 if(This->stateBlock->streamIsUP) {
4561 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4562 This->stateBlock->streamIsUP = FALSE;
4565 if(This->stateBlock->loadBaseVertexIndex != 0) {
4566 This->stateBlock->loadBaseVertexIndex = 0;
4567 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4569 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4570 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4574 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4578 IWineD3DBuffer *pIB;
4581 pIB = This->stateBlock->pIndexData;
4583 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4584 * without an index buffer set. (The first time at least...)
4585 * D3D8 simply dies, but I doubt it can do much harm to return
4586 * D3DERR_INVALIDCALL there as well. */
4587 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4588 return WINED3DERR_INVALIDCALL;
4591 if(!This->stateBlock->vertexDecl) {
4592 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4593 return WINED3DERR_INVALIDCALL;
4596 if(This->stateBlock->streamIsUP) {
4597 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4598 This->stateBlock->streamIsUP = FALSE;
4600 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4602 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4604 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4610 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4611 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4612 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4615 drawPrimitive(iface, index_count, startIndex, idxStride,
4616 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4621 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4622 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4627 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4628 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4630 if(!This->stateBlock->vertexDecl) {
4631 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4632 return WINED3DERR_INVALIDCALL;
4635 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4636 vb = This->stateBlock->streamSource[0];
4637 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4638 if (vb) IWineD3DBuffer_Release(vb);
4639 This->stateBlock->streamOffset[0] = 0;
4640 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4641 This->stateBlock->streamIsUP = TRUE;
4642 This->stateBlock->loadBaseVertexIndex = 0;
4644 /* TODO: Only mark dirty if drawing from a different UP address */
4645 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4647 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4649 /* MSDN specifies stream zero settings must be set to NULL */
4650 This->stateBlock->streamStride[0] = 0;
4651 This->stateBlock->streamSource[0] = NULL;
4653 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4654 * the new stream sources or use UP drawing again
4659 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4660 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4661 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4668 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4669 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4671 if(!This->stateBlock->vertexDecl) {
4672 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4673 return WINED3DERR_INVALIDCALL;
4676 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4682 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4683 vb = This->stateBlock->streamSource[0];
4684 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4685 if (vb) IWineD3DBuffer_Release(vb);
4686 This->stateBlock->streamIsUP = TRUE;
4687 This->stateBlock->streamOffset[0] = 0;
4688 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4690 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4691 This->stateBlock->baseVertexIndex = 0;
4692 This->stateBlock->loadBaseVertexIndex = 0;
4693 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4694 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4695 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4697 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4699 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4700 This->stateBlock->streamSource[0] = NULL;
4701 This->stateBlock->streamStride[0] = 0;
4702 ib = This->stateBlock->pIndexData;
4704 IWineD3DBuffer_Release(ib);
4705 This->stateBlock->pIndexData = NULL;
4707 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4708 * SetStreamSource to specify a vertex buffer
4714 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4715 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4719 /* Mark the state dirty until we have nicer tracking
4720 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4723 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4724 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4725 This->stateBlock->baseVertexIndex = 0;
4726 This->up_strided = DrawPrimStrideData;
4727 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4728 This->up_strided = NULL;
4732 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4733 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4734 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4737 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4739 /* Mark the state dirty until we have nicer tracking
4740 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4743 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4744 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4745 This->stateBlock->streamIsUP = TRUE;
4746 This->stateBlock->baseVertexIndex = 0;
4747 This->up_strided = DrawPrimStrideData;
4748 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4749 This->up_strided = NULL;
4753 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4754 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4755 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4757 WINED3DLOCKED_BOX src;
4758 WINED3DLOCKED_BOX dst;
4761 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4762 iface, pSourceVolume, pDestinationVolume);
4764 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4765 * dirtification to improve loading performance.
4767 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4768 if(FAILED(hr)) return hr;
4769 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4771 IWineD3DVolume_UnlockBox(pSourceVolume);
4775 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4777 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4779 IWineD3DVolume_UnlockBox(pSourceVolume);
4781 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4786 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4787 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4789 unsigned int level_count, i;
4790 WINED3DRESOURCETYPE type;
4793 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4795 /* Verify that the source and destination textures are non-NULL. */
4796 if (!src_texture || !dst_texture)
4798 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4799 return WINED3DERR_INVALIDCALL;
4802 if (src_texture == dst_texture)
4804 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4805 return WINED3DERR_INVALIDCALL;
4808 /* Verify that the source and destination textures are the same type. */
4809 type = IWineD3DBaseTexture_GetType(src_texture);
4810 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4812 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4813 return WINED3DERR_INVALIDCALL;
4816 /* Check that both textures have the identical numbers of levels. */
4817 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4818 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4820 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4821 return WINED3DERR_INVALIDCALL;
4824 /* Make sure that the destination texture is loaded. */
4825 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4827 /* Update every surface level of the texture. */
4830 case WINED3DRTYPE_TEXTURE:
4832 IWineD3DSurface *src_surface;
4833 IWineD3DSurface *dst_surface;
4835 for (i = 0; i < level_count; ++i)
4837 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4838 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4839 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4840 IWineD3DSurface_Release(dst_surface);
4841 IWineD3DSurface_Release(src_surface);
4844 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4851 case WINED3DRTYPE_CUBETEXTURE:
4853 IWineD3DSurface *src_surface;
4854 IWineD3DSurface *dst_surface;
4855 WINED3DCUBEMAP_FACES face;
4857 for (i = 0; i < level_count; ++i)
4859 /* Update each cube face. */
4860 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4862 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4863 face, i, &src_surface);
4864 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4865 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4866 face, i, &dst_surface);
4867 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4868 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4869 IWineD3DSurface_Release(dst_surface);
4870 IWineD3DSurface_Release(src_surface);
4873 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4881 case WINED3DRTYPE_VOLUMETEXTURE:
4883 IWineD3DVolume *src_volume;
4884 IWineD3DVolume *dst_volume;
4886 for (i = 0; i < level_count; ++i)
4888 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4889 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4890 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4891 IWineD3DVolume_Release(dst_volume);
4892 IWineD3DVolume_Release(src_volume);
4895 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4903 FIXME("Unsupported texture type %#x.\n", type);
4904 return WINED3DERR_INVALIDCALL;
4910 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4911 IWineD3DSwapChain *swapChain;
4913 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4914 if(hr == WINED3D_OK) {
4915 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4916 IWineD3DSwapChain_Release(swapChain);
4921 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4923 IWineD3DBaseTextureImpl *texture;
4926 TRACE("(%p) : %p\n", This, pNumPasses);
4928 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4929 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
4930 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4931 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4933 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
4934 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4935 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4938 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
4939 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
4941 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
4942 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4945 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
4946 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4949 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
4950 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
4951 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4956 /* return a sensible default */
4959 TRACE("returning D3D_OK\n");
4963 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
4967 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4969 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
4970 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
4971 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
4973 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
4978 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4982 PALETTEENTRY **palettes;
4984 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4986 if (PaletteNumber >= MAX_PALETTES) {
4987 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4988 return WINED3DERR_INVALIDCALL;
4991 if (PaletteNumber >= This->NumberOfPalettes) {
4992 NewSize = This->NumberOfPalettes;
4995 } while(PaletteNumber >= NewSize);
4996 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
4998 ERR("Out of memory!\n");
4999 return E_OUTOFMEMORY;
5001 This->palettes = palettes;
5002 This->NumberOfPalettes = NewSize;
5005 if (!This->palettes[PaletteNumber]) {
5006 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5007 if (!This->palettes[PaletteNumber]) {
5008 ERR("Out of memory!\n");
5009 return E_OUTOFMEMORY;
5013 for (j = 0; j < 256; ++j) {
5014 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5015 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5016 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5017 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5019 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5020 TRACE("(%p) : returning\n", This);
5024 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5027 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5028 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5029 /* What happens in such situation isn't documented; Native seems to silently abort
5030 on such conditions. Return Invalid Call. */
5031 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5032 return WINED3DERR_INVALIDCALL;
5034 for (j = 0; j < 256; ++j) {
5035 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5036 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5037 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5038 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5040 TRACE("(%p) : returning\n", This);
5044 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5046 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5047 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5048 (tested with reference rasterizer). Return Invalid Call. */
5049 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5050 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5051 return WINED3DERR_INVALIDCALL;
5053 /*TODO: stateblocks */
5054 if (This->currentPalette != PaletteNumber) {
5055 This->currentPalette = PaletteNumber;
5056 dirtify_p8_texture_samplers(This);
5058 TRACE("(%p) : returning\n", This);
5062 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5064 if (PaletteNumber == NULL) {
5065 WARN("(%p) : returning Invalid Call\n", This);
5066 return WINED3DERR_INVALIDCALL;
5068 /*TODO: stateblocks */
5069 *PaletteNumber = This->currentPalette;
5070 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5074 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5079 FIXME("(%p) : stub\n", This);
5083 This->softwareVertexProcessing = bSoftware;
5088 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5093 FIXME("(%p) : stub\n", This);
5096 return This->softwareVertexProcessing;
5099 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5100 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5102 IWineD3DSwapChain *swapchain;
5105 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5106 iface, swapchain_idx, raster_status);
5108 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5111 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5115 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5116 IWineD3DSwapChain_Release(swapchain);
5119 WARN("Failed to get raster status, hr %#x.\n", hr);
5126 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5129 if(nSegments != 0.0f) {
5132 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5139 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5144 FIXME("iface %p stub!\n", iface);
5150 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5151 const struct wined3d_format_desc *src_format_desc, *dst_format_desc;
5152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5153 /** TODO: remove casts to IWineD3DSurfaceImpl
5154 * NOTE: move code to surface to accomplish this
5155 ****************************************/
5156 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5157 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5158 int srcWidth, srcHeight;
5159 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5160 WINED3DFORMAT destFormat, srcFormat;
5162 int srcLeft, destLeft, destTop;
5163 WINED3DPOOL srcPool, destPool;
5165 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5169 CONVERT_TYPES convert = NO_CONVERSION;
5170 struct wined3d_context *context;
5172 WINED3DSURFACE_DESC winedesc;
5174 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5176 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5177 srcSurfaceWidth = winedesc.width;
5178 srcSurfaceHeight = winedesc.height;
5179 srcPool = winedesc.pool;
5180 srcFormat = winedesc.format;
5182 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5183 destSurfaceWidth = winedesc.width;
5184 destSurfaceHeight = winedesc.height;
5185 destPool = winedesc.pool;
5186 destFormat = winedesc.format;
5187 destSize = winedesc.size;
5189 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5190 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5191 return WINED3DERR_INVALIDCALL;
5194 /* This call loads the opengl surface directly, instead of copying the surface to the
5195 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5196 * copy in sysmem and use regular surface loading.
5198 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5199 if(convert != NO_CONVERSION) {
5200 return IWineD3DSurface_BltFast(pDestinationSurface,
5201 pDestPoint ? pDestPoint->x : 0,
5202 pDestPoint ? pDestPoint->y : 0,
5203 pSourceSurface, pSourceRect, 0);
5206 if (destFormat == WINED3DFMT_UNKNOWN) {
5207 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5208 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5210 /* Get the update surface description */
5211 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5214 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5217 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5218 checkGLcall("glActiveTextureARB");
5221 /* Make sure the surface is loaded and up to date */
5222 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5223 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5225 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5226 dst_format_desc = dst_impl->resource.format_desc;
5228 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5229 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5230 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5231 srcLeft = pSourceRect ? pSourceRect->left : 0;
5232 destLeft = pDestPoint ? pDestPoint->x : 0;
5233 destTop = pDestPoint ? pDestPoint->y : 0;
5236 /* This function doesn't support compressed textures
5237 the pitch is just bytesPerPixel * width */
5238 if(srcWidth != srcSurfaceWidth || srcLeft ){
5239 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5240 offset += srcLeft * src_format_desc->byte_count;
5241 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5243 /* TODO DXT formats */
5245 if(pSourceRect != NULL && pSourceRect->top != 0){
5246 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5248 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5249 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5250 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5253 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5255 /* need to lock the surface to get the data */
5256 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5261 /* TODO: Cube and volume support */
5263 /* not a whole row so we have to do it a line at a time */
5266 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5267 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5269 for (j = destTop; j < (srcHeight + destTop); ++j)
5271 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5272 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5276 } else { /* Full width, so just write out the whole texture */
5277 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5279 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5281 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5283 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5284 FIXME("Updating part of a compressed texture is not supported.\n");
5286 if (destFormat != srcFormat)
5288 FIXME("Updating mixed format compressed textures is not supported.\n");
5292 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5293 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5298 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5299 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5302 checkGLcall("glTexSubImage2D");
5305 context_release(context);
5307 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5308 sampler = This->rev_tex_unit_map[0];
5309 if (sampler != WINED3D_UNMAPPED_STAGE)
5311 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5317 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5319 struct WineD3DRectPatch *patch;
5320 GLenum old_primitive_type;
5324 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5326 if(!(Handle || pRectPatchInfo)) {
5327 /* TODO: Write a test for the return value, thus the FIXME */
5328 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5329 return WINED3DERR_INVALIDCALL;
5333 i = PATCHMAP_HASHFUNC(Handle);
5335 LIST_FOR_EACH(e, &This->patches[i]) {
5336 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5337 if(patch->Handle == Handle) {
5344 TRACE("Patch does not exist. Creating a new one\n");
5345 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5346 patch->Handle = Handle;
5347 list_add_head(&This->patches[i], &patch->entry);
5349 TRACE("Found existing patch %p\n", patch);
5352 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5353 * attributes we have to tesselate, read back, and draw. This needs a patch
5354 * management structure instance. Create one.
5356 * A possible improvement is to check if a vertex shader is used, and if not directly
5359 FIXME("Drawing an uncached patch. This is slow\n");
5360 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5363 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5364 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5365 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5367 TRACE("Tesselation density or patch info changed, retesselating\n");
5369 if(pRectPatchInfo) {
5370 patch->RectPatchInfo = *pRectPatchInfo;
5372 patch->numSegs[0] = pNumSegs[0];
5373 patch->numSegs[1] = pNumSegs[1];
5374 patch->numSegs[2] = pNumSegs[2];
5375 patch->numSegs[3] = pNumSegs[3];
5377 hr = tesselate_rectpatch(This, patch);
5379 WARN("Patch tesselation failed\n");
5381 /* Do not release the handle to store the params of the patch */
5383 HeapFree(GetProcessHeap(), 0, patch);
5389 This->currentPatch = patch;
5390 old_primitive_type = This->stateBlock->gl_primitive_type;
5391 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5392 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5393 This->stateBlock->gl_primitive_type = old_primitive_type;
5394 This->currentPatch = NULL;
5396 /* Destroy uncached patches */
5398 HeapFree(GetProcessHeap(), 0, patch->mem);
5399 HeapFree(GetProcessHeap(), 0, patch);
5404 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5405 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5407 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5408 iface, handle, segment_count, patch_info);
5413 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5414 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5416 struct WineD3DRectPatch *patch;
5418 TRACE("(%p) Handle(%d)\n", This, Handle);
5420 i = PATCHMAP_HASHFUNC(Handle);
5421 LIST_FOR_EACH(e, &This->patches[i]) {
5422 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5423 if(patch->Handle == Handle) {
5424 TRACE("Deleting patch %p\n", patch);
5425 list_remove(&patch->entry);
5426 HeapFree(GetProcessHeap(), 0, patch->mem);
5427 HeapFree(GetProcessHeap(), 0, patch);
5432 /* TODO: Write a test for the return value */
5433 FIXME("Attempt to destroy nonexistent patch\n");
5434 return WINED3DERR_INVALIDCALL;
5437 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5438 const WINED3DRECT *rect, const float color[4])
5440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5441 struct wined3d_context *context;
5443 if (rect) IWineD3DSurface_LoadLocation(surface, SFLAG_INDRAWABLE, NULL);
5444 IWineD3DSurface_ModifyLocation(surface, SFLAG_INDRAWABLE, TRUE);
5446 if (!surface_is_offscreen(surface))
5448 TRACE("Surface %p is onscreen\n", surface);
5450 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5452 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5453 context_set_draw_buffer(context, surface_get_gl_buffer(surface));
5457 TRACE("Surface %p is offscreen\n", surface);
5459 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5461 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5462 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5463 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5467 glEnable(GL_SCISSOR_TEST);
5468 if(surface_is_offscreen(surface)) {
5469 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5471 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5472 rect->x2 - rect->x1, rect->y2 - rect->y1);
5474 checkGLcall("glScissor");
5475 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5477 glDisable(GL_SCISSOR_TEST);
5479 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5481 glDisable(GL_BLEND);
5482 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5484 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5485 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5487 glClearColor(color[0], color[1], color[2], color[3]);
5488 glClear(GL_COLOR_BUFFER_BIT);
5489 checkGLcall("glClear");
5493 wglFlush(); /* Flush to ensure ordering across contexts. */
5495 context_release(context);
5498 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5499 unsigned int r, g, b, a;
5502 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5503 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5504 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5507 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5509 a = (color & 0xff000000) >> 24;
5510 r = (color & 0x00ff0000) >> 16;
5511 g = (color & 0x0000ff00) >> 8;
5512 b = (color & 0x000000ff) >> 0;
5516 case WINED3DFMT_B5G6R5_UNORM:
5517 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5524 TRACE("Returning %08x\n", ret);
5527 case WINED3DFMT_B5G5R5X1_UNORM:
5528 case WINED3DFMT_B5G5R5A1_UNORM:
5537 TRACE("Returning %08x\n", ret);
5540 case WINED3DFMT_A8_UNORM:
5541 TRACE("Returning %08x\n", a);
5544 case WINED3DFMT_B4G4R4X4_UNORM:
5545 case WINED3DFMT_B4G4R4A4_UNORM:
5554 TRACE("Returning %08x\n", ret);
5557 case WINED3DFMT_B2G3R3_UNORM:
5564 TRACE("Returning %08x\n", ret);
5567 case WINED3DFMT_R8G8B8X8_UNORM:
5568 case WINED3DFMT_R8G8B8A8_UNORM:
5573 TRACE("Returning %08x\n", ret);
5576 case WINED3DFMT_B10G10R10A2_UNORM:
5578 r = (r * 1024) / 256;
5579 g = (g * 1024) / 256;
5580 b = (b * 1024) / 256;
5585 TRACE("Returning %08x\n", ret);
5588 case WINED3DFMT_R10G10B10A2_UNORM:
5590 r = (r * 1024) / 256;
5591 g = (g * 1024) / 256;
5592 b = (b * 1024) / 256;
5597 TRACE("Returning %08x\n", ret);
5601 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5606 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5607 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5609 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5612 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5614 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5615 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5616 return WINED3DERR_INVALIDCALL;
5619 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5620 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5621 color_fill_fbo(iface, pSurface, pRect, c);
5624 /* Just forward this to the DirectDraw blitting engine */
5625 memset(&BltFx, 0, sizeof(BltFx));
5626 BltFx.dwSize = sizeof(BltFx);
5627 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5628 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5629 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5633 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5634 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5636 IWineD3DResource *resource;
5637 IWineD3DSurface *surface;
5640 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5643 ERR("Failed to get resource, hr %#x\n", hr);
5647 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5649 FIXME("Only supported on surface resources\n");
5650 IWineD3DResource_Release(resource);
5654 surface = (IWineD3DSurface *)resource;
5656 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5658 color_fill_fbo(iface, surface, NULL, color);
5665 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5667 c = ((DWORD)(color[2] * 255.0f));
5668 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5669 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5670 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5672 /* Just forward this to the DirectDraw blitting engine */
5673 memset(&BltFx, 0, sizeof(BltFx));
5674 BltFx.dwSize = sizeof(BltFx);
5675 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5676 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5679 ERR("Blt failed, hr %#x\n", hr);
5683 IWineD3DResource_Release(resource);
5686 /* rendertarget and depth stencil functions */
5687 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5690 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5692 ERR("(%p) : Only %d render targets are supported.\n",
5693 This, This->adapter->gl_info.limits.buffers);
5694 return WINED3DERR_INVALIDCALL;
5697 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5698 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5699 /* Note inc ref on returned surface */
5700 if(*ppRenderTarget != NULL)
5701 IWineD3DSurface_AddRef(*ppRenderTarget);
5705 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5706 IWineD3DSurface *front, IWineD3DSurface *back)
5708 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5709 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5710 IWineD3DSwapChainImpl *swapchain;
5713 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5715 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5717 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5721 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5723 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5724 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5725 return WINED3DERR_INVALIDCALL;
5730 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5732 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5733 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5734 return WINED3DERR_INVALIDCALL;
5737 if (!swapchain->backBuffer)
5739 swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->backBuffer));
5740 if (!swapchain->backBuffer)
5742 ERR("Failed to allocate back buffer array memory.\n");
5743 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5744 return E_OUTOFMEMORY;
5749 if (swapchain->frontBuffer != front)
5751 TRACE("Changing the front buffer from %p to %p.\n", swapchain->frontBuffer, front);
5753 if (swapchain->frontBuffer)
5755 IWineD3DSurface_SetContainer(swapchain->frontBuffer, NULL);
5756 ((IWineD3DSurfaceImpl *)swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5758 swapchain->frontBuffer = front;
5762 IWineD3DSurface_SetContainer(front, (IWineD3DBase *)swapchain);
5763 front_impl->Flags |= SFLAG_SWAPCHAIN;
5767 if (swapchain->backBuffer[0] != back)
5769 TRACE("Changing the back buffer from %p to %p.\n", swapchain->backBuffer[0], back);
5771 if (swapchain->backBuffer[0])
5773 IWineD3DSurface_SetContainer(swapchain->backBuffer[0], NULL);
5774 ((IWineD3DSurfaceImpl *)swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5776 swapchain->backBuffer[0] = back;
5780 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5781 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5782 swapchain->presentParms.BackBufferFormat = back_impl->resource.format_desc->format;
5783 swapchain->presentParms.BackBufferCount = 1;
5785 IWineD3DSurface_SetContainer(back, (IWineD3DBase *)swapchain);
5786 back_impl->Flags |= SFLAG_SWAPCHAIN;
5790 swapchain->presentParms.BackBufferCount = 0;
5791 HeapFree(GetProcessHeap(), 0, swapchain->backBuffer);
5792 swapchain->backBuffer = NULL;
5796 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5800 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5802 *ppZStencilSurface = This->stencilBufferTarget;
5803 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5805 if(*ppZStencilSurface != NULL) {
5806 /* Note inc ref on returned surface */
5807 IWineD3DSurface_AddRef(*ppZStencilSurface);
5810 return WINED3DERR_NOTFOUND;
5814 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5815 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
5817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5818 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5819 const struct wined3d_gl_info *gl_info;
5820 struct wined3d_context *context;
5822 POINT offset = {0, 0};
5824 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5825 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5826 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5827 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5830 case WINED3DTEXF_LINEAR:
5831 gl_filter = GL_LINEAR;
5835 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5836 case WINED3DTEXF_NONE:
5837 case WINED3DTEXF_POINT:
5838 gl_filter = GL_NEAREST;
5842 /* Make sure the drawables are up-to-date. Note that loading the
5843 * destination surface isn't strictly required if we overwrite the
5844 * entire surface. */
5845 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
5846 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
5848 if (!surface_is_offscreen(src_surface)) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
5849 else if (!surface_is_offscreen(dst_surface)) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5850 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5852 if (!context->valid)
5854 context_release(context);
5855 WARN("Invalid context, skipping blit.\n");
5859 gl_info = context->gl_info;
5861 if (!surface_is_offscreen(src_surface))
5863 GLenum buffer = surface_get_gl_buffer(src_surface);
5865 TRACE("Source surface %p is onscreen\n", src_surface);
5867 if(buffer == GL_FRONT) {
5870 ClientToScreen(context->win_handle, &offset);
5871 GetClientRect(context->win_handle, &windowsize);
5872 h = windowsize.bottom - windowsize.top;
5873 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
5874 src_rect->y1 = offset.y + h - src_rect->y1;
5875 src_rect->y2 = offset.y + h - src_rect->y2;
5877 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5878 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5882 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5883 glReadBuffer(buffer);
5884 checkGLcall("glReadBuffer()");
5886 TRACE("Source surface %p is offscreen\n", src_surface);
5888 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5889 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
5890 glReadBuffer(GL_COLOR_ATTACHMENT0);
5891 checkGLcall("glReadBuffer()");
5892 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5896 /* Attach dst surface to dst fbo */
5897 if (!surface_is_offscreen(dst_surface))
5899 GLenum buffer = surface_get_gl_buffer(dst_surface);
5901 TRACE("Destination surface %p is onscreen\n", dst_surface);
5903 if(buffer == GL_FRONT) {
5906 ClientToScreen(context->win_handle, &offset);
5907 GetClientRect(context->win_handle, &windowsize);
5908 h = windowsize.bottom - windowsize.top;
5909 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
5910 dst_rect->y1 = offset.y + h - dst_rect->y1;
5911 dst_rect->y2 = offset.y + h - dst_rect->y2;
5913 /* Screen coords = window coords, surface height = window height */
5914 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5915 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5919 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5920 context_set_draw_buffer(context, buffer);
5924 TRACE("Destination surface %p is offscreen\n", dst_surface);
5927 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5928 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
5929 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5930 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5932 glDisable(GL_SCISSOR_TEST);
5933 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5936 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5937 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
5938 checkGLcall("glBlitFramebuffer()");
5940 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5941 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
5942 checkGLcall("glBlitFramebuffer()");
5947 wglFlush(); /* Flush to ensure ordering across contexts. */
5949 context_release(context);
5951 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
5954 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5955 BOOL set_viewport) {
5956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5958 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5960 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5962 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5963 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5964 return WINED3DERR_INVALIDCALL;
5967 /* MSDN says that null disables the render target
5968 but a device must always be associated with a render target
5969 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5971 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5972 FIXME("Trying to set render target 0 to NULL\n");
5973 return WINED3DERR_INVALIDCALL;
5975 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5976 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);
5977 return WINED3DERR_INVALIDCALL;
5980 /* If we are trying to set what we already have, don't bother */
5981 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5982 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5985 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5986 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5987 This->render_targets[RenderTargetIndex] = pRenderTarget;
5989 /* Render target 0 is special */
5990 if(RenderTargetIndex == 0 && set_viewport) {
5991 /* Finally, reset the viewport and scissor rect as the MSDN states.
5992 * Tests show that stateblock recording is ignored, the change goes
5993 * directly into the primary stateblock.
5995 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5996 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5997 This->stateBlock->viewport.X = 0;
5998 This->stateBlock->viewport.Y = 0;
5999 This->stateBlock->viewport.MaxZ = 1.0f;
6000 This->stateBlock->viewport.MinZ = 0.0f;
6001 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6003 This->stateBlock->scissorRect.top = 0;
6004 This->stateBlock->scissorRect.left = 0;
6005 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
6006 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
6007 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6012 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6014 HRESULT hr = WINED3D_OK;
6015 IWineD3DSurface *tmp;
6017 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6019 if (pNewZStencil == This->stencilBufferTarget) {
6020 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6022 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6023 * depending on the renter target implementation being used.
6024 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6025 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6026 * stencil buffer and incur an extra memory overhead
6027 ******************************************************/
6029 if (This->stencilBufferTarget) {
6030 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6031 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6032 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6034 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6035 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
6036 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6037 context_release(context);
6041 tmp = This->stencilBufferTarget;
6042 This->stencilBufferTarget = pNewZStencil;
6043 /* should we be calling the parent or the wined3d surface? */
6044 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6045 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6048 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6049 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6050 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6051 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6052 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6059 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6060 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6062 /* TODO: the use of Impl is deprecated. */
6063 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6064 WINED3DLOCKED_RECT lockedRect;
6066 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6068 /* some basic validation checks */
6069 if(This->cursorTexture) {
6070 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6072 glDeleteTextures(1, &This->cursorTexture);
6074 context_release(context);
6075 This->cursorTexture = 0;
6078 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6079 This->haveHardwareCursor = TRUE;
6081 This->haveHardwareCursor = FALSE;
6084 WINED3DLOCKED_RECT rect;
6086 /* MSDN: Cursor must be A8R8G8B8 */
6087 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6089 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6090 return WINED3DERR_INVALIDCALL;
6093 /* MSDN: Cursor must be smaller than the display mode */
6094 if(pSur->currentDesc.Width > This->ddraw_width ||
6095 pSur->currentDesc.Height > This->ddraw_height) {
6096 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);
6097 return WINED3DERR_INVALIDCALL;
6100 if (!This->haveHardwareCursor) {
6101 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6103 /* Do not store the surface's pointer because the application may
6104 * release it after setting the cursor image. Windows doesn't
6105 * addref the set surface, so we can't do this either without
6106 * creating circular refcount dependencies. Copy out the gl texture
6109 This->cursorWidth = pSur->currentDesc.Width;
6110 This->cursorHeight = pSur->currentDesc.Height;
6111 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6113 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6114 const struct wined3d_format_desc *format_desc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6115 struct wined3d_context *context;
6116 char *mem, *bits = rect.pBits;
6117 GLint intfmt = format_desc->glInternal;
6118 GLint format = format_desc->glFormat;
6119 GLint type = format_desc->glType;
6120 INT height = This->cursorHeight;
6121 INT width = This->cursorWidth;
6122 INT bpp = format_desc->byte_count;
6126 /* Reformat the texture memory (pitch and width can be
6128 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6129 for(i = 0; i < height; i++)
6130 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6131 IWineD3DSurface_UnlockRect(pCursorBitmap);
6133 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6137 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6139 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6140 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6143 /* Make sure that a proper texture unit is selected */
6144 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6145 checkGLcall("glActiveTextureARB");
6146 sampler = This->rev_tex_unit_map[0];
6147 if (sampler != WINED3D_UNMAPPED_STAGE)
6149 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6151 /* Create a new cursor texture */
6152 glGenTextures(1, &This->cursorTexture);
6153 checkGLcall("glGenTextures");
6154 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6155 checkGLcall("glBindTexture");
6156 /* Copy the bitmap memory into the cursor texture */
6157 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6158 HeapFree(GetProcessHeap(), 0, mem);
6159 checkGLcall("glTexImage2D");
6161 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6163 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6164 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6169 context_release(context);
6173 FIXME("A cursor texture was not returned.\n");
6174 This->cursorTexture = 0;
6179 /* Draw a hardware cursor */
6180 ICONINFO cursorInfo;
6182 /* Create and clear maskBits because it is not needed for
6183 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6185 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6186 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6187 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6188 WINED3DLOCK_NO_DIRTY_UPDATE |
6189 WINED3DLOCK_READONLY
6191 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6192 pSur->currentDesc.Height);
6194 cursorInfo.fIcon = FALSE;
6195 cursorInfo.xHotspot = XHotSpot;
6196 cursorInfo.yHotspot = YHotSpot;
6197 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6199 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6200 1, 32, lockedRect.pBits);
6201 IWineD3DSurface_UnlockRect(pCursorBitmap);
6202 /* Create our cursor and clean up. */
6203 cursor = CreateIconIndirect(&cursorInfo);
6205 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6206 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6207 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6208 This->hardwareCursor = cursor;
6209 HeapFree(GetProcessHeap(), 0, maskBits);
6213 This->xHotSpot = XHotSpot;
6214 This->yHotSpot = YHotSpot;
6218 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6219 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6220 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6222 This->xScreenSpace = XScreenSpace;
6223 This->yScreenSpace = YScreenSpace;
6229 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6231 BOOL oldVisible = This->bCursorVisible;
6234 TRACE("(%p) : visible(%d)\n", This, bShow);
6237 * When ShowCursor is first called it should make the cursor appear at the OS's last
6238 * known cursor position. Because of this, some applications just repetitively call
6239 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6242 This->xScreenSpace = pt.x;
6243 This->yScreenSpace = pt.y;
6245 if (This->haveHardwareCursor) {
6246 This->bCursorVisible = bShow;
6248 SetCursor(This->hardwareCursor);
6254 if (This->cursorTexture)
6255 This->bCursorVisible = bShow;
6261 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6262 TRACE("checking resource %p for eviction\n", resource);
6263 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6264 TRACE("Evicting %p\n", resource);
6265 IWineD3DResource_UnLoad(resource);
6267 IWineD3DResource_Release(resource);
6271 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6273 TRACE("iface %p.\n", iface);
6275 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6279 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6281 IWineD3DDeviceImpl *device = surface->resource.device;
6282 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6284 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6285 if(surface->Flags & SFLAG_DIBSECTION) {
6286 /* Release the DC */
6287 SelectObject(surface->hDC, surface->dib.holdbitmap);
6288 DeleteDC(surface->hDC);
6289 /* Release the DIB section */
6290 DeleteObject(surface->dib.DIBsection);
6291 surface->dib.bitmap_data = NULL;
6292 surface->resource.allocatedMemory = NULL;
6293 surface->Flags &= ~SFLAG_DIBSECTION;
6295 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6296 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6297 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6298 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6300 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6301 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6303 surface->pow2Width = surface->pow2Height = 1;
6304 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6305 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6307 surface->glRect.left = 0;
6308 surface->glRect.top = 0;
6309 surface->glRect.right = surface->pow2Width;
6310 surface->glRect.bottom = surface->pow2Height;
6312 if (surface->texture_name)
6314 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6316 glDeleteTextures(1, &surface->texture_name);
6318 context_release(context);
6319 surface->texture_name = 0;
6320 surface->Flags &= ~SFLAG_CLIENT;
6322 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6323 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6324 surface->Flags |= SFLAG_NONPOW2;
6326 surface->Flags &= ~SFLAG_NONPOW2;
6328 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6329 surface->resource.allocatedMemory = NULL;
6330 surface->resource.heapMemory = NULL;
6331 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6333 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6335 if(!surface_init_sysmem((IWineD3DSurface *) surface))
6337 return E_OUTOFMEMORY;
6342 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6343 TRACE("Unloading resource %p\n", resource);
6344 IWineD3DResource_UnLoad(resource);
6345 IWineD3DResource_Release(resource);
6349 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6352 WINED3DDISPLAYMODE m;
6355 /* All Windowed modes are supported, as is leaving the current mode */
6356 if(pp->Windowed) return TRUE;
6357 if(!pp->BackBufferWidth) return TRUE;
6358 if(!pp->BackBufferHeight) return TRUE;
6360 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6361 for(i = 0; i < count; i++) {
6362 memset(&m, 0, sizeof(m));
6363 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6365 ERR("EnumAdapterModes failed\n");
6367 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6368 /* Mode found, it is supported */
6372 /* Mode not found -> not supported */
6376 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6378 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6379 const struct wined3d_gl_info *gl_info;
6380 struct wined3d_context *context;
6381 IWineD3DBaseShaderImpl *shader;
6383 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6384 gl_info = context->gl_info;
6386 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6387 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6388 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6392 if(This->depth_blt_texture) {
6393 glDeleteTextures(1, &This->depth_blt_texture);
6394 This->depth_blt_texture = 0;
6396 if (This->depth_blt_rb) {
6397 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6398 This->depth_blt_rb = 0;
6399 This->depth_blt_rb_w = 0;
6400 This->depth_blt_rb_h = 0;
6404 This->blitter->free_private(iface);
6405 This->frag_pipe->free_private(iface);
6406 This->shader_backend->shader_free_private(iface);
6407 destroy_dummy_textures(This, gl_info);
6409 context_release(context);
6411 while (This->numContexts)
6413 context_destroy(This, This->contexts[0]);
6415 HeapFree(GetProcessHeap(), 0, swapchain->context);
6416 swapchain->context = NULL;
6417 swapchain->num_contexts = 0;
6420 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6422 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6423 struct wined3d_context *context;
6425 IWineD3DSurfaceImpl *target;
6427 /* Recreate the primary swapchain's context */
6428 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6429 if (!swapchain->context)
6431 ERR("Failed to allocate memory for swapchain context array.\n");
6432 return E_OUTOFMEMORY;
6435 target = (IWineD3DSurfaceImpl *)(swapchain->backBuffer ? swapchain->backBuffer[0] : swapchain->frontBuffer);
6436 if (!(context = context_create(swapchain, target)))
6438 WARN("Failed to create context.\n");
6439 HeapFree(GetProcessHeap(), 0, swapchain->context);
6443 swapchain->context[0] = context;
6444 swapchain->num_contexts = 1;
6445 create_dummy_textures(This);
6446 context_release(context);
6448 hr = This->shader_backend->shader_alloc_private(iface);
6451 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6455 hr = This->frag_pipe->alloc_private(iface);
6458 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6459 This->shader_backend->shader_free_private(iface);
6463 hr = This->blitter->alloc_private(iface);
6466 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6467 This->frag_pipe->free_private(iface);
6468 This->shader_backend->shader_free_private(iface);
6475 context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6476 destroy_dummy_textures(This, context->gl_info);
6477 context_release(context);
6478 context_destroy(This, context);
6479 HeapFree(GetProcessHeap(), 0, swapchain->context);
6480 swapchain->num_contexts = 0;
6484 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6486 IWineD3DSwapChainImpl *swapchain;
6488 BOOL DisplayModeChanged = FALSE;
6489 WINED3DDISPLAYMODE mode;
6490 TRACE("(%p)\n", This);
6492 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6494 ERR("Failed to get the first implicit swapchain\n");
6498 if(!is_display_mode_supported(This, pPresentationParameters)) {
6499 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6500 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6501 pPresentationParameters->BackBufferHeight);
6502 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6503 return WINED3DERR_INVALIDCALL;
6506 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6507 * on an existing gl context, so there's no real need for recreation.
6509 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6511 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6513 TRACE("New params:\n");
6514 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6515 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6516 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6517 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6518 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6519 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6520 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6521 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6522 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6523 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6524 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6525 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6526 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6528 /* No special treatment of these parameters. Just store them */
6529 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6530 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6531 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6532 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6534 /* What to do about these? */
6535 if(pPresentationParameters->BackBufferCount != 0 &&
6536 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6537 ERR("Cannot change the back buffer count yet\n");
6539 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6540 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6541 ERR("Cannot change the back buffer format yet\n");
6543 if(pPresentationParameters->hDeviceWindow != NULL &&
6544 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6545 ERR("Cannot change the device window yet\n");
6547 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6550 TRACE("Creating the depth stencil buffer\n");
6552 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6554 pPresentationParameters->BackBufferWidth,
6555 pPresentationParameters->BackBufferHeight,
6556 pPresentationParameters->AutoDepthStencilFormat,
6557 pPresentationParameters->MultiSampleType,
6558 pPresentationParameters->MultiSampleQuality,
6560 &This->auto_depth_stencil_buffer);
6563 ERR("Failed to create the depth stencil buffer\n");
6564 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6565 return WINED3DERR_INVALIDCALL;
6569 /* Reset the depth stencil */
6570 if (pPresentationParameters->EnableAutoDepthStencil)
6571 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6573 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6575 TRACE("Resetting stateblock\n");
6576 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6577 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6579 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6581 if(pPresentationParameters->Windowed) {
6582 mode.Width = swapchain->orig_width;
6583 mode.Height = swapchain->orig_height;
6584 mode.RefreshRate = 0;
6585 mode.Format = swapchain->presentParms.BackBufferFormat;
6587 mode.Width = pPresentationParameters->BackBufferWidth;
6588 mode.Height = pPresentationParameters->BackBufferHeight;
6589 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6590 mode.Format = swapchain->presentParms.BackBufferFormat;
6593 /* Should Width == 800 && Height == 0 set 800x600? */
6594 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6595 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6596 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6600 if(!pPresentationParameters->Windowed) {
6601 DisplayModeChanged = TRUE;
6603 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6604 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6606 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6609 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6613 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6614 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6617 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6621 if(This->auto_depth_stencil_buffer) {
6622 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6625 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6631 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6632 || DisplayModeChanged)
6634 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6636 if (!pPresentationParameters->Windowed)
6638 if(swapchain->presentParms.Windowed) {
6639 /* switch from windowed to fs */
6640 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6641 pPresentationParameters->BackBufferHeight);
6643 /* Fullscreen -> fullscreen mode change */
6644 MoveWindow(swapchain->device_window, 0, 0,
6645 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6649 else if (!swapchain->presentParms.Windowed)
6651 /* Fullscreen -> windowed switch */
6652 swapchain_restore_fullscreen_window(swapchain);
6654 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6655 } else if(!pPresentationParameters->Windowed) {
6656 DWORD style = This->style, exStyle = This->exStyle;
6657 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6658 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6659 * Reset to clear up their mess. Guild Wars also loses the device during that.
6663 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6664 pPresentationParameters->BackBufferHeight);
6665 This->style = style;
6666 This->exStyle = exStyle;
6669 /* Note: No parent needed for initial internal stateblock */
6670 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6671 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6672 else TRACE("Created stateblock %p\n", This->stateBlock);
6673 This->updateStateBlock = This->stateBlock;
6674 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6676 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6678 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6681 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6684 GetClientRect(swapchain->win_handle, &client_rect);
6686 if(!swapchain->presentParms.BackBufferCount)
6688 TRACE("Single buffered rendering\n");
6689 swapchain->render_to_fbo = FALSE;
6691 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6692 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6694 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6695 swapchain->presentParms.BackBufferWidth,
6696 swapchain->presentParms.BackBufferHeight,
6697 client_rect.right, client_rect.bottom);
6698 swapchain->render_to_fbo = TRUE;
6702 TRACE("Rendering directly to GL_BACK\n");
6703 swapchain->render_to_fbo = FALSE;
6707 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6708 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6710 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6716 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6718 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6720 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6726 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6728 TRACE("(%p) : pParameters %p\n", This, pParameters);
6730 *pParameters = This->createParms;
6734 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6735 IWineD3DSwapChain *swapchain;
6737 TRACE("Relaying to swapchain\n");
6739 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6740 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6741 IWineD3DSwapChain_Release(swapchain);
6745 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6746 IWineD3DSwapChain *swapchain;
6748 TRACE("Relaying to swapchain\n");
6750 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6751 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6752 IWineD3DSwapChain_Release(swapchain);
6757 /** ********************************************************
6758 * Notification functions
6759 ** ********************************************************/
6760 /** This function must be called in the release of a resource when ref == 0,
6761 * the contents of resource must still be correct,
6762 * any handles to other resource held by the caller must be closed
6763 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6764 *****************************************************/
6765 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6767 TRACE("(%p) : Adding resource %p\n", This, resource);
6769 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6772 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6774 TRACE("(%p) : Removing resource %p\n", This, resource);
6776 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6779 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6781 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6784 TRACE("(%p) : resource %p\n", This, resource);
6786 context_resource_released((IWineD3DDevice *)This, resource, type);
6789 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6790 case WINED3DRTYPE_SURFACE: {
6793 if (This->d3d_initialized)
6795 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6797 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6798 This->render_targets[i] = NULL;
6801 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6802 This->stencilBufferTarget = NULL;
6808 case WINED3DRTYPE_TEXTURE:
6809 case WINED3DRTYPE_CUBETEXTURE:
6810 case WINED3DRTYPE_VOLUMETEXTURE:
6811 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6812 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6813 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6814 This->stateBlock->textures[counter] = NULL;
6816 if (This->updateStateBlock != This->stateBlock ){
6817 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6818 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6819 This->updateStateBlock->textures[counter] = NULL;
6824 case WINED3DRTYPE_VOLUME:
6825 /* TODO: nothing really? */
6827 case WINED3DRTYPE_BUFFER:
6830 TRACE("Cleaning up stream pointers\n");
6832 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6833 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6834 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6836 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6837 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6838 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6839 This->updateStateBlock->streamSource[streamNumber] = 0;
6840 /* Set changed flag? */
6843 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) */
6844 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6845 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6846 This->stateBlock->streamSource[streamNumber] = 0;
6851 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6852 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6853 This->updateStateBlock->pIndexData = NULL;
6856 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6857 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6858 This->stateBlock->pIndexData = NULL;
6865 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6870 /* Remove the resource from the resourceStore */
6871 device_resource_remove(This, resource);
6873 TRACE("Resource released\n");
6877 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6879 IWineD3DResourceImpl *resource, *cursor;
6881 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6883 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6884 TRACE("enumerating resource %p\n", resource);
6885 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6886 ret = pCallback((IWineD3DResource *) resource, pData);
6887 if(ret == S_FALSE) {
6888 TRACE("Canceling enumeration\n");
6895 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6898 IWineD3DResourceImpl *resource;
6900 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6902 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6903 if (type == WINED3DRTYPE_SURFACE)
6905 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6907 TRACE("Found surface %p for dc %p.\n", resource, dc);
6908 *surface = (IWineD3DSurface *)resource;
6914 return WINED3DERR_INVALIDCALL;
6917 /**********************************************************
6918 * IWineD3DDevice VTbl follows
6919 **********************************************************/
6921 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6923 /*** IUnknown methods ***/
6924 IWineD3DDeviceImpl_QueryInterface,
6925 IWineD3DDeviceImpl_AddRef,
6926 IWineD3DDeviceImpl_Release,
6927 /*** IWineD3DDevice methods ***/
6928 IWineD3DDeviceImpl_GetParent,
6929 /*** Creation methods**/
6930 IWineD3DDeviceImpl_CreateBuffer,
6931 IWineD3DDeviceImpl_CreateVertexBuffer,
6932 IWineD3DDeviceImpl_CreateIndexBuffer,
6933 IWineD3DDeviceImpl_CreateStateBlock,
6934 IWineD3DDeviceImpl_CreateSurface,
6935 IWineD3DDeviceImpl_CreateRendertargetView,
6936 IWineD3DDeviceImpl_CreateTexture,
6937 IWineD3DDeviceImpl_CreateVolumeTexture,
6938 IWineD3DDeviceImpl_CreateVolume,
6939 IWineD3DDeviceImpl_CreateCubeTexture,
6940 IWineD3DDeviceImpl_CreateQuery,
6941 IWineD3DDeviceImpl_CreateSwapChain,
6942 IWineD3DDeviceImpl_CreateVertexDeclaration,
6943 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6944 IWineD3DDeviceImpl_CreateVertexShader,
6945 IWineD3DDeviceImpl_CreateGeometryShader,
6946 IWineD3DDeviceImpl_CreatePixelShader,
6947 IWineD3DDeviceImpl_CreatePalette,
6948 /*** Odd functions **/
6949 IWineD3DDeviceImpl_Init3D,
6950 IWineD3DDeviceImpl_InitGDI,
6951 IWineD3DDeviceImpl_Uninit3D,
6952 IWineD3DDeviceImpl_UninitGDI,
6953 IWineD3DDeviceImpl_SetMultithreaded,
6954 IWineD3DDeviceImpl_EvictManagedResources,
6955 IWineD3DDeviceImpl_GetAvailableTextureMem,
6956 IWineD3DDeviceImpl_GetBackBuffer,
6957 IWineD3DDeviceImpl_GetCreationParameters,
6958 IWineD3DDeviceImpl_GetDeviceCaps,
6959 IWineD3DDeviceImpl_GetDirect3D,
6960 IWineD3DDeviceImpl_GetDisplayMode,
6961 IWineD3DDeviceImpl_SetDisplayMode,
6962 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6963 IWineD3DDeviceImpl_GetRasterStatus,
6964 IWineD3DDeviceImpl_GetSwapChain,
6965 IWineD3DDeviceImpl_Reset,
6966 IWineD3DDeviceImpl_SetDialogBoxMode,
6967 IWineD3DDeviceImpl_SetCursorProperties,
6968 IWineD3DDeviceImpl_SetCursorPosition,
6969 IWineD3DDeviceImpl_ShowCursor,
6970 /*** Getters and setters **/
6971 IWineD3DDeviceImpl_SetClipPlane,
6972 IWineD3DDeviceImpl_GetClipPlane,
6973 IWineD3DDeviceImpl_SetClipStatus,
6974 IWineD3DDeviceImpl_GetClipStatus,
6975 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6976 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6977 IWineD3DDeviceImpl_SetDepthStencilSurface,
6978 IWineD3DDeviceImpl_GetDepthStencilSurface,
6979 IWineD3DDeviceImpl_SetGammaRamp,
6980 IWineD3DDeviceImpl_GetGammaRamp,
6981 IWineD3DDeviceImpl_SetIndexBuffer,
6982 IWineD3DDeviceImpl_GetIndexBuffer,
6983 IWineD3DDeviceImpl_SetBaseVertexIndex,
6984 IWineD3DDeviceImpl_GetBaseVertexIndex,
6985 IWineD3DDeviceImpl_SetLight,
6986 IWineD3DDeviceImpl_GetLight,
6987 IWineD3DDeviceImpl_SetLightEnable,
6988 IWineD3DDeviceImpl_GetLightEnable,
6989 IWineD3DDeviceImpl_SetMaterial,
6990 IWineD3DDeviceImpl_GetMaterial,
6991 IWineD3DDeviceImpl_SetNPatchMode,
6992 IWineD3DDeviceImpl_GetNPatchMode,
6993 IWineD3DDeviceImpl_SetPaletteEntries,
6994 IWineD3DDeviceImpl_GetPaletteEntries,
6995 IWineD3DDeviceImpl_SetPixelShader,
6996 IWineD3DDeviceImpl_GetPixelShader,
6997 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6998 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6999 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7000 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7001 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7002 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7003 IWineD3DDeviceImpl_SetRenderState,
7004 IWineD3DDeviceImpl_GetRenderState,
7005 IWineD3DDeviceImpl_SetRenderTarget,
7006 IWineD3DDeviceImpl_GetRenderTarget,
7007 IWineD3DDeviceImpl_SetFrontBackBuffers,
7008 IWineD3DDeviceImpl_SetSamplerState,
7009 IWineD3DDeviceImpl_GetSamplerState,
7010 IWineD3DDeviceImpl_SetScissorRect,
7011 IWineD3DDeviceImpl_GetScissorRect,
7012 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7013 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7014 IWineD3DDeviceImpl_SetStreamSource,
7015 IWineD3DDeviceImpl_GetStreamSource,
7016 IWineD3DDeviceImpl_SetStreamSourceFreq,
7017 IWineD3DDeviceImpl_GetStreamSourceFreq,
7018 IWineD3DDeviceImpl_SetTexture,
7019 IWineD3DDeviceImpl_GetTexture,
7020 IWineD3DDeviceImpl_SetTextureStageState,
7021 IWineD3DDeviceImpl_GetTextureStageState,
7022 IWineD3DDeviceImpl_SetTransform,
7023 IWineD3DDeviceImpl_GetTransform,
7024 IWineD3DDeviceImpl_SetVertexDeclaration,
7025 IWineD3DDeviceImpl_GetVertexDeclaration,
7026 IWineD3DDeviceImpl_SetVertexShader,
7027 IWineD3DDeviceImpl_GetVertexShader,
7028 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7029 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7030 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7031 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7032 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7033 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7034 IWineD3DDeviceImpl_SetViewport,
7035 IWineD3DDeviceImpl_GetViewport,
7036 IWineD3DDeviceImpl_MultiplyTransform,
7037 IWineD3DDeviceImpl_ValidateDevice,
7038 IWineD3DDeviceImpl_ProcessVertices,
7039 /*** State block ***/
7040 IWineD3DDeviceImpl_BeginStateBlock,
7041 IWineD3DDeviceImpl_EndStateBlock,
7042 /*** Scene management ***/
7043 IWineD3DDeviceImpl_BeginScene,
7044 IWineD3DDeviceImpl_EndScene,
7045 IWineD3DDeviceImpl_Present,
7046 IWineD3DDeviceImpl_Clear,
7047 IWineD3DDeviceImpl_ClearRendertargetView,
7049 IWineD3DDeviceImpl_SetPrimitiveType,
7050 IWineD3DDeviceImpl_GetPrimitiveType,
7051 IWineD3DDeviceImpl_DrawPrimitive,
7052 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7053 IWineD3DDeviceImpl_DrawPrimitiveUP,
7054 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7055 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7056 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7057 IWineD3DDeviceImpl_DrawRectPatch,
7058 IWineD3DDeviceImpl_DrawTriPatch,
7059 IWineD3DDeviceImpl_DeletePatch,
7060 IWineD3DDeviceImpl_ColorFill,
7061 IWineD3DDeviceImpl_UpdateTexture,
7062 IWineD3DDeviceImpl_UpdateSurface,
7063 IWineD3DDeviceImpl_GetFrontBufferData,
7064 /*** object tracking ***/
7065 IWineD3DDeviceImpl_EnumResources,
7066 IWineD3DDeviceImpl_GetSurfaceFromDC,
7067 IWineD3DDeviceImpl_AcquireFocusWindow,
7068 IWineD3DDeviceImpl_ReleaseFocusWindow,
7071 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
7072 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
7073 IUnknown *parent, IWineD3DDeviceParent *device_parent)
7075 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
7076 const struct fragment_pipeline *fragment_pipeline;
7077 struct shader_caps shader_caps;
7078 struct fragment_caps ffp_caps;
7079 WINED3DDISPLAYMODE mode;
7083 device->lpVtbl = &IWineD3DDevice_Vtbl;
7085 device->wined3d = (IWineD3D *)wined3d;
7086 IWineD3D_AddRef(device->wined3d);
7087 device->adapter = wined3d->adapter_count ? adapter : NULL;
7088 device->parent = parent;
7089 device->device_parent = device_parent;
7090 list_init(&device->resources);
7091 list_init(&device->shaders);
7093 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7094 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
7096 /* Get the initial screen setup for ddraw. */
7097 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
7100 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7101 IWineD3D_Release(device->wined3d);
7104 device->ddraw_width = mode.Width;
7105 device->ddraw_height = mode.Height;
7106 device->ddraw_format = mode.Format;
7108 /* Save the creation parameters. */
7109 device->createParms.AdapterOrdinal = adapter_idx;
7110 device->createParms.DeviceType = device_type;
7111 device->createParms.hFocusWindow = focus_window;
7112 device->createParms.BehaviorFlags = flags;
7114 device->devType = device_type;
7115 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7117 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7118 device->shader_backend = adapter->shader_backend;
7120 memset(&shader_caps, 0, sizeof(shader_caps));
7121 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7122 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7123 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7124 device->vs_clipping = shader_caps.VSClipping;
7126 memset(&ffp_caps, 0, sizeof(ffp_caps));
7127 fragment_pipeline = adapter->fragment_pipe;
7128 device->frag_pipe = fragment_pipeline;
7129 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7130 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7132 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7133 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7136 ERR("Failed to compile state table, hr %#x.\n", hr);
7137 IWineD3D_Release(device->wined3d);
7141 device->blitter = adapter->blitter;
7147 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7148 DWORD rep = This->StateTable[state].representative;
7149 struct wined3d_context *context;
7154 for(i = 0; i < This->numContexts; i++) {
7155 context = This->contexts[i];
7156 if(isStateDirty(context, rep)) continue;
7158 context->dirtyArray[context->numDirtyEntries++] = rep;
7159 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7160 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7161 context->isStateDirty[idx] |= (1 << shift);
7165 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7167 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7168 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7169 *width = surface->pow2Width;
7170 *height = surface->pow2Height;
7173 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7175 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7176 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7177 * current context's drawable, which is the size of the back buffer of the swapchain
7178 * the active context belongs to. */
7179 *width = swapchain->presentParms.BackBufferWidth;
7180 *height = swapchain->presentParms.BackBufferHeight;
7183 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7184 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7186 if (device->filter_messages)
7188 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7189 window, message, wparam, lparam);
7190 return DefWindowProcW(window, message, wparam, lparam);
7193 if (message == WM_DESTROY)
7195 TRACE("unregister window %p.\n", window);
7196 wined3d_unregister_window(window);
7198 if (device->focus_window == window) device->focus_window = NULL;
7199 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7202 return CallWindowProcW(proc, window, message, wparam, lparam);