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 GlPixelFormatDesc *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 GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1222 elements[idx].input_slot = 0;
1223 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1224 elements[idx].offset = offset;
1225 offset += format_desc->component_count * format_desc->component_size;
1228 *ppVertexElements = elements;
1232 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1233 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1234 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1237 WINED3DVERTEXELEMENT *elements;
1241 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1243 size = ConvertFvfToDeclaration(This, fvf, &elements);
1244 if (size == ~0U) return E_OUTOFMEMORY;
1246 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1247 HeapFree(GetProcessHeap(), 0, elements);
1251 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1252 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1253 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1254 const struct wined3d_parent_ops *parent_ops)
1256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1257 IWineD3DVertexShaderImpl *object;
1260 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1263 ERR("Failed to allocate shader memory.\n");
1264 return E_OUTOFMEMORY;
1267 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1270 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1271 HeapFree(GetProcessHeap(), 0, object);
1275 TRACE("Created vertex shader %p.\n", object);
1276 *ppVertexShader = (IWineD3DVertexShader *)object;
1281 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1282 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1283 IWineD3DGeometryShader **shader, IUnknown *parent,
1284 const struct wined3d_parent_ops *parent_ops)
1286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1287 struct wined3d_geometryshader *object;
1290 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1293 ERR("Failed to allocate shader memory.\n");
1294 return E_OUTOFMEMORY;
1297 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1300 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1301 HeapFree(GetProcessHeap(), 0, object);
1305 TRACE("Created geometry shader %p.\n", object);
1306 *shader = (IWineD3DGeometryShader *)object;
1311 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1312 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1313 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1314 const struct wined3d_parent_ops *parent_ops)
1316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1317 IWineD3DPixelShaderImpl *object;
1320 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1323 ERR("Failed to allocate shader memory.\n");
1324 return E_OUTOFMEMORY;
1327 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1330 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1331 HeapFree(GetProcessHeap(), 0, object);
1335 TRACE("Created pixel shader %p.\n", object);
1336 *ppPixelShader = (IWineD3DPixelShader *)object;
1341 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1342 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1345 IWineD3DPaletteImpl *object;
1347 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1349 /* Create the new object */
1350 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1352 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1353 return E_OUTOFMEMORY;
1356 object->lpVtbl = &IWineD3DPalette_Vtbl;
1358 object->Flags = Flags;
1359 object->parent = Parent;
1360 object->device = This;
1361 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1362 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1365 HeapFree( GetProcessHeap(), 0, object);
1366 return E_OUTOFMEMORY;
1369 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1371 IWineD3DPalette_Release((IWineD3DPalette *) object);
1375 *Palette = (IWineD3DPalette *) object;
1380 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1384 HDC dcb = NULL, dcs = NULL;
1385 WINEDDCOLORKEY colorkey;
1387 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1390 GetObjectA(hbm, sizeof(BITMAP), &bm);
1391 dcb = CreateCompatibleDC(NULL);
1393 SelectObject(dcb, hbm);
1397 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1398 * couldn't be loaded
1400 memset(&bm, 0, sizeof(bm));
1405 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1406 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1407 NULL, &wined3d_null_parent_ops);
1409 ERR("Wine logo requested, but failed to create surface\n");
1414 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1415 if(FAILED(hr)) goto out;
1416 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1417 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1419 colorkey.dwColorSpaceLowValue = 0;
1420 colorkey.dwColorSpaceHighValue = 0;
1421 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1423 /* Fill the surface with a white color to show that wined3d is there */
1424 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1428 if (dcb) DeleteDC(dcb);
1429 if (hbm) DeleteObject(hbm);
1432 /* Context activation is done by the caller. */
1433 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1435 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1437 /* Under DirectX you can have texture stage operations even if no texture is
1438 bound, whereas opengl will only do texture operations when a valid texture is
1439 bound. We emulate this by creating dummy textures and binding them to each
1440 texture stage, but disable all stages by default. Hence if a stage is enabled
1441 then the default texture will kick in until replaced by a SetTexture call */
1444 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1446 /* The dummy texture does not have client storage backing */
1447 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1448 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1451 for (i = 0; i < gl_info->limits.textures; ++i)
1453 GLubyte white = 255;
1455 /* Make appropriate texture active */
1456 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1457 checkGLcall("glActiveTextureARB");
1459 /* Generate an opengl texture name */
1460 glGenTextures(1, &This->dummyTextureName[i]);
1461 checkGLcall("glGenTextures");
1462 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1464 /* Generate a dummy 2d texture (not using 1d because they cause many
1465 * DRI drivers fall back to sw) */
1466 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1467 checkGLcall("glBindTexture");
1469 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1470 checkGLcall("glTexImage2D");
1473 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1475 /* Reenable because if supported it is enabled by default */
1476 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1477 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1483 /* Context activation is done by the caller. */
1484 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1487 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1488 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1491 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1494 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1495 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1498 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1499 IWineD3DSwapChainImpl *swapchain = NULL;
1500 struct wined3d_context *context;
1505 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1507 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1508 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1510 if (!pPresentationParameters->Windowed)
1512 This->focus_window = This->createParms.hFocusWindow;
1513 if (!This->focus_window) This->focus_window = pPresentationParameters->hDeviceWindow;
1514 if (!wined3d_register_window(This->focus_window, This))
1516 ERR("Failed to register window %p.\n", This->focus_window);
1521 TRACE("(%p) : Creating stateblock\n", This);
1522 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1523 hr = IWineD3DDevice_CreateStateBlock(iface,
1525 (IWineD3DStateBlock **)&This->stateBlock,
1527 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1528 WARN("Failed to create stateblock\n");
1531 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1532 This->updateStateBlock = This->stateBlock;
1533 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1535 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1536 sizeof(IWineD3DSurface *) * gl_info->limits.buffers);
1537 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1538 sizeof(GLenum) * gl_info->limits.buffers);
1540 This->NumberOfPalettes = 1;
1541 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1542 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1543 ERR("Out of memory!\n");
1547 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1548 if(!This->palettes[0]) {
1549 ERR("Out of memory!\n");
1553 for (i = 0; i < 256; ++i) {
1554 This->palettes[0][i].peRed = 0xFF;
1555 This->palettes[0][i].peGreen = 0xFF;
1556 This->palettes[0][i].peBlue = 0xFF;
1557 This->palettes[0][i].peFlags = 0xFF;
1559 This->currentPalette = 0;
1561 /* Initialize the texture unit mapping to a 1:1 mapping */
1562 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1564 if (state < gl_info->limits.fragment_samplers)
1566 This->texUnitMap[state] = state;
1567 This->rev_tex_unit_map[state] = state;
1569 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1570 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1574 if (This->focus_window) SetFocus(This->focus_window);
1576 /* Setup the implicit swapchain. This also initializes a context. */
1577 TRACE("Creating implicit swapchain\n");
1578 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1579 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1582 WARN("Failed to create implicit swapchain\n");
1586 This->NumberOfSwapChains = 1;
1587 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1588 if(!This->swapchains) {
1589 ERR("Out of memory!\n");
1592 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1594 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1595 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1596 This->render_targets[0] = swapchain->backBuffer[0];
1599 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1600 This->render_targets[0] = swapchain->frontBuffer;
1602 IWineD3DSurface_AddRef(This->render_targets[0]);
1604 /* Depth Stencil support */
1605 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
1606 if (NULL != This->stencilBufferTarget) {
1607 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1610 hr = This->shader_backend->shader_alloc_private(iface);
1612 TRACE("Shader private data couldn't be allocated\n");
1615 hr = This->frag_pipe->alloc_private(iface);
1617 TRACE("Fragment pipeline private data couldn't be allocated\n");
1620 hr = This->blitter->alloc_private(iface);
1622 TRACE("Blitter private data couldn't be allocated\n");
1626 /* Set up some starting GL setup */
1628 /* Setup all the devices defaults */
1629 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1631 context = context_acquire(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
1633 create_dummy_textures(This);
1637 /* Initialize the current view state */
1638 This->view_ident = 1;
1639 This->contexts[0]->last_was_rhw = 0;
1640 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1641 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1643 switch(wined3d_settings.offscreen_rendering_mode) {
1645 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1648 case ORM_BACKBUFFER:
1650 if (context_get_current()->aux_buffers > 0)
1652 TRACE("Using auxilliary buffer for offscreen rendering\n");
1653 This->offscreenBuffer = GL_AUX0;
1655 TRACE("Using back buffer for offscreen rendering\n");
1656 This->offscreenBuffer = GL_BACK;
1661 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1664 context_release(context);
1666 /* Clear the screen */
1667 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1668 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1671 This->d3d_initialized = TRUE;
1673 if(wined3d_settings.logo) {
1674 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1676 This->highest_dirty_ps_const = 0;
1677 This->highest_dirty_vs_const = 0;
1681 HeapFree(GetProcessHeap(), 0, This->render_targets);
1682 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1683 HeapFree(GetProcessHeap(), 0, This->swapchains);
1684 This->NumberOfSwapChains = 0;
1685 if(This->palettes) {
1686 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1687 HeapFree(GetProcessHeap(), 0, This->palettes);
1689 This->NumberOfPalettes = 0;
1691 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1693 if(This->stateBlock) {
1694 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1695 This->stateBlock = NULL;
1697 if (This->blit_priv) {
1698 This->blitter->free_private(iface);
1700 if (This->fragment_priv) {
1701 This->frag_pipe->free_private(iface);
1703 if (This->shader_priv) {
1704 This->shader_backend->shader_free_private(iface);
1706 if (This->focus_window) wined3d_unregister_window(This->focus_window);
1710 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1711 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1714 IWineD3DSwapChainImpl *swapchain = NULL;
1717 /* Setup the implicit swapchain */
1718 TRACE("Creating implicit swapchain\n");
1719 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1720 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1723 WARN("Failed to create implicit swapchain\n");
1727 This->NumberOfSwapChains = 1;
1728 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1729 if(!This->swapchains) {
1730 ERR("Out of memory!\n");
1733 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1737 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1741 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1743 IWineD3DResource_UnLoad(resource);
1744 IWineD3DResource_Release(resource);
1748 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1749 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1752 const struct wined3d_gl_info *gl_info;
1753 struct wined3d_context *context;
1756 TRACE("(%p)\n", This);
1758 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1760 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1761 * it was created. Thus make sure a context is active for the glDelete* calls
1763 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1764 gl_info = context->gl_info;
1766 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1768 /* Unload resources */
1769 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1771 TRACE("Deleting high order patches\n");
1772 for(i = 0; i < PATCHMAP_SIZE; i++) {
1773 struct list *e1, *e2;
1774 struct WineD3DRectPatch *patch;
1775 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1776 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1777 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1781 /* Delete the mouse cursor texture */
1782 if(This->cursorTexture) {
1784 glDeleteTextures(1, &This->cursorTexture);
1786 This->cursorTexture = 0;
1789 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1790 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1792 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1793 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1796 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1797 * private data, it might contain opengl pointers
1799 if(This->depth_blt_texture) {
1801 glDeleteTextures(1, &This->depth_blt_texture);
1803 This->depth_blt_texture = 0;
1805 if (This->depth_blt_rb) {
1807 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1809 This->depth_blt_rb = 0;
1810 This->depth_blt_rb_w = 0;
1811 This->depth_blt_rb_h = 0;
1814 /* Release the update stateblock */
1815 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1816 if(This->updateStateBlock != This->stateBlock)
1817 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1819 This->updateStateBlock = NULL;
1821 { /* because were not doing proper internal refcounts releasing the primary state block
1822 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1823 to set this->stateBlock = NULL; first */
1824 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1825 This->stateBlock = NULL;
1827 /* Release the stateblock */
1828 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1829 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1833 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1834 This->blitter->free_private(iface);
1835 This->frag_pipe->free_private(iface);
1836 This->shader_backend->shader_free_private(iface);
1838 /* Release the buffers (with sanity checks)*/
1839 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1840 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1841 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
1842 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
1844 This->stencilBufferTarget = NULL;
1846 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1847 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1848 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1850 TRACE("Setting rendertarget to NULL\n");
1851 This->render_targets[0] = NULL;
1853 if (This->auto_depth_stencil_buffer) {
1854 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
1856 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1858 This->auto_depth_stencil_buffer = NULL;
1861 context_release(context);
1863 for(i=0; i < This->NumberOfSwapChains; i++) {
1864 TRACE("Releasing the implicit swapchain %d\n", i);
1865 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1866 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1870 HeapFree(GetProcessHeap(), 0, This->swapchains);
1871 This->swapchains = NULL;
1872 This->NumberOfSwapChains = 0;
1874 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1875 HeapFree(GetProcessHeap(), 0, This->palettes);
1876 This->palettes = NULL;
1877 This->NumberOfPalettes = 0;
1879 HeapFree(GetProcessHeap(), 0, This->render_targets);
1880 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1881 This->render_targets = NULL;
1882 This->draw_buffers = NULL;
1884 This->d3d_initialized = FALSE;
1886 if (This->focus_window) wined3d_unregister_window(This->focus_window);
1891 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1895 for(i=0; i < This->NumberOfSwapChains; i++) {
1896 TRACE("Releasing the implicit swapchain %d\n", i);
1897 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1898 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1902 HeapFree(GetProcessHeap(), 0, This->swapchains);
1903 This->swapchains = NULL;
1904 This->NumberOfSwapChains = 0;
1908 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1909 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1910 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1912 * There is no way to deactivate thread safety once it is enabled.
1914 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1917 /*For now just store the flag(needed in case of ddraw) */
1918 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1921 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1922 const WINED3DDISPLAYMODE* pMode) {
1924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1926 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1929 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1931 /* Resize the screen even without a window:
1932 * The app could have unset it with SetCooperativeLevel, but not called
1933 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1934 * but we don't have any hwnd
1937 memset(&devmode, 0, sizeof(devmode));
1938 devmode.dmSize = sizeof(devmode);
1939 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1940 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1941 devmode.dmPelsWidth = pMode->Width;
1942 devmode.dmPelsHeight = pMode->Height;
1944 devmode.dmDisplayFrequency = pMode->RefreshRate;
1945 if (pMode->RefreshRate != 0) {
1946 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1949 /* Only change the mode if necessary */
1950 if( (This->ddraw_width == pMode->Width) &&
1951 (This->ddraw_height == pMode->Height) &&
1952 (This->ddraw_format == pMode->Format) &&
1953 (pMode->RefreshRate == 0) ) {
1957 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1958 if (ret != DISP_CHANGE_SUCCESSFUL) {
1959 if(devmode.dmDisplayFrequency != 0) {
1960 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1961 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1962 devmode.dmDisplayFrequency = 0;
1963 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1965 if(ret != DISP_CHANGE_SUCCESSFUL) {
1966 return WINED3DERR_NOTAVAILABLE;
1970 /* Store the new values */
1971 This->ddraw_width = pMode->Width;
1972 This->ddraw_height = pMode->Height;
1973 This->ddraw_format = pMode->Format;
1975 /* And finally clip mouse to our screen */
1976 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1977 ClipCursor(&clip_rc);
1982 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1984 *ppD3D = This->wined3d;
1985 TRACE("Returning %p.\n", *ppD3D);
1986 IWineD3D_AddRef(*ppD3D);
1990 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1993 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1994 (This->adapter->TextureRam/(1024*1024)),
1995 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
1996 /* return simulated texture memory left */
1997 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2001 * Get / Set Stream Source
2003 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2004 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2007 IWineD3DBuffer *oldSrc;
2009 if (StreamNumber >= MAX_STREAMS) {
2010 WARN("Stream out of range %d\n", StreamNumber);
2011 return WINED3DERR_INVALIDCALL;
2012 } else if(OffsetInBytes & 0x3) {
2013 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2014 return WINED3DERR_INVALIDCALL;
2017 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2018 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2020 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2022 if(oldSrc == pStreamData &&
2023 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2024 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2025 TRACE("Application is setting the old values over, nothing to do\n");
2029 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2031 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2032 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2035 /* Handle recording of state blocks */
2036 if (This->isRecordingState) {
2037 TRACE("Recording... not performing anything\n");
2038 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2039 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2043 if (pStreamData != NULL) {
2044 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2045 IWineD3DBuffer_AddRef(pStreamData);
2047 if (oldSrc != NULL) {
2048 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2049 IWineD3DBuffer_Release(oldSrc);
2052 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2057 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2058 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2062 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2063 This->stateBlock->streamSource[StreamNumber],
2064 This->stateBlock->streamOffset[StreamNumber],
2065 This->stateBlock->streamStride[StreamNumber]);
2067 if (StreamNumber >= MAX_STREAMS) {
2068 WARN("Stream out of range %d\n", StreamNumber);
2069 return WINED3DERR_INVALIDCALL;
2071 *pStream = This->stateBlock->streamSource[StreamNumber];
2072 *pStride = This->stateBlock->streamStride[StreamNumber];
2074 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2077 if (*pStream != NULL) {
2078 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2083 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2085 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2086 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2088 /* Verify input at least in d3d9 this is invalid*/
2089 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2090 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2091 return WINED3DERR_INVALIDCALL;
2093 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2094 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2095 return WINED3DERR_INVALIDCALL;
2098 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2099 return WINED3DERR_INVALIDCALL;
2102 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2103 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2105 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2106 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2108 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2109 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2110 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2116 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2119 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2120 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2122 TRACE("(%p) : returning %d\n", This, *Divider);
2128 * Get / Set & Multiply Transform
2130 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2133 /* Most of this routine, comments included copied from ddraw tree initially: */
2134 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2136 /* Handle recording of state blocks */
2137 if (This->isRecordingState) {
2138 TRACE("Recording... not performing anything\n");
2139 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2140 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2145 * If the new matrix is the same as the current one,
2146 * we cut off any further processing. this seems to be a reasonable
2147 * optimization because as was noticed, some apps (warcraft3 for example)
2148 * tend towards setting the same matrix repeatedly for some reason.
2150 * From here on we assume that the new matrix is different, wherever it matters.
2152 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2153 TRACE("The app is setting the same matrix over again\n");
2156 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2160 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2161 where ViewMat = Camera space, WorldMat = world space.
2163 In OpenGL, camera and world space is combined into GL_MODELVIEW
2164 matrix. The Projection matrix stay projection matrix.
2167 /* Capture the times we can just ignore the change for now */
2168 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2169 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2170 /* Handled by the state manager */
2173 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2177 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2179 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2180 *pMatrix = This->stateBlock->transforms[State];
2184 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2185 const WINED3DMATRIX *mat = NULL;
2188 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2189 * below means it will be recorded in a state block change, but it
2190 * works regardless where it is recorded.
2191 * If this is found to be wrong, change to StateBlock.
2193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2194 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2196 if (State <= HIGHEST_TRANSFORMSTATE)
2198 mat = &This->updateStateBlock->transforms[State];
2200 FIXME("Unhandled transform state!!\n");
2203 multiply_matrix(&temp, mat, pMatrix);
2205 /* Apply change via set transform - will reapply to eg. lights this way */
2206 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2212 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2213 you can reference any indexes you want as long as that number max are enabled at any
2214 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2215 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2216 but when recording, just build a chain pretty much of commands to be replayed. */
2218 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2220 struct wined3d_light_info *object = NULL;
2221 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2225 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2227 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2231 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2232 return WINED3DERR_INVALIDCALL;
2235 switch(pLight->Type) {
2236 case WINED3DLIGHT_POINT:
2237 case WINED3DLIGHT_SPOT:
2238 case WINED3DLIGHT_PARALLELPOINT:
2239 case WINED3DLIGHT_GLSPOT:
2240 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2243 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2245 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2246 return WINED3DERR_INVALIDCALL;
2250 case WINED3DLIGHT_DIRECTIONAL:
2251 /* Ignores attenuation */
2255 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2256 return WINED3DERR_INVALIDCALL;
2259 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2261 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2262 if(object->OriginalIndex == Index) break;
2267 TRACE("Adding new light\n");
2268 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2270 ERR("Out of memory error when allocating a light\n");
2271 return E_OUTOFMEMORY;
2273 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2274 object->glIndex = -1;
2275 object->OriginalIndex = Index;
2278 /* Initialize the object */
2279 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,
2280 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2281 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2282 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2283 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2284 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2285 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2287 /* Save away the information */
2288 object->OriginalParms = *pLight;
2290 switch (pLight->Type) {
2291 case WINED3DLIGHT_POINT:
2293 object->lightPosn[0] = pLight->Position.x;
2294 object->lightPosn[1] = pLight->Position.y;
2295 object->lightPosn[2] = pLight->Position.z;
2296 object->lightPosn[3] = 1.0f;
2297 object->cutoff = 180.0f;
2301 case WINED3DLIGHT_DIRECTIONAL:
2303 object->lightPosn[0] = -pLight->Direction.x;
2304 object->lightPosn[1] = -pLight->Direction.y;
2305 object->lightPosn[2] = -pLight->Direction.z;
2306 object->lightPosn[3] = 0.0f;
2307 object->exponent = 0.0f;
2308 object->cutoff = 180.0f;
2311 case WINED3DLIGHT_SPOT:
2313 object->lightPosn[0] = pLight->Position.x;
2314 object->lightPosn[1] = pLight->Position.y;
2315 object->lightPosn[2] = pLight->Position.z;
2316 object->lightPosn[3] = 1.0f;
2319 object->lightDirn[0] = pLight->Direction.x;
2320 object->lightDirn[1] = pLight->Direction.y;
2321 object->lightDirn[2] = pLight->Direction.z;
2322 object->lightDirn[3] = 1.0f;
2325 * opengl-ish and d3d-ish spot lights use too different models for the
2326 * light "intensity" as a function of the angle towards the main light direction,
2327 * so we only can approximate very roughly.
2328 * however spot lights are rather rarely used in games (if ever used at all).
2329 * furthermore if still used, probably nobody pays attention to such details.
2331 if (pLight->Falloff == 0) {
2332 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2333 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2334 * will always be 1.0 for both of them, and we don't have to care for the
2335 * rest of the rather complex calculation
2337 object->exponent = 0.0f;
2339 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2340 if (rho < 0.0001f) rho = 0.0001f;
2341 object->exponent = -0.3f/logf(cosf(rho/2));
2343 if (object->exponent > 128.0f)
2345 object->exponent = 128.0f;
2347 object->cutoff = pLight->Phi*90/M_PI;
2353 FIXME("Unrecognized light type %d\n", pLight->Type);
2356 /* Update the live definitions if the light is currently assigned a glIndex */
2357 if (object->glIndex != -1 && !This->isRecordingState) {
2358 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2363 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2365 struct wined3d_light_info *lightInfo = NULL;
2366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2367 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2369 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2371 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2373 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2374 if(lightInfo->OriginalIndex == Index) break;
2378 if (lightInfo == NULL) {
2379 TRACE("Light information requested but light not defined\n");
2380 return WINED3DERR_INVALIDCALL;
2383 *pLight = lightInfo->OriginalParms;
2388 * Get / Set Light Enable
2389 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2391 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2393 struct wined3d_light_info *lightInfo = NULL;
2394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2395 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2397 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2399 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2401 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2402 if(lightInfo->OriginalIndex == Index) break;
2405 TRACE("Found light: %p\n", lightInfo);
2407 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2408 if (lightInfo == NULL) {
2410 TRACE("Light enabled requested but light not defined, so defining one!\n");
2411 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2413 /* Search for it again! Should be fairly quick as near head of list */
2414 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2416 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2417 if(lightInfo->OriginalIndex == Index) break;
2420 if (lightInfo == NULL) {
2421 FIXME("Adding default lights has failed dismally\n");
2422 return WINED3DERR_INVALIDCALL;
2427 if(lightInfo->glIndex != -1) {
2428 if(!This->isRecordingState) {
2429 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2432 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2433 lightInfo->glIndex = -1;
2435 TRACE("Light already disabled, nothing to do\n");
2437 lightInfo->enabled = FALSE;
2439 lightInfo->enabled = TRUE;
2440 if (lightInfo->glIndex != -1) {
2442 TRACE("Nothing to do as light was enabled\n");
2445 /* Find a free gl light */
2446 for(i = 0; i < This->maxConcurrentLights; i++) {
2447 if(This->updateStateBlock->activeLights[i] == NULL) {
2448 This->updateStateBlock->activeLights[i] = lightInfo;
2449 lightInfo->glIndex = i;
2453 if(lightInfo->glIndex == -1) {
2454 /* Our tests show that Windows returns D3D_OK in this situation, even with
2455 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2456 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2457 * as well for those lights.
2459 * TODO: Test how this affects rendering
2461 WARN("Too many concurrently active lights\n");
2465 /* i == lightInfo->glIndex */
2466 if(!This->isRecordingState) {
2467 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2475 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2477 struct wined3d_light_info *lightInfo = NULL;
2478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2480 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2481 TRACE("(%p) : for idx(%d)\n", This, Index);
2483 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2485 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2486 if(lightInfo->OriginalIndex == Index) break;
2490 if (lightInfo == NULL) {
2491 TRACE("Light enabled state requested but light not defined\n");
2492 return WINED3DERR_INVALIDCALL;
2494 /* true is 128 according to SetLightEnable */
2495 *pEnable = lightInfo->enabled ? 128 : 0;
2500 * Get / Set Clip Planes
2502 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2504 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2506 /* Validate Index */
2507 if (Index >= This->adapter->gl_info.limits.clipplanes)
2509 TRACE("Application has requested clipplane this device doesn't support\n");
2510 return WINED3DERR_INVALIDCALL;
2513 This->updateStateBlock->changed.clipplane |= 1 << Index;
2515 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2516 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2517 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2518 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2519 TRACE("Application is setting old values over, nothing to do\n");
2523 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2524 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2525 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2526 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2528 /* Handle recording of state blocks */
2529 if (This->isRecordingState) {
2530 TRACE("Recording... not performing anything\n");
2534 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2539 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2540 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2541 TRACE("(%p) : for idx %d\n", This, Index);
2543 /* Validate Index */
2544 if (Index >= This->adapter->gl_info.limits.clipplanes)
2546 TRACE("Application has requested clipplane this device doesn't support\n");
2547 return WINED3DERR_INVALIDCALL;
2550 pPlane[0] = This->stateBlock->clipplane[Index][0];
2551 pPlane[1] = This->stateBlock->clipplane[Index][1];
2552 pPlane[2] = This->stateBlock->clipplane[Index][2];
2553 pPlane[3] = This->stateBlock->clipplane[Index][3];
2558 * Get / Set Clip Plane Status
2559 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2561 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2563 FIXME("(%p) : stub\n", This);
2564 if (NULL == pClipStatus) {
2565 return WINED3DERR_INVALIDCALL;
2567 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2568 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2572 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2574 FIXME("(%p) : stub\n", This);
2575 if (NULL == pClipStatus) {
2576 return WINED3DERR_INVALIDCALL;
2578 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2579 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2584 * Get / Set Material
2586 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2589 This->updateStateBlock->changed.material = TRUE;
2590 This->updateStateBlock->material = *pMaterial;
2592 /* Handle recording of state blocks */
2593 if (This->isRecordingState) {
2594 TRACE("Recording... not performing anything\n");
2598 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2602 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2604 *pMaterial = This->updateStateBlock->material;
2605 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2606 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2607 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2608 pMaterial->Ambient.b, pMaterial->Ambient.a);
2609 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2610 pMaterial->Specular.b, pMaterial->Specular.a);
2611 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2612 pMaterial->Emissive.b, pMaterial->Emissive.a);
2613 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2621 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2622 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2625 IWineD3DBuffer *oldIdxs;
2627 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2628 oldIdxs = This->updateStateBlock->pIndexData;
2630 This->updateStateBlock->changed.indices = TRUE;
2631 This->updateStateBlock->pIndexData = pIndexData;
2632 This->updateStateBlock->IndexFmt = fmt;
2634 /* Handle recording of state blocks */
2635 if (This->isRecordingState) {
2636 TRACE("Recording... not performing anything\n");
2637 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2638 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2642 if(oldIdxs != pIndexData) {
2643 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2645 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2646 IWineD3DBuffer_AddRef(pIndexData);
2649 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2650 IWineD3DBuffer_Release(oldIdxs);
2657 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2661 *ppIndexData = This->stateBlock->pIndexData;
2663 /* up ref count on ppindexdata */
2665 IWineD3DBuffer_AddRef(*ppIndexData);
2666 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2668 TRACE("(%p) No index data set\n", This);
2670 TRACE("Returning %p\n", *ppIndexData);
2675 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2676 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2678 TRACE("(%p)->(%d)\n", This, BaseIndex);
2680 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2681 TRACE("Application is setting the old value over, nothing to do\n");
2685 This->updateStateBlock->baseVertexIndex = BaseIndex;
2687 if (This->isRecordingState) {
2688 TRACE("Recording... not performing anything\n");
2691 /* The base vertex index affects the stream sources */
2692 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2696 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2698 TRACE("(%p) : base_index %p\n", This, base_index);
2700 *base_index = This->stateBlock->baseVertexIndex;
2702 TRACE("Returning %u\n", *base_index);
2708 * Get / Set Viewports
2710 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2713 TRACE("(%p)\n", This);
2714 This->updateStateBlock->changed.viewport = TRUE;
2715 This->updateStateBlock->viewport = *pViewport;
2717 /* Handle recording of state blocks */
2718 if (This->isRecordingState) {
2719 TRACE("Recording... not performing anything\n");
2723 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2724 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2726 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2731 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2733 TRACE("(%p)\n", This);
2734 *pViewport = This->stateBlock->viewport;
2739 * Get / Set Render States
2740 * TODO: Verify against dx9 definitions
2742 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2745 DWORD oldValue = This->stateBlock->renderState[State];
2747 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2749 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2750 This->updateStateBlock->renderState[State] = Value;
2752 /* Handle recording of state blocks */
2753 if (This->isRecordingState) {
2754 TRACE("Recording... not performing anything\n");
2758 /* Compared here and not before the assignment to allow proper stateblock recording */
2759 if(Value == oldValue) {
2760 TRACE("Application is setting the old value over, nothing to do\n");
2762 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2768 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2770 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2771 *pValue = This->stateBlock->renderState[State];
2776 * Get / Set Sampler States
2777 * TODO: Verify against dx9 definitions
2780 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2784 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2785 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2787 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2788 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2791 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2792 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2793 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2796 * SetSampler is designed to allow for more than the standard up to 8 textures
2797 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2798 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2800 * http://developer.nvidia.com/object/General_FAQ.html#t6
2802 * There are two new settings for GForce
2804 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2805 * and the texture one:
2806 * GL_MAX_TEXTURE_COORDS_ARB.
2807 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2810 oldValue = This->stateBlock->samplerState[Sampler][Type];
2811 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2812 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2814 /* Handle recording of state blocks */
2815 if (This->isRecordingState) {
2816 TRACE("Recording... not performing anything\n");
2820 if(oldValue == Value) {
2821 TRACE("Application is setting the old value over, nothing to do\n");
2825 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2830 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2833 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2834 This, Sampler, debug_d3dsamplerstate(Type), Type);
2836 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2837 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2840 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2841 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2842 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2844 *Value = This->stateBlock->samplerState[Sampler][Type];
2845 TRACE("(%p) : Returning %#x\n", This, *Value);
2850 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2853 This->updateStateBlock->changed.scissorRect = TRUE;
2854 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2855 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2858 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2860 if(This->isRecordingState) {
2861 TRACE("Recording... not performing anything\n");
2865 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2870 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2873 *pRect = This->updateStateBlock->scissorRect;
2874 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2878 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2880 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2882 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2884 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2885 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2887 This->updateStateBlock->vertexDecl = pDecl;
2888 This->updateStateBlock->changed.vertexDecl = TRUE;
2890 if (This->isRecordingState) {
2891 TRACE("Recording... not performing anything\n");
2893 } else if(pDecl == oldDecl) {
2894 /* Checked after the assignment to allow proper stateblock recording */
2895 TRACE("Application is setting the old declaration over, nothing to do\n");
2899 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2903 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2906 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2908 *ppDecl = This->stateBlock->vertexDecl;
2909 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2913 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2915 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2917 This->updateStateBlock->vertexShader = pShader;
2918 This->updateStateBlock->changed.vertexShader = TRUE;
2920 if (This->isRecordingState) {
2921 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2922 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2923 TRACE("Recording... not performing anything\n");
2925 } else if(oldShader == pShader) {
2926 /* Checked here to allow proper stateblock recording */
2927 TRACE("App is setting the old shader over, nothing to do\n");
2931 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2932 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2933 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2935 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2940 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2943 if (NULL == ppShader) {
2944 return WINED3DERR_INVALIDCALL;
2946 *ppShader = This->stateBlock->vertexShader;
2947 if( NULL != *ppShader)
2948 IWineD3DVertexShader_AddRef(*ppShader);
2950 TRACE("(%p) : returning %p\n", This, *ppShader);
2954 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2955 IWineD3DDevice *iface,
2957 CONST BOOL *srcData,
2960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2961 unsigned int i, cnt = min(count, MAX_CONST_B - start);
2963 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2964 iface, srcData, start, count);
2966 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
2968 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2969 for (i = 0; i < cnt; i++)
2970 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2972 for (i = start; i < cnt + start; ++i) {
2973 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
2976 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2981 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2982 IWineD3DDevice *iface,
2987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2988 int cnt = min(count, MAX_CONST_B - start);
2990 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2991 iface, dstData, start, count);
2993 if (dstData == NULL || cnt < 0)
2994 return WINED3DERR_INVALIDCALL;
2996 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3000 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3001 IWineD3DDevice *iface,
3006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3007 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3009 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3010 iface, srcData, start, count);
3012 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3014 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3015 for (i = 0; i < cnt; i++)
3016 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3017 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3019 for (i = start; i < cnt + start; ++i) {
3020 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3023 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3028 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3029 IWineD3DDevice *iface,
3034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3035 int cnt = min(count, MAX_CONST_I - start);
3037 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3038 iface, dstData, start, count);
3040 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3041 return WINED3DERR_INVALIDCALL;
3043 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3047 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3048 IWineD3DDevice *iface,
3050 CONST float *srcData,
3053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3056 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3057 iface, srcData, start, count);
3059 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3060 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3061 return WINED3DERR_INVALIDCALL;
3063 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3065 for (i = 0; i < count; i++)
3066 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3067 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3070 if (!This->isRecordingState)
3072 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3073 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3076 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3077 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3082 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3083 IWineD3DDevice *iface,
3088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3089 int cnt = min(count, This->d3d_vshader_constantF - start);
3091 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3092 iface, dstData, start, count);
3094 if (dstData == NULL || cnt < 0)
3095 return WINED3DERR_INVALIDCALL;
3097 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3101 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3103 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3105 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3109 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3111 DWORD i = This->rev_tex_unit_map[unit];
3112 DWORD j = This->texUnitMap[stage];
3114 This->texUnitMap[stage] = unit;
3115 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3117 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3120 This->rev_tex_unit_map[unit] = stage;
3121 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3123 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3127 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3130 This->fixed_function_usage_map = 0;
3131 for (i = 0; i < MAX_TEXTURES; ++i) {
3132 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3133 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3134 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3135 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3136 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3137 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3138 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3139 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3141 if (color_op == WINED3DTOP_DISABLE) {
3142 /* Not used, and disable higher stages */
3146 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3147 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3148 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3149 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3150 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3151 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3152 This->fixed_function_usage_map |= (1 << i);
3155 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3156 This->fixed_function_usage_map |= (1 << (i + 1));
3161 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3163 unsigned int i, tex;
3166 device_update_fixed_function_usage_map(This);
3167 ffu_map = This->fixed_function_usage_map;
3169 if (This->max_ffp_textures == gl_info->limits.texture_stages
3170 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3172 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3174 if (!(ffu_map & 1)) continue;
3176 if (This->texUnitMap[i] != i) {
3177 device_map_stage(This, i, i);
3178 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3179 markTextureStagesDirty(This, i);
3185 /* Now work out the mapping */
3187 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3189 if (!(ffu_map & 1)) continue;
3191 if (This->texUnitMap[i] != tex) {
3192 device_map_stage(This, i, tex);
3193 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3194 markTextureStagesDirty(This, i);
3201 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3203 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3204 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3207 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3208 if (sampler_type[i] && This->texUnitMap[i] != i)
3210 device_map_stage(This, i, i);
3211 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3212 if (i < gl_info->limits.texture_stages)
3214 markTextureStagesDirty(This, i);
3220 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3221 const DWORD *vshader_sampler_tokens, DWORD unit)
3223 DWORD current_mapping = This->rev_tex_unit_map[unit];
3225 /* Not currently used */
3226 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3228 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3229 /* Used by a fragment sampler */
3231 if (!pshader_sampler_tokens) {
3232 /* No pixel shader, check fixed function */
3233 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3236 /* Pixel shader, check the shader's sampler map */
3237 return !pshader_sampler_tokens[current_mapping];
3240 /* Used by a vertex sampler */
3241 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3244 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3246 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3247 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3248 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3249 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3253 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3255 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3256 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3257 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3260 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3261 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3262 if (vshader_sampler_type[i])
3264 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3266 /* Already mapped somewhere */
3270 while (start >= 0) {
3271 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3273 device_map_stage(This, vsampler_idx, start);
3274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3286 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3288 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3289 BOOL vs = use_vs(This->stateBlock);
3290 BOOL ps = use_ps(This->stateBlock);
3293 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3294 * that would be really messy and require shader recompilation
3295 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3296 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3298 if (ps) device_map_psamplers(This, gl_info);
3299 else device_map_fixed_function_samplers(This, gl_info);
3301 if (vs) device_map_vsamplers(This, ps, gl_info);
3304 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3306 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3307 This->updateStateBlock->pixelShader = pShader;
3308 This->updateStateBlock->changed.pixelShader = TRUE;
3310 /* Handle recording of state blocks */
3311 if (This->isRecordingState) {
3312 TRACE("Recording... not performing anything\n");
3315 if (This->isRecordingState) {
3316 TRACE("Recording... not performing anything\n");
3317 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3318 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3322 if(pShader == oldShader) {
3323 TRACE("App is setting the old pixel shader over, nothing to do\n");
3327 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3328 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3330 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3331 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3336 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3339 if (NULL == ppShader) {
3340 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3341 return WINED3DERR_INVALIDCALL;
3344 *ppShader = This->stateBlock->pixelShader;
3345 if (NULL != *ppShader) {
3346 IWineD3DPixelShader_AddRef(*ppShader);
3348 TRACE("(%p) : returning %p\n", This, *ppShader);
3352 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3353 IWineD3DDevice *iface,
3355 CONST BOOL *srcData,
3358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3359 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3361 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3362 iface, srcData, start, count);
3364 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3366 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3367 for (i = 0; i < cnt; i++)
3368 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3370 for (i = start; i < cnt + start; ++i) {
3371 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3374 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3379 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3380 IWineD3DDevice *iface,
3385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3386 int cnt = min(count, MAX_CONST_B - start);
3388 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3389 iface, dstData, start, count);
3391 if (dstData == NULL || cnt < 0)
3392 return WINED3DERR_INVALIDCALL;
3394 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3398 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3399 IWineD3DDevice *iface,
3404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3405 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3407 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3408 iface, srcData, start, count);
3410 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3412 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3413 for (i = 0; i < cnt; i++)
3414 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3415 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3417 for (i = start; i < cnt + start; ++i) {
3418 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3421 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3426 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3427 IWineD3DDevice *iface,
3432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3433 int cnt = min(count, MAX_CONST_I - start);
3435 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3436 iface, dstData, start, count);
3438 if (dstData == NULL || cnt < 0)
3439 return WINED3DERR_INVALIDCALL;
3441 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3445 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3446 IWineD3DDevice *iface,
3448 CONST float *srcData,
3451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3454 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3455 iface, srcData, start, count);
3457 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3458 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3459 return WINED3DERR_INVALIDCALL;
3461 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3463 for (i = 0; i < count; i++)
3464 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3465 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3468 if (!This->isRecordingState)
3470 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3471 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3474 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3475 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3480 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3481 IWineD3DDevice *iface,
3486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3487 int cnt = min(count, This->d3d_pshader_constantF - start);
3489 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3490 iface, dstData, start, count);
3492 if (dstData == NULL || cnt < 0)
3493 return WINED3DERR_INVALIDCALL;
3495 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3499 /* Context activation is done by the caller. */
3500 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3501 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3502 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3505 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3506 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3509 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3513 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3515 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3518 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3520 ERR("Source has no position mask\n");
3521 return WINED3DERR_INVALIDCALL;
3524 /* We might access VBOs from this code, so hold the lock */
3527 if (dest->resource.allocatedMemory == NULL) {
3528 buffer_get_sysmem(dest);
3531 /* Get a pointer into the destination vbo(create one if none exists) and
3532 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3534 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3536 dest->flags |= WINED3D_BUFFER_CREATEBO;
3537 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3540 if (dest->buffer_object)
3542 unsigned char extrabytes = 0;
3543 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3544 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3545 * this may write 4 extra bytes beyond the area that should be written
3547 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3548 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3549 if(!dest_conv_addr) {
3550 ERR("Out of memory\n");
3551 /* Continue without storing converted vertices */
3553 dest_conv = dest_conv_addr;
3557 * a) WINED3DRS_CLIPPING is enabled
3558 * b) WINED3DVOP_CLIP is passed
3560 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3561 static BOOL warned = FALSE;
3563 * The clipping code is not quite correct. Some things need
3564 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3565 * so disable clipping for now.
3566 * (The graphics in Half-Life are broken, and my processvertices
3567 * test crashes with IDirect3DDevice3)
3573 FIXME("Clipping is broken and disabled for now\n");
3575 } else doClip = FALSE;
3576 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3578 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3581 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3582 WINED3DTS_PROJECTION,
3584 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3585 WINED3DTS_WORLDMATRIX(0),
3588 TRACE("View mat:\n");
3589 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);
3590 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);
3591 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);
3592 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);
3594 TRACE("Proj mat:\n");
3595 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);
3596 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);
3597 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);
3598 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);
3600 TRACE("World mat:\n");
3601 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);
3602 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);
3603 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);
3604 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);
3606 /* Get the viewport */
3607 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3608 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3609 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3611 multiply_matrix(&mat,&view_mat,&world_mat);
3612 multiply_matrix(&mat,&proj_mat,&mat);
3614 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3616 for (i = 0; i < dwCount; i+= 1) {
3617 unsigned int tex_index;
3619 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3620 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3621 /* The position first */
3622 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3623 const float *p = (const float *)(element->data + i * element->stride);
3625 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3627 /* Multiplication with world, view and projection matrix */
3628 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);
3629 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);
3630 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);
3631 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);
3633 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3635 /* WARNING: The following things are taken from d3d7 and were not yet checked
3636 * against d3d8 or d3d9!
3639 /* Clipping conditions: From msdn
3641 * A vertex is clipped if it does not match the following requirements
3645 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3647 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3648 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3653 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3654 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3657 /* "Normal" viewport transformation (not clipped)
3658 * 1) The values are divided by rhw
3659 * 2) The y axis is negative, so multiply it with -1
3660 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3661 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3662 * 4) Multiply x with Width/2 and add Width/2
3663 * 5) The same for the height
3664 * 6) Add the viewpoint X and Y to the 2D coordinates and
3665 * The minimum Z value to z
3666 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3668 * Well, basically it's simply a linear transformation into viewport
3680 z *= vp.MaxZ - vp.MinZ;
3682 x += vp.Width / 2 + vp.X;
3683 y += vp.Height / 2 + vp.Y;
3688 /* That vertex got clipped
3689 * Contrary to OpenGL it is not dropped completely, it just
3690 * undergoes a different calculation.
3692 TRACE("Vertex got clipped\n");
3699 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3700 * outside of the main vertex buffer memory. That needs some more
3705 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3708 ( (float *) dest_ptr)[0] = x;
3709 ( (float *) dest_ptr)[1] = y;
3710 ( (float *) dest_ptr)[2] = z;
3711 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3713 dest_ptr += 3 * sizeof(float);
3715 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3716 dest_ptr += sizeof(float);
3721 ( (float *) dest_conv)[0] = x * w;
3722 ( (float *) dest_conv)[1] = y * w;
3723 ( (float *) dest_conv)[2] = z * w;
3724 ( (float *) dest_conv)[3] = w;
3726 dest_conv += 3 * sizeof(float);
3728 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3729 dest_conv += sizeof(float);
3733 if (DestFVF & WINED3DFVF_PSIZE) {
3734 dest_ptr += sizeof(DWORD);
3735 if(dest_conv) dest_conv += sizeof(DWORD);
3737 if (DestFVF & WINED3DFVF_NORMAL) {
3738 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3739 const float *normal = (const float *)(element->data + i * element->stride);
3740 /* AFAIK this should go into the lighting information */
3741 FIXME("Didn't expect the destination to have a normal\n");
3742 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3744 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3748 if (DestFVF & WINED3DFVF_DIFFUSE) {
3749 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3750 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3751 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3753 static BOOL warned = FALSE;
3756 ERR("No diffuse color in source, but destination has one\n");
3760 *( (DWORD *) dest_ptr) = 0xffffffff;
3761 dest_ptr += sizeof(DWORD);
3764 *( (DWORD *) dest_conv) = 0xffffffff;
3765 dest_conv += sizeof(DWORD);
3769 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3771 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3772 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3773 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3774 dest_conv += sizeof(DWORD);
3779 if (DestFVF & WINED3DFVF_SPECULAR)
3781 /* What's the color value in the feedback buffer? */
3782 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3783 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3784 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3786 static BOOL warned = FALSE;
3789 ERR("No specular color in source, but destination has one\n");
3793 *( (DWORD *) dest_ptr) = 0xFF000000;
3794 dest_ptr += sizeof(DWORD);
3797 *( (DWORD *) dest_conv) = 0xFF000000;
3798 dest_conv += sizeof(DWORD);
3802 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3804 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3805 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3806 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3807 dest_conv += sizeof(DWORD);
3812 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3813 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3814 const float *tex_coord = (const float *)(element->data + i * element->stride);
3815 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3817 ERR("No source texture, but destination requests one\n");
3818 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3819 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3822 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3824 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3831 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3832 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3833 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3834 dwCount * get_flexible_vertex_size(DestFVF),
3836 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3837 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3844 #undef copy_and_next
3846 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3847 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3851 struct wined3d_stream_info stream_info;
3852 struct wined3d_context *context;
3853 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3856 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3859 ERR("Output vertex declaration not implemented yet\n");
3862 /* Need any context to write to the vbo. */
3863 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
3865 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3866 * control the streamIsUP flag, thus restore it afterwards.
3868 This->stateBlock->streamIsUP = FALSE;
3869 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3870 This->stateBlock->streamIsUP = streamWasUP;
3872 if(vbo || SrcStartIndex) {
3874 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3875 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3877 * Also get the start index in, but only loop over all elements if there's something to add at all.
3879 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3881 struct wined3d_stream_info_element *e;
3883 if (!(stream_info.use_map & (1 << i))) continue;
3885 e = &stream_info.elements[i];
3886 if (e->buffer_object)
3888 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3889 e->buffer_object = 0;
3890 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3892 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3893 vb->buffer_object = 0;
3896 if (e->data) e->data += e->stride * SrcStartIndex;
3900 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3901 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3903 context_release(context);
3909 * Get / Set Texture Stage States
3910 * TODO: Verify against dx9 definitions
3912 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3914 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3915 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3917 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3919 if (Stage >= gl_info->limits.texture_stages)
3921 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3922 Stage, gl_info->limits.texture_stages - 1);
3926 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3927 This->updateStateBlock->textureState[Stage][Type] = Value;
3929 if (This->isRecordingState) {
3930 TRACE("Recording... not performing anything\n");
3934 /* Checked after the assignments to allow proper stateblock recording */
3935 if(oldValue == Value) {
3936 TRACE("App is setting the old value over, nothing to do\n");
3940 if(Stage > This->stateBlock->lowest_disabled_stage &&
3941 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3942 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3943 * Changes in other states are important on disabled stages too
3948 if(Type == WINED3DTSS_COLOROP) {
3951 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3952 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3953 * they have to be disabled
3955 * The current stage is dirtified below.
3957 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3958 TRACE("Additionally dirtifying stage %u\n", i);
3959 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3961 This->stateBlock->lowest_disabled_stage = Stage;
3962 TRACE("New lowest disabled: %u\n", Stage);
3963 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3964 /* Previously disabled stage enabled. Stages above it may need enabling
3965 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3966 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3968 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3971 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
3973 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3976 TRACE("Additionally dirtifying stage %u due to enable\n", i);
3977 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3979 This->stateBlock->lowest_disabled_stage = i;
3980 TRACE("New lowest disabled: %u\n", i);
3984 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3989 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3991 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3992 *pValue = This->updateStateBlock->textureState[Stage][Type];
3999 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4000 DWORD stage, IWineD3DBaseTexture *texture)
4002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4003 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4004 IWineD3DBaseTexture *prev;
4006 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4008 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4009 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4011 /* Windows accepts overflowing this array... we do not. */
4012 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4014 WARN("Ignoring invalid stage %u.\n", stage);
4018 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4019 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4021 WARN("Rejecting attempt to set scratch texture.\n");
4022 return WINED3DERR_INVALIDCALL;
4025 This->updateStateBlock->changed.textures |= 1 << stage;
4027 prev = This->updateStateBlock->textures[stage];
4028 TRACE("Previous texture %p.\n", prev);
4030 if (texture == prev)
4032 TRACE("App is setting the same texture again, nothing to do.\n");
4036 TRACE("Setting new texture to %p.\n", texture);
4037 This->updateStateBlock->textures[stage] = texture;
4039 if (This->isRecordingState)
4041 TRACE("Recording... not performing anything\n");
4043 if (texture) IWineD3DBaseTexture_AddRef(texture);
4044 if (prev) IWineD3DBaseTexture_Release(prev);
4051 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4052 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4053 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4055 IWineD3DBaseTexture_AddRef(texture);
4057 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4059 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4062 if (!prev && stage < gl_info->limits.texture_stages)
4064 /* The source arguments for color and alpha ops have different
4065 * meanings when a NULL texture is bound, so the COLOROP and
4066 * ALPHAOP have to be dirtified. */
4067 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4068 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4071 if (bind_count == 1) t->baseTexture.sampler = stage;
4076 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4077 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4079 IWineD3DBaseTexture_Release(prev);
4081 if (!texture && stage < gl_info->limits.texture_stages)
4083 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4084 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4087 if (bind_count && t->baseTexture.sampler == stage)
4091 /* Search for other stages the texture is bound to. Shouldn't
4092 * happen if applications bind textures to a single stage only. */
4093 TRACE("Searching for other stages the texture is bound to.\n");
4094 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4096 if (This->updateStateBlock->textures[i] == prev)
4098 TRACE("Texture is also bound to stage %u.\n", i);
4099 t->baseTexture.sampler = i;
4106 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4111 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4114 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4116 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4117 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4120 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4121 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4122 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4125 *ppTexture=This->stateBlock->textures[Stage];
4127 IWineD3DBaseTexture_AddRef(*ppTexture);
4129 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4137 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4138 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4140 IWineD3DSwapChain *swapchain;
4143 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4144 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4146 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4149 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4153 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4154 IWineD3DSwapChain_Release(swapchain);
4157 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4164 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4166 WARN("(%p) : stub, calling idirect3d for now\n", This);
4167 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4170 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4172 IWineD3DSwapChain *swapChain;
4175 if(iSwapChain > 0) {
4176 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4177 if (hr == WINED3D_OK) {
4178 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4179 IWineD3DSwapChain_Release(swapChain);
4181 FIXME("(%p) Error getting display mode\n", This);
4184 /* Don't read the real display mode,
4185 but return the stored mode instead. X11 can't change the color
4186 depth, and some apps are pretty angry if they SetDisplayMode from
4187 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4189 Also don't relay to the swapchain because with ddraw it's possible
4190 that there isn't a swapchain at all */
4191 pMode->Width = This->ddraw_width;
4192 pMode->Height = This->ddraw_height;
4193 pMode->Format = This->ddraw_format;
4194 pMode->RefreshRate = 0;
4202 * Stateblock related functions
4205 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4207 IWineD3DStateBlock *stateblock;
4210 TRACE("(%p)\n", This);
4212 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4214 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4215 if (FAILED(hr)) return hr;
4217 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4218 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4219 This->isRecordingState = TRUE;
4221 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4226 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4228 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4230 if (!This->isRecordingState) {
4231 WARN("(%p) not recording! returning error\n", This);
4232 *ppStateBlock = NULL;
4233 return WINED3DERR_INVALIDCALL;
4236 stateblock_init_contained_states(object);
4238 *ppStateBlock = (IWineD3DStateBlock*) object;
4239 This->isRecordingState = FALSE;
4240 This->updateStateBlock = This->stateBlock;
4241 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4242 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4243 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4248 * Scene related functions
4250 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4251 /* At the moment we have no need for any functionality at the beginning
4253 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4254 TRACE("(%p)\n", This);
4257 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4258 return WINED3DERR_INVALIDCALL;
4260 This->inScene = TRUE;
4264 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4267 struct wined3d_context *context;
4269 TRACE("(%p)\n", This);
4271 if(!This->inScene) {
4272 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4273 return WINED3DERR_INVALIDCALL;
4276 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4277 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4279 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4281 context_release(context);
4283 This->inScene = FALSE;
4287 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4288 const RECT *pSourceRect, const RECT *pDestRect,
4289 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4291 IWineD3DSwapChain *swapChain = NULL;
4293 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4295 TRACE("iface %p.\n", iface);
4297 for(i = 0 ; i < swapchains ; i ++) {
4299 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4300 TRACE("presentinng chain %d, %p\n", i, swapChain);
4301 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4302 IWineD3DSwapChain_Release(swapChain);
4308 /* Not called from the VTable (internal subroutine) */
4309 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4310 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4311 float Z, DWORD Stencil) {
4312 GLbitfield glMask = 0;
4314 WINED3DRECT curRect;
4316 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4317 UINT drawable_width, drawable_height;
4318 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4319 struct wined3d_context *context;
4321 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4322 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4323 * for the cleared parts, and the untouched parts.
4325 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4326 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4327 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4328 * checking all this if the dest surface is in the drawable anyway.
4330 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4332 if(vp->X != 0 || vp->Y != 0 ||
4333 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4334 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4337 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4338 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4339 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4340 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4341 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4344 if(Count > 0 && pRects && (
4345 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4346 pRects[0].x2 < target->currentDesc.Width ||
4347 pRects[0].y2 < target->currentDesc.Height)) {
4348 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4355 context = context_acquire(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4357 target->get_drawable_size(context, &drawable_width, &drawable_height);
4361 /* Only set the values up once, as they are not changing */
4362 if (Flags & WINED3DCLEAR_STENCIL) {
4363 glClearStencil(Stencil);
4364 checkGLcall("glClearStencil");
4365 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4366 glStencilMask(0xFFFFFFFF);
4369 if (Flags & WINED3DCLEAR_ZBUFFER) {
4370 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4371 glDepthMask(GL_TRUE);
4373 checkGLcall("glClearDepth");
4374 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4375 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4377 if (vp->X != 0 || vp->Y != 0 ||
4378 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4379 surface_load_ds_location(This->stencilBufferTarget, context, location);
4381 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4382 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4383 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4384 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4385 surface_load_ds_location(This->stencilBufferTarget, context, location);
4387 else if (Count > 0 && pRects && (
4388 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4389 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4390 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4391 surface_load_ds_location(This->stencilBufferTarget, context, location);
4395 if (Flags & WINED3DCLEAR_TARGET) {
4396 TRACE("Clearing screen with glClear to color %x\n", Color);
4397 glClearColor(D3DCOLOR_R(Color),
4401 checkGLcall("glClearColor");
4403 /* Clear ALL colors! */
4404 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4405 glMask = glMask | GL_COLOR_BUFFER_BIT;
4408 vp_rect.left = vp->X;
4409 vp_rect.top = vp->Y;
4410 vp_rect.right = vp->X + vp->Width;
4411 vp_rect.bottom = vp->Y + vp->Height;
4412 if (!(Count > 0 && pRects)) {
4413 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4414 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4416 if (context->render_offscreen)
4418 glScissor(vp_rect.left, vp_rect.top,
4419 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4421 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4422 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4424 checkGLcall("glScissor");
4426 checkGLcall("glClear");
4428 /* Now process each rect in turn */
4429 for (i = 0; i < Count; i++) {
4430 /* Note gl uses lower left, width/height */
4431 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4432 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4433 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4435 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4436 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4437 curRect.x1, (target->currentDesc.Height - curRect.y2),
4438 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4440 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4441 * The rectangle is not cleared, no error is returned, but further rectanlges are
4442 * still cleared if they are valid
4444 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4445 TRACE("Rectangle with negative dimensions, ignoring\n");
4449 if (context->render_offscreen)
4451 glScissor(curRect.x1, curRect.y1,
4452 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4454 glScissor(curRect.x1, drawable_height - curRect.y2,
4455 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4457 checkGLcall("glScissor");
4460 checkGLcall("glClear");
4464 /* Restore the old values (why..?) */
4465 if (Flags & WINED3DCLEAR_STENCIL) {
4466 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4468 if (Flags & WINED3DCLEAR_TARGET) {
4469 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4470 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4471 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4472 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4473 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4475 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4476 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4478 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4480 if (Flags & WINED3DCLEAR_ZBUFFER) {
4481 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4482 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4483 surface_modify_ds_location(This->stencilBufferTarget, location);
4488 wglFlush(); /* Flush to ensure ordering across contexts. */
4490 context_release(context);
4495 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4496 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4498 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4500 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4501 Count, pRects, Flags, Color, Z, Stencil);
4503 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4504 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4505 /* TODO: What about depth stencil buffers without stencil bits? */
4506 return WINED3DERR_INVALIDCALL;
4509 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4516 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4517 WINED3DPRIMITIVETYPE primitive_type)
4519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4521 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4523 This->updateStateBlock->changed.primitive_type = TRUE;
4524 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4527 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4528 WINED3DPRIMITIVETYPE *primitive_type)
4530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4532 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4534 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4536 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4539 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4543 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4545 if(!This->stateBlock->vertexDecl) {
4546 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4547 return WINED3DERR_INVALIDCALL;
4550 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4551 if(This->stateBlock->streamIsUP) {
4552 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4553 This->stateBlock->streamIsUP = FALSE;
4556 if(This->stateBlock->loadBaseVertexIndex != 0) {
4557 This->stateBlock->loadBaseVertexIndex = 0;
4558 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4560 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4561 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4565 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4569 IWineD3DBuffer *pIB;
4572 pIB = This->stateBlock->pIndexData;
4574 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4575 * without an index buffer set. (The first time at least...)
4576 * D3D8 simply dies, but I doubt it can do much harm to return
4577 * D3DERR_INVALIDCALL there as well. */
4578 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4579 return WINED3DERR_INVALIDCALL;
4582 if(!This->stateBlock->vertexDecl) {
4583 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4584 return WINED3DERR_INVALIDCALL;
4587 if(This->stateBlock->streamIsUP) {
4588 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4589 This->stateBlock->streamIsUP = FALSE;
4591 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4593 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4595 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4601 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4602 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4603 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4606 drawPrimitive(iface, index_count, startIndex, idxStride,
4607 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4612 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4613 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4618 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4619 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4621 if(!This->stateBlock->vertexDecl) {
4622 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4623 return WINED3DERR_INVALIDCALL;
4626 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4627 vb = This->stateBlock->streamSource[0];
4628 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4629 if (vb) IWineD3DBuffer_Release(vb);
4630 This->stateBlock->streamOffset[0] = 0;
4631 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4632 This->stateBlock->streamIsUP = TRUE;
4633 This->stateBlock->loadBaseVertexIndex = 0;
4635 /* TODO: Only mark dirty if drawing from a different UP address */
4636 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4638 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4640 /* MSDN specifies stream zero settings must be set to NULL */
4641 This->stateBlock->streamStride[0] = 0;
4642 This->stateBlock->streamSource[0] = NULL;
4644 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4645 * the new stream sources or use UP drawing again
4650 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4651 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4652 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4659 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4660 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4662 if(!This->stateBlock->vertexDecl) {
4663 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4664 return WINED3DERR_INVALIDCALL;
4667 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4673 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4674 vb = This->stateBlock->streamSource[0];
4675 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4676 if (vb) IWineD3DBuffer_Release(vb);
4677 This->stateBlock->streamIsUP = TRUE;
4678 This->stateBlock->streamOffset[0] = 0;
4679 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4681 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4682 This->stateBlock->baseVertexIndex = 0;
4683 This->stateBlock->loadBaseVertexIndex = 0;
4684 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4685 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4686 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4688 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4690 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4691 This->stateBlock->streamSource[0] = NULL;
4692 This->stateBlock->streamStride[0] = 0;
4693 ib = This->stateBlock->pIndexData;
4695 IWineD3DBuffer_Release(ib);
4696 This->stateBlock->pIndexData = NULL;
4698 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4699 * SetStreamSource to specify a vertex buffer
4705 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4706 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4710 /* Mark the state dirty until we have nicer tracking
4711 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4714 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4715 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4716 This->stateBlock->baseVertexIndex = 0;
4717 This->up_strided = DrawPrimStrideData;
4718 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4719 This->up_strided = NULL;
4723 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4724 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4725 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4728 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4730 /* Mark the state dirty until we have nicer tracking
4731 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4734 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4735 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4736 This->stateBlock->streamIsUP = TRUE;
4737 This->stateBlock->baseVertexIndex = 0;
4738 This->up_strided = DrawPrimStrideData;
4739 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4740 This->up_strided = NULL;
4744 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4745 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4746 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4748 WINED3DLOCKED_BOX src;
4749 WINED3DLOCKED_BOX dst;
4752 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4753 iface, pSourceVolume, pDestinationVolume);
4755 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4756 * dirtification to improve loading performance.
4758 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4759 if(FAILED(hr)) return hr;
4760 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4762 IWineD3DVolume_UnlockBox(pSourceVolume);
4766 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4768 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4770 IWineD3DVolume_UnlockBox(pSourceVolume);
4772 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4777 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4778 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4780 unsigned int level_count, i;
4781 WINED3DRESOURCETYPE type;
4784 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4786 /* Verify that the source and destination textures are non-NULL. */
4787 if (!src_texture || !dst_texture)
4789 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4790 return WINED3DERR_INVALIDCALL;
4793 if (src_texture == dst_texture)
4795 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4796 return WINED3DERR_INVALIDCALL;
4799 /* Verify that the source and destination textures are the same type. */
4800 type = IWineD3DBaseTexture_GetType(src_texture);
4801 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4803 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4804 return WINED3DERR_INVALIDCALL;
4807 /* Check that both textures have the identical numbers of levels. */
4808 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4809 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4811 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4812 return WINED3DERR_INVALIDCALL;
4815 /* Make sure that the destination texture is loaded. */
4816 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4818 /* Update every surface level of the texture. */
4821 case WINED3DRTYPE_TEXTURE:
4823 IWineD3DSurface *src_surface;
4824 IWineD3DSurface *dst_surface;
4826 for (i = 0; i < level_count; ++i)
4828 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4829 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4830 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4831 IWineD3DSurface_Release(dst_surface);
4832 IWineD3DSurface_Release(src_surface);
4835 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4842 case WINED3DRTYPE_CUBETEXTURE:
4844 IWineD3DSurface *src_surface;
4845 IWineD3DSurface *dst_surface;
4846 WINED3DCUBEMAP_FACES face;
4848 for (i = 0; i < level_count; ++i)
4850 /* Update each cube face. */
4851 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4853 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4854 face, i, &src_surface);
4855 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4856 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4857 face, i, &dst_surface);
4858 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4859 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4860 IWineD3DSurface_Release(dst_surface);
4861 IWineD3DSurface_Release(src_surface);
4864 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4872 case WINED3DRTYPE_VOLUMETEXTURE:
4874 IWineD3DVolume *src_volume;
4875 IWineD3DVolume *dst_volume;
4877 for (i = 0; i < level_count; ++i)
4879 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4880 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4881 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4882 IWineD3DVolume_Release(dst_volume);
4883 IWineD3DVolume_Release(src_volume);
4886 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4894 FIXME("Unsupported texture type %#x.\n", type);
4895 return WINED3DERR_INVALIDCALL;
4901 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4902 IWineD3DSwapChain *swapChain;
4904 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4905 if(hr == WINED3D_OK) {
4906 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4907 IWineD3DSwapChain_Release(swapChain);
4912 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4914 IWineD3DBaseTextureImpl *texture;
4917 TRACE("(%p) : %p\n", This, pNumPasses);
4919 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4920 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
4921 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4922 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4924 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
4925 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4926 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4929 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
4930 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
4932 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
4933 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4936 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
4937 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4940 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
4941 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
4942 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4947 /* return a sensible default */
4950 TRACE("returning D3D_OK\n");
4954 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
4958 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4960 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
4961 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
4962 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
4964 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
4969 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4973 PALETTEENTRY **palettes;
4975 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4977 if (PaletteNumber >= MAX_PALETTES) {
4978 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4979 return WINED3DERR_INVALIDCALL;
4982 if (PaletteNumber >= This->NumberOfPalettes) {
4983 NewSize = This->NumberOfPalettes;
4986 } while(PaletteNumber >= NewSize);
4987 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
4989 ERR("Out of memory!\n");
4990 return E_OUTOFMEMORY;
4992 This->palettes = palettes;
4993 This->NumberOfPalettes = NewSize;
4996 if (!This->palettes[PaletteNumber]) {
4997 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
4998 if (!This->palettes[PaletteNumber]) {
4999 ERR("Out of memory!\n");
5000 return E_OUTOFMEMORY;
5004 for (j = 0; j < 256; ++j) {
5005 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5006 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5007 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5008 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5010 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5011 TRACE("(%p) : returning\n", This);
5015 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5018 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5019 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5020 /* What happens in such situation isn't documented; Native seems to silently abort
5021 on such conditions. Return Invalid Call. */
5022 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5023 return WINED3DERR_INVALIDCALL;
5025 for (j = 0; j < 256; ++j) {
5026 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5027 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5028 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5029 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5031 TRACE("(%p) : returning\n", This);
5035 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5037 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5038 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5039 (tested with reference rasterizer). Return Invalid Call. */
5040 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5041 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5042 return WINED3DERR_INVALIDCALL;
5044 /*TODO: stateblocks */
5045 if (This->currentPalette != PaletteNumber) {
5046 This->currentPalette = PaletteNumber;
5047 dirtify_p8_texture_samplers(This);
5049 TRACE("(%p) : returning\n", This);
5053 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5055 if (PaletteNumber == NULL) {
5056 WARN("(%p) : returning Invalid Call\n", This);
5057 return WINED3DERR_INVALIDCALL;
5059 /*TODO: stateblocks */
5060 *PaletteNumber = This->currentPalette;
5061 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5065 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5070 FIXME("(%p) : stub\n", This);
5074 This->softwareVertexProcessing = bSoftware;
5079 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5080 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5084 FIXME("(%p) : stub\n", This);
5087 return This->softwareVertexProcessing;
5090 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5091 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5093 IWineD3DSwapChain *swapchain;
5096 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5097 iface, swapchain_idx, raster_status);
5099 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5102 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5106 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5107 IWineD3DSwapChain_Release(swapchain);
5110 WARN("Failed to get raster status, hr %#x.\n", hr);
5117 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5120 if(nSegments != 0.0f) {
5123 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5130 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5135 FIXME("iface %p stub!\n", iface);
5141 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5143 /** TODO: remove casts to IWineD3DSurfaceImpl
5144 * NOTE: move code to surface to accomplish this
5145 ****************************************/
5146 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5147 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5148 int srcWidth, srcHeight;
5149 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5150 WINED3DFORMAT destFormat, srcFormat;
5152 int srcLeft, destLeft, destTop;
5153 WINED3DPOOL srcPool, destPool;
5155 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5156 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5160 CONVERT_TYPES convert = NO_CONVERSION;
5161 struct wined3d_context *context;
5163 WINED3DSURFACE_DESC winedesc;
5165 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5167 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5168 srcSurfaceWidth = winedesc.width;
5169 srcSurfaceHeight = winedesc.height;
5170 srcPool = winedesc.pool;
5171 srcFormat = winedesc.format;
5173 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5174 destSurfaceWidth = winedesc.width;
5175 destSurfaceHeight = winedesc.height;
5176 destPool = winedesc.pool;
5177 destFormat = winedesc.format;
5178 destSize = winedesc.size;
5180 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5181 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5182 return WINED3DERR_INVALIDCALL;
5185 /* This call loads the opengl surface directly, instead of copying the surface to the
5186 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5187 * copy in sysmem and use regular surface loading.
5189 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5190 if(convert != NO_CONVERSION) {
5191 return IWineD3DSurface_BltFast(pDestinationSurface,
5192 pDestPoint ? pDestPoint->x : 0,
5193 pDestPoint ? pDestPoint->y : 0,
5194 pSourceSurface, pSourceRect, 0);
5197 if (destFormat == WINED3DFMT_UNKNOWN) {
5198 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5199 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5201 /* Get the update surface description */
5202 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5205 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5208 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5209 checkGLcall("glActiveTextureARB");
5212 /* Make sure the surface is loaded and up to date */
5213 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5214 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5216 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5217 dst_format_desc = dst_impl->resource.format_desc;
5219 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5220 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5221 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5222 srcLeft = pSourceRect ? pSourceRect->left : 0;
5223 destLeft = pDestPoint ? pDestPoint->x : 0;
5224 destTop = pDestPoint ? pDestPoint->y : 0;
5227 /* This function doesn't support compressed textures
5228 the pitch is just bytesPerPixel * width */
5229 if(srcWidth != srcSurfaceWidth || srcLeft ){
5230 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5231 offset += srcLeft * src_format_desc->byte_count;
5232 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5234 /* TODO DXT formats */
5236 if(pSourceRect != NULL && pSourceRect->top != 0){
5237 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5239 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5240 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5241 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5244 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5246 /* need to lock the surface to get the data */
5247 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5252 /* TODO: Cube and volume support */
5254 /* not a whole row so we have to do it a line at a time */
5257 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5258 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5260 for (j = destTop; j < (srcHeight + destTop); ++j)
5262 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5263 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5267 } else { /* Full width, so just write out the whole texture */
5268 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5270 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5272 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5274 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5275 FIXME("Updating part of a compressed texture is not supported.\n");
5277 if (destFormat != srcFormat)
5279 FIXME("Updating mixed format compressed textures is not supported.\n");
5283 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5284 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5289 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5290 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5293 checkGLcall("glTexSubImage2D");
5296 context_release(context);
5298 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5299 sampler = This->rev_tex_unit_map[0];
5300 if (sampler != WINED3D_UNMAPPED_STAGE)
5302 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5308 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5310 struct WineD3DRectPatch *patch;
5311 GLenum old_primitive_type;
5315 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5317 if(!(Handle || pRectPatchInfo)) {
5318 /* TODO: Write a test for the return value, thus the FIXME */
5319 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5320 return WINED3DERR_INVALIDCALL;
5324 i = PATCHMAP_HASHFUNC(Handle);
5326 LIST_FOR_EACH(e, &This->patches[i]) {
5327 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5328 if(patch->Handle == Handle) {
5335 TRACE("Patch does not exist. Creating a new one\n");
5336 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5337 patch->Handle = Handle;
5338 list_add_head(&This->patches[i], &patch->entry);
5340 TRACE("Found existing patch %p\n", patch);
5343 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5344 * attributes we have to tesselate, read back, and draw. This needs a patch
5345 * management structure instance. Create one.
5347 * A possible improvement is to check if a vertex shader is used, and if not directly
5350 FIXME("Drawing an uncached patch. This is slow\n");
5351 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5354 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5355 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5356 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5358 TRACE("Tesselation density or patch info changed, retesselating\n");
5360 if(pRectPatchInfo) {
5361 patch->RectPatchInfo = *pRectPatchInfo;
5363 patch->numSegs[0] = pNumSegs[0];
5364 patch->numSegs[1] = pNumSegs[1];
5365 patch->numSegs[2] = pNumSegs[2];
5366 patch->numSegs[3] = pNumSegs[3];
5368 hr = tesselate_rectpatch(This, patch);
5370 WARN("Patch tesselation failed\n");
5372 /* Do not release the handle to store the params of the patch */
5374 HeapFree(GetProcessHeap(), 0, patch);
5380 This->currentPatch = patch;
5381 old_primitive_type = This->stateBlock->gl_primitive_type;
5382 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5383 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5384 This->stateBlock->gl_primitive_type = old_primitive_type;
5385 This->currentPatch = NULL;
5387 /* Destroy uncached patches */
5389 HeapFree(GetProcessHeap(), 0, patch->mem);
5390 HeapFree(GetProcessHeap(), 0, patch);
5395 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5396 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5398 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5399 iface, handle, segment_count, patch_info);
5404 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5407 struct WineD3DRectPatch *patch;
5409 TRACE("(%p) Handle(%d)\n", This, Handle);
5411 i = PATCHMAP_HASHFUNC(Handle);
5412 LIST_FOR_EACH(e, &This->patches[i]) {
5413 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5414 if(patch->Handle == Handle) {
5415 TRACE("Deleting patch %p\n", patch);
5416 list_remove(&patch->entry);
5417 HeapFree(GetProcessHeap(), 0, patch->mem);
5418 HeapFree(GetProcessHeap(), 0, patch);
5423 /* TODO: Write a test for the return value */
5424 FIXME("Attempt to destroy nonexistent patch\n");
5425 return WINED3DERR_INVALIDCALL;
5428 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5429 const WINED3DRECT *rect, const float color[4])
5431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5432 struct wined3d_context *context;
5434 if (rect) IWineD3DSurface_LoadLocation(surface, SFLAG_INDRAWABLE, NULL);
5435 IWineD3DSurface_ModifyLocation(surface, SFLAG_INDRAWABLE, TRUE);
5437 if (!surface_is_offscreen(surface))
5439 TRACE("Surface %p is onscreen\n", surface);
5441 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5443 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5444 context_set_draw_buffer(context, surface_get_gl_buffer(surface));
5448 TRACE("Surface %p is offscreen\n", surface);
5450 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5452 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5453 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5454 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5458 glEnable(GL_SCISSOR_TEST);
5459 if(surface_is_offscreen(surface)) {
5460 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5462 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5463 rect->x2 - rect->x1, rect->y2 - rect->y1);
5465 checkGLcall("glScissor");
5466 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5468 glDisable(GL_SCISSOR_TEST);
5470 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5472 glDisable(GL_BLEND);
5473 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5475 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5476 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5478 glClearColor(color[0], color[1], color[2], color[3]);
5479 glClear(GL_COLOR_BUFFER_BIT);
5480 checkGLcall("glClear");
5484 wglFlush(); /* Flush to ensure ordering across contexts. */
5486 context_release(context);
5489 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5490 unsigned int r, g, b, a;
5493 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
5494 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
5495 || destfmt == WINED3DFMT_B8G8R8_UNORM)
5498 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5500 a = (color & 0xff000000) >> 24;
5501 r = (color & 0x00ff0000) >> 16;
5502 g = (color & 0x0000ff00) >> 8;
5503 b = (color & 0x000000ff) >> 0;
5507 case WINED3DFMT_B5G6R5_UNORM:
5508 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5515 TRACE("Returning %08x\n", ret);
5518 case WINED3DFMT_B5G5R5X1_UNORM:
5519 case WINED3DFMT_B5G5R5A1_UNORM:
5528 TRACE("Returning %08x\n", ret);
5531 case WINED3DFMT_A8_UNORM:
5532 TRACE("Returning %08x\n", a);
5535 case WINED3DFMT_B4G4R4X4_UNORM:
5536 case WINED3DFMT_B4G4R4A4_UNORM:
5545 TRACE("Returning %08x\n", ret);
5548 case WINED3DFMT_B2G3R3_UNORM:
5555 TRACE("Returning %08x\n", ret);
5558 case WINED3DFMT_R8G8B8X8_UNORM:
5559 case WINED3DFMT_R8G8B8A8_UNORM:
5564 TRACE("Returning %08x\n", ret);
5567 case WINED3DFMT_B10G10R10A2_UNORM:
5569 r = (r * 1024) / 256;
5570 g = (g * 1024) / 256;
5571 b = (b * 1024) / 256;
5576 TRACE("Returning %08x\n", ret);
5579 case WINED3DFMT_R10G10B10A2_UNORM:
5581 r = (r * 1024) / 256;
5582 g = (g * 1024) / 256;
5583 b = (b * 1024) / 256;
5588 TRACE("Returning %08x\n", ret);
5592 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5597 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5598 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5600 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5603 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5605 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5606 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5607 return WINED3DERR_INVALIDCALL;
5610 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5611 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5612 color_fill_fbo(iface, pSurface, pRect, c);
5615 /* Just forward this to the DirectDraw blitting engine */
5616 memset(&BltFx, 0, sizeof(BltFx));
5617 BltFx.dwSize = sizeof(BltFx);
5618 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
5619 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5620 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5624 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5625 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5627 IWineD3DResource *resource;
5628 IWineD3DSurface *surface;
5631 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5634 ERR("Failed to get resource, hr %#x\n", hr);
5638 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5640 FIXME("Only supported on surface resources\n");
5641 IWineD3DResource_Release(resource);
5645 surface = (IWineD3DSurface *)resource;
5647 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5649 color_fill_fbo(iface, surface, NULL, color);
5656 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5658 c = ((DWORD)(color[2] * 255.0f));
5659 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5660 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5661 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5663 /* Just forward this to the DirectDraw blitting engine */
5664 memset(&BltFx, 0, sizeof(BltFx));
5665 BltFx.dwSize = sizeof(BltFx);
5666 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
5667 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5670 ERR("Blt failed, hr %#x\n", hr);
5674 IWineD3DResource_Release(resource);
5677 /* rendertarget and depth stencil functions */
5678 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5681 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5683 ERR("(%p) : Only %d render targets are supported.\n",
5684 This, This->adapter->gl_info.limits.buffers);
5685 return WINED3DERR_INVALIDCALL;
5688 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5689 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5690 /* Note inc ref on returned surface */
5691 if(*ppRenderTarget != NULL)
5692 IWineD3DSurface_AddRef(*ppRenderTarget);
5696 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5697 IWineD3DSurface *Front, IWineD3DSurface *Back)
5699 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5700 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5701 IWineD3DSwapChainImpl *Swapchain;
5704 TRACE("iface %p, front %p, back %p.\n", iface, Front, Back);
5706 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5707 if(hr != WINED3D_OK) {
5708 ERR("Can't get the swapchain\n");
5712 /* Make sure to release the swapchain */
5713 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5715 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5716 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5717 return WINED3DERR_INVALIDCALL;
5719 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5720 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5721 return WINED3DERR_INVALIDCALL;
5724 if(Swapchain->frontBuffer != Front) {
5725 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5727 if(Swapchain->frontBuffer)
5729 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5730 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
5732 Swapchain->frontBuffer = Front;
5734 if(Swapchain->frontBuffer) {
5735 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5736 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
5740 if(Back && !Swapchain->backBuffer) {
5741 /* We need memory for the back buffer array - only one back buffer this way */
5742 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5743 if(!Swapchain->backBuffer) {
5744 ERR("Out of memory\n");
5745 return E_OUTOFMEMORY;
5749 if(Swapchain->backBuffer[0] != Back) {
5750 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5752 /* What to do about the context here in the case of multithreading? Not sure.
5753 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5755 WARN("No active context?\n");
5758 if(!Swapchain->backBuffer[0]) {
5759 /* GL was told to draw to the front buffer at creation,
5762 glDrawBuffer(GL_BACK);
5763 checkGLcall("glDrawBuffer(GL_BACK)");
5764 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5765 Swapchain->presentParms.BackBufferCount = 1;
5767 /* That makes problems - disable for now */
5768 /* glDrawBuffer(GL_FRONT); */
5769 checkGLcall("glDrawBuffer(GL_FRONT)");
5770 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5771 Swapchain->presentParms.BackBufferCount = 0;
5775 if(Swapchain->backBuffer[0])
5777 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5778 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
5780 Swapchain->backBuffer[0] = Back;
5782 if(Swapchain->backBuffer[0]) {
5783 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5784 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
5785 Swapchain->presentParms.BackBufferWidth = BackImpl->currentDesc.Width;
5786 Swapchain->presentParms.BackBufferHeight = BackImpl->currentDesc.Height;
5787 Swapchain->presentParms.BackBufferFormat = BackImpl->resource.format_desc->format;
5789 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5790 Swapchain->backBuffer = NULL;
5798 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5800 *ppZStencilSurface = This->stencilBufferTarget;
5801 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5803 if(*ppZStencilSurface != NULL) {
5804 /* Note inc ref on returned surface */
5805 IWineD3DSurface_AddRef(*ppZStencilSurface);
5808 return WINED3DERR_NOTFOUND;
5812 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5813 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
5815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5816 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5817 const struct wined3d_gl_info *gl_info;
5818 struct wined3d_context *context;
5820 POINT offset = {0, 0};
5822 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5823 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5824 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5825 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5828 case WINED3DTEXF_LINEAR:
5829 gl_filter = GL_LINEAR;
5833 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5834 case WINED3DTEXF_NONE:
5835 case WINED3DTEXF_POINT:
5836 gl_filter = GL_NEAREST;
5840 /* Make sure the drawables are up-to-date. Note that loading the
5841 * destination surface isn't strictly required if we overwrite the
5842 * entire surface. */
5843 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
5844 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
5846 if (!surface_is_offscreen(src_surface)) context = context_acquire(This, src_surface, CTXUSAGE_RESOURCELOAD);
5847 else if (!surface_is_offscreen(dst_surface)) context = context_acquire(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5848 else context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5850 gl_info = context->gl_info;
5852 if (!surface_is_offscreen(src_surface))
5854 GLenum buffer = surface_get_gl_buffer(src_surface);
5856 TRACE("Source surface %p is onscreen\n", src_surface);
5858 if(buffer == GL_FRONT) {
5861 ClientToScreen(context->win_handle, &offset);
5862 GetClientRect(context->win_handle, &windowsize);
5863 h = windowsize.bottom - windowsize.top;
5864 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
5865 src_rect->y1 = offset.y + h - src_rect->y1;
5866 src_rect->y2 = offset.y + h - src_rect->y2;
5868 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5869 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5873 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5874 glReadBuffer(buffer);
5875 checkGLcall("glReadBuffer()");
5877 TRACE("Source surface %p is offscreen\n", src_surface);
5879 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5880 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
5881 glReadBuffer(GL_COLOR_ATTACHMENT0);
5882 checkGLcall("glReadBuffer()");
5883 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5887 /* Attach dst surface to dst fbo */
5888 if (!surface_is_offscreen(dst_surface))
5890 GLenum buffer = surface_get_gl_buffer(dst_surface);
5892 TRACE("Destination surface %p is onscreen\n", dst_surface);
5894 if(buffer == GL_FRONT) {
5897 ClientToScreen(context->win_handle, &offset);
5898 GetClientRect(context->win_handle, &windowsize);
5899 h = windowsize.bottom - windowsize.top;
5900 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
5901 dst_rect->y1 = offset.y + h - dst_rect->y1;
5902 dst_rect->y2 = offset.y + h - dst_rect->y2;
5904 /* Screen coords = window coords, surface height = window height */
5905 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5906 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5910 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5911 context_set_draw_buffer(context, buffer);
5915 TRACE("Destination surface %p is offscreen\n", dst_surface);
5918 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5919 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
5920 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5921 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5923 glDisable(GL_SCISSOR_TEST);
5924 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5927 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5928 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
5929 checkGLcall("glBlitFramebuffer()");
5931 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5932 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
5933 checkGLcall("glBlitFramebuffer()");
5938 wglFlush(); /* Flush to ensure ordering across contexts. */
5940 context_release(context);
5942 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
5945 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5946 BOOL set_viewport) {
5947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5949 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5951 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5953 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5954 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5955 return WINED3DERR_INVALIDCALL;
5958 /* MSDN says that null disables the render target
5959 but a device must always be associated with a render target
5960 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5962 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5963 FIXME("Trying to set render target 0 to NULL\n");
5964 return WINED3DERR_INVALIDCALL;
5966 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5967 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);
5968 return WINED3DERR_INVALIDCALL;
5971 /* If we are trying to set what we already have, don't bother */
5972 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5973 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5976 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5977 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5978 This->render_targets[RenderTargetIndex] = pRenderTarget;
5980 /* Render target 0 is special */
5981 if(RenderTargetIndex == 0 && set_viewport) {
5982 /* Finally, reset the viewport and scissor rect as the MSDN states.
5983 * Tests show that stateblock recording is ignored, the change goes
5984 * directly into the primary stateblock.
5986 This->stateBlock->viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5987 This->stateBlock->viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5988 This->stateBlock->viewport.X = 0;
5989 This->stateBlock->viewport.Y = 0;
5990 This->stateBlock->viewport.MaxZ = 1.0f;
5991 This->stateBlock->viewport.MinZ = 0.0f;
5992 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5994 This->stateBlock->scissorRect.top = 0;
5995 This->stateBlock->scissorRect.left = 0;
5996 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5997 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5998 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6003 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6005 HRESULT hr = WINED3D_OK;
6006 IWineD3DSurface *tmp;
6008 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6010 if (pNewZStencil == This->stencilBufferTarget) {
6011 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6013 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6014 * depending on the renter target implementation being used.
6015 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6016 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6017 * stencil buffer and incur an extra memory overhead
6018 ******************************************************/
6020 if (This->stencilBufferTarget) {
6021 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6022 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6023 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6025 struct wined3d_context *context = context_acquire(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6026 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
6027 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6028 context_release(context);
6032 tmp = This->stencilBufferTarget;
6033 This->stencilBufferTarget = pNewZStencil;
6034 /* should we be calling the parent or the wined3d surface? */
6035 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6036 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6039 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6040 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6041 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6042 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6043 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6050 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6051 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6053 /* TODO: the use of Impl is deprecated. */
6054 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6055 WINED3DLOCKED_RECT lockedRect;
6057 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6059 /* some basic validation checks */
6060 if(This->cursorTexture) {
6061 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6063 glDeleteTextures(1, &This->cursorTexture);
6065 context_release(context);
6066 This->cursorTexture = 0;
6069 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6070 This->haveHardwareCursor = TRUE;
6072 This->haveHardwareCursor = FALSE;
6075 WINED3DLOCKED_RECT rect;
6077 /* MSDN: Cursor must be A8R8G8B8 */
6078 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6080 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6081 return WINED3DERR_INVALIDCALL;
6084 /* MSDN: Cursor must be smaller than the display mode */
6085 if(pSur->currentDesc.Width > This->ddraw_width ||
6086 pSur->currentDesc.Height > This->ddraw_height) {
6087 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);
6088 return WINED3DERR_INVALIDCALL;
6091 if (!This->haveHardwareCursor) {
6092 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6094 /* Do not store the surface's pointer because the application may
6095 * release it after setting the cursor image. Windows doesn't
6096 * addref the set surface, so we can't do this either without
6097 * creating circular refcount dependencies. Copy out the gl texture
6100 This->cursorWidth = pSur->currentDesc.Width;
6101 This->cursorHeight = pSur->currentDesc.Height;
6102 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6104 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6105 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6106 struct wined3d_context *context;
6107 char *mem, *bits = rect.pBits;
6108 GLint intfmt = glDesc->glInternal;
6109 GLint format = glDesc->glFormat;
6110 GLint type = glDesc->glType;
6111 INT height = This->cursorHeight;
6112 INT width = This->cursorWidth;
6113 INT bpp = glDesc->byte_count;
6117 /* Reformat the texture memory (pitch and width can be
6119 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6120 for(i = 0; i < height; i++)
6121 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6122 IWineD3DSurface_UnlockRect(pCursorBitmap);
6124 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6128 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6130 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6131 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6134 /* Make sure that a proper texture unit is selected */
6135 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6136 checkGLcall("glActiveTextureARB");
6137 sampler = This->rev_tex_unit_map[0];
6138 if (sampler != WINED3D_UNMAPPED_STAGE)
6140 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6142 /* Create a new cursor texture */
6143 glGenTextures(1, &This->cursorTexture);
6144 checkGLcall("glGenTextures");
6145 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6146 checkGLcall("glBindTexture");
6147 /* Copy the bitmap memory into the cursor texture */
6148 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6149 HeapFree(GetProcessHeap(), 0, mem);
6150 checkGLcall("glTexImage2D");
6152 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6154 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6155 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6160 context_release(context);
6164 FIXME("A cursor texture was not returned.\n");
6165 This->cursorTexture = 0;
6170 /* Draw a hardware cursor */
6171 ICONINFO cursorInfo;
6173 /* Create and clear maskBits because it is not needed for
6174 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6176 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6177 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6178 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6179 WINED3DLOCK_NO_DIRTY_UPDATE |
6180 WINED3DLOCK_READONLY
6182 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6183 pSur->currentDesc.Height);
6185 cursorInfo.fIcon = FALSE;
6186 cursorInfo.xHotspot = XHotSpot;
6187 cursorInfo.yHotspot = YHotSpot;
6188 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6190 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6191 1, 32, lockedRect.pBits);
6192 IWineD3DSurface_UnlockRect(pCursorBitmap);
6193 /* Create our cursor and clean up. */
6194 cursor = CreateIconIndirect(&cursorInfo);
6196 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6197 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6198 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6199 This->hardwareCursor = cursor;
6200 HeapFree(GetProcessHeap(), 0, maskBits);
6204 This->xHotSpot = XHotSpot;
6205 This->yHotSpot = YHotSpot;
6209 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6211 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6213 This->xScreenSpace = XScreenSpace;
6214 This->yScreenSpace = YScreenSpace;
6220 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6222 BOOL oldVisible = This->bCursorVisible;
6225 TRACE("(%p) : visible(%d)\n", This, bShow);
6228 * When ShowCursor is first called it should make the cursor appear at the OS's last
6229 * known cursor position. Because of this, some applications just repetitively call
6230 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6233 This->xScreenSpace = pt.x;
6234 This->yScreenSpace = pt.y;
6236 if (This->haveHardwareCursor) {
6237 This->bCursorVisible = bShow;
6239 SetCursor(This->hardwareCursor);
6245 if (This->cursorTexture)
6246 This->bCursorVisible = bShow;
6252 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6253 TRACE("checking resource %p for eviction\n", resource);
6254 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6255 TRACE("Evicting %p\n", resource);
6256 IWineD3DResource_UnLoad(resource);
6258 IWineD3DResource_Release(resource);
6262 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6264 TRACE("iface %p.\n", iface);
6266 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6270 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6272 IWineD3DDeviceImpl *device = surface->resource.device;
6273 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6275 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6276 if(surface->Flags & SFLAG_DIBSECTION) {
6277 /* Release the DC */
6278 SelectObject(surface->hDC, surface->dib.holdbitmap);
6279 DeleteDC(surface->hDC);
6280 /* Release the DIB section */
6281 DeleteObject(surface->dib.DIBsection);
6282 surface->dib.bitmap_data = NULL;
6283 surface->resource.allocatedMemory = NULL;
6284 surface->Flags &= ~SFLAG_DIBSECTION;
6286 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6287 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6288 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6289 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6291 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6292 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6294 surface->pow2Width = surface->pow2Height = 1;
6295 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6296 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6298 surface->glRect.left = 0;
6299 surface->glRect.top = 0;
6300 surface->glRect.right = surface->pow2Width;
6301 surface->glRect.bottom = surface->pow2Height;
6303 if (surface->texture_name)
6305 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6307 glDeleteTextures(1, &surface->texture_name);
6309 context_release(context);
6310 surface->texture_name = 0;
6311 surface->Flags &= ~SFLAG_CLIENT;
6313 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6314 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6315 surface->Flags |= SFLAG_NONPOW2;
6317 surface->Flags &= ~SFLAG_NONPOW2;
6319 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6320 surface->resource.allocatedMemory = NULL;
6321 surface->resource.heapMemory = NULL;
6322 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6324 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6326 if(!surface_init_sysmem((IWineD3DSurface *) surface))
6328 return E_OUTOFMEMORY;
6333 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6334 TRACE("Unloading resource %p\n", resource);
6335 IWineD3DResource_UnLoad(resource);
6336 IWineD3DResource_Release(resource);
6340 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6343 WINED3DDISPLAYMODE m;
6346 /* All Windowed modes are supported, as is leaving the current mode */
6347 if(pp->Windowed) return TRUE;
6348 if(!pp->BackBufferWidth) return TRUE;
6349 if(!pp->BackBufferHeight) return TRUE;
6351 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6352 for(i = 0; i < count; i++) {
6353 memset(&m, 0, sizeof(m));
6354 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6356 ERR("EnumAdapterModes failed\n");
6358 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6359 /* Mode found, it is supported */
6363 /* Mode not found -> not supported */
6367 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6368 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6369 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6370 const struct wined3d_gl_info *gl_info;
6371 struct wined3d_context *context;
6372 IWineD3DBaseShaderImpl *shader;
6374 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6375 gl_info = context->gl_info;
6377 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6378 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6379 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6383 if(This->depth_blt_texture) {
6384 glDeleteTextures(1, &This->depth_blt_texture);
6385 This->depth_blt_texture = 0;
6387 if (This->depth_blt_rb) {
6388 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6389 This->depth_blt_rb = 0;
6390 This->depth_blt_rb_w = 0;
6391 This->depth_blt_rb_h = 0;
6395 This->blitter->free_private(iface);
6396 This->frag_pipe->free_private(iface);
6397 This->shader_backend->shader_free_private(iface);
6398 destroy_dummy_textures(This, gl_info);
6400 context_release(context);
6402 while (This->numContexts)
6404 context_destroy(This, This->contexts[0]);
6406 HeapFree(GetProcessHeap(), 0, swapchain->context);
6407 swapchain->context = NULL;
6408 swapchain->num_contexts = 0;
6411 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6413 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6414 struct wined3d_context *context;
6416 IWineD3DSurfaceImpl *target;
6418 /* Recreate the primary swapchain's context */
6419 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6420 if (!swapchain->context)
6422 ERR("Failed to allocate memory for swapchain context array.\n");
6423 return E_OUTOFMEMORY;
6426 target = (IWineD3DSurfaceImpl *)(swapchain->backBuffer ? swapchain->backBuffer[0] : swapchain->frontBuffer);
6427 if (!(context = context_create(swapchain, target)))
6429 WARN("Failed to create context.\n");
6430 HeapFree(GetProcessHeap(), 0, swapchain->context);
6434 swapchain->context[0] = context;
6435 swapchain->num_contexts = 1;
6436 create_dummy_textures(This);
6437 context_release(context);
6439 hr = This->shader_backend->shader_alloc_private(iface);
6442 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6446 hr = This->frag_pipe->alloc_private(iface);
6449 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6450 This->shader_backend->shader_free_private(iface);
6454 hr = This->blitter->alloc_private(iface);
6457 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6458 This->frag_pipe->free_private(iface);
6459 This->shader_backend->shader_free_private(iface);
6466 context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6467 destroy_dummy_textures(This, context->gl_info);
6468 context_release(context);
6469 context_destroy(This, context);
6470 HeapFree(GetProcessHeap(), 0, swapchain->context);
6471 swapchain->num_contexts = 0;
6475 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6477 IWineD3DSwapChainImpl *swapchain;
6479 BOOL DisplayModeChanged = FALSE;
6480 WINED3DDISPLAYMODE mode;
6481 TRACE("(%p)\n", This);
6483 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6485 ERR("Failed to get the first implicit swapchain\n");
6489 if(!is_display_mode_supported(This, pPresentationParameters)) {
6490 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6491 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6492 pPresentationParameters->BackBufferHeight);
6493 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6494 return WINED3DERR_INVALIDCALL;
6497 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6498 * on an existing gl context, so there's no real need for recreation.
6500 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6502 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6504 TRACE("New params:\n");
6505 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6506 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6507 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6508 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6509 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6510 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6511 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6512 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6513 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6514 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6515 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6516 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6517 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6519 /* No special treatment of these parameters. Just store them */
6520 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6521 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6522 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6523 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6525 /* What to do about these? */
6526 if(pPresentationParameters->BackBufferCount != 0 &&
6527 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6528 ERR("Cannot change the back buffer count yet\n");
6530 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6531 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6532 ERR("Cannot change the back buffer format yet\n");
6534 if(pPresentationParameters->hDeviceWindow != NULL &&
6535 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6536 ERR("Cannot change the device window yet\n");
6538 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
6541 TRACE("Creating the depth stencil buffer\n");
6543 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6545 pPresentationParameters->BackBufferWidth,
6546 pPresentationParameters->BackBufferHeight,
6547 pPresentationParameters->AutoDepthStencilFormat,
6548 pPresentationParameters->MultiSampleType,
6549 pPresentationParameters->MultiSampleQuality,
6551 &This->auto_depth_stencil_buffer);
6554 ERR("Failed to create the depth stencil buffer\n");
6555 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6556 return WINED3DERR_INVALIDCALL;
6560 /* Reset the depth stencil */
6561 if (pPresentationParameters->EnableAutoDepthStencil)
6562 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
6564 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6566 TRACE("Resetting stateblock\n");
6567 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6568 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6570 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
6572 if(pPresentationParameters->Windowed) {
6573 mode.Width = swapchain->orig_width;
6574 mode.Height = swapchain->orig_height;
6575 mode.RefreshRate = 0;
6576 mode.Format = swapchain->presentParms.BackBufferFormat;
6578 mode.Width = pPresentationParameters->BackBufferWidth;
6579 mode.Height = pPresentationParameters->BackBufferHeight;
6580 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6581 mode.Format = swapchain->presentParms.BackBufferFormat;
6584 /* Should Width == 800 && Height == 0 set 800x600? */
6585 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6586 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6587 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6591 if(!pPresentationParameters->Windowed) {
6592 DisplayModeChanged = TRUE;
6594 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6595 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6597 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6600 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6604 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6605 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6608 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6612 if(This->auto_depth_stencil_buffer) {
6613 hr = updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6616 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6622 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6623 || DisplayModeChanged)
6625 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6627 if (!pPresentationParameters->Windowed)
6629 if(swapchain->presentParms.Windowed) {
6630 /* switch from windowed to fs */
6631 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6632 pPresentationParameters->BackBufferHeight);
6634 /* Fullscreen -> fullscreen mode change */
6635 MoveWindow(swapchain->device_window, 0, 0,
6636 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6640 else if (!swapchain->presentParms.Windowed)
6642 /* Fullscreen -> windowed switch */
6643 swapchain_restore_fullscreen_window(swapchain);
6645 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6646 } else if(!pPresentationParameters->Windowed) {
6647 DWORD style = This->style, exStyle = This->exStyle;
6648 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6649 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6650 * Reset to clear up their mess. Guild Wars also loses the device during that.
6654 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6655 pPresentationParameters->BackBufferHeight);
6656 This->style = style;
6657 This->exStyle = exStyle;
6660 /* Note: No parent needed for initial internal stateblock */
6661 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6662 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6663 else TRACE("Created stateblock %p\n", This->stateBlock);
6664 This->updateStateBlock = This->stateBlock;
6665 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6667 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6669 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6672 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6675 GetClientRect(swapchain->win_handle, &client_rect);
6677 if(!swapchain->presentParms.BackBufferCount)
6679 TRACE("Single buffered rendering\n");
6680 swapchain->render_to_fbo = FALSE;
6682 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6683 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6685 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6686 swapchain->presentParms.BackBufferWidth,
6687 swapchain->presentParms.BackBufferHeight,
6688 client_rect.right, client_rect.bottom);
6689 swapchain->render_to_fbo = TRUE;
6693 TRACE("Rendering directly to GL_BACK\n");
6694 swapchain->render_to_fbo = FALSE;
6698 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
6699 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6701 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6707 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6709 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6711 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6717 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6719 TRACE("(%p) : pParameters %p\n", This, pParameters);
6721 *pParameters = This->createParms;
6725 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6726 IWineD3DSwapChain *swapchain;
6728 TRACE("Relaying to swapchain\n");
6730 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6731 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6732 IWineD3DSwapChain_Release(swapchain);
6736 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6737 IWineD3DSwapChain *swapchain;
6739 TRACE("Relaying to swapchain\n");
6741 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6742 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6743 IWineD3DSwapChain_Release(swapchain);
6748 /** ********************************************************
6749 * Notification functions
6750 ** ********************************************************/
6751 /** This function must be called in the release of a resource when ref == 0,
6752 * the contents of resource must still be correct,
6753 * any handles to other resource held by the caller must be closed
6754 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6755 *****************************************************/
6756 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6758 TRACE("(%p) : Adding resource %p\n", This, resource);
6760 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6763 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6765 TRACE("(%p) : Removing resource %p\n", This, resource);
6767 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6770 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6772 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6775 TRACE("(%p) : resource %p\n", This, resource);
6777 context_resource_released((IWineD3DDevice *)This, resource, type);
6780 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6781 case WINED3DRTYPE_SURFACE: {
6784 if (This->d3d_initialized)
6786 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6788 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
6789 This->render_targets[i] = NULL;
6792 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
6793 This->stencilBufferTarget = NULL;
6799 case WINED3DRTYPE_TEXTURE:
6800 case WINED3DRTYPE_CUBETEXTURE:
6801 case WINED3DRTYPE_VOLUMETEXTURE:
6802 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6803 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6804 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6805 This->stateBlock->textures[counter] = NULL;
6807 if (This->updateStateBlock != This->stateBlock ){
6808 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6809 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6810 This->updateStateBlock->textures[counter] = NULL;
6815 case WINED3DRTYPE_VOLUME:
6816 /* TODO: nothing really? */
6818 case WINED3DRTYPE_BUFFER:
6821 TRACE("Cleaning up stream pointers\n");
6823 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6824 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6825 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6827 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6828 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6829 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6830 This->updateStateBlock->streamSource[streamNumber] = 0;
6831 /* Set changed flag? */
6834 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) */
6835 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6836 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6837 This->stateBlock->streamSource[streamNumber] = 0;
6842 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6843 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6844 This->updateStateBlock->pIndexData = NULL;
6847 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6848 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6849 This->stateBlock->pIndexData = NULL;
6856 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6861 /* Remove the resource from the resourceStore */
6862 device_resource_remove(This, resource);
6864 TRACE("Resource released\n");
6868 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6870 IWineD3DResourceImpl *resource, *cursor;
6872 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6874 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6875 TRACE("enumerating resource %p\n", resource);
6876 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6877 ret = pCallback((IWineD3DResource *) resource, pData);
6878 if(ret == S_FALSE) {
6879 TRACE("Canceling enumeration\n");
6886 /**********************************************************
6887 * IWineD3DDevice VTbl follows
6888 **********************************************************/
6890 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6892 /*** IUnknown methods ***/
6893 IWineD3DDeviceImpl_QueryInterface,
6894 IWineD3DDeviceImpl_AddRef,
6895 IWineD3DDeviceImpl_Release,
6896 /*** IWineD3DDevice methods ***/
6897 IWineD3DDeviceImpl_GetParent,
6898 /*** Creation methods**/
6899 IWineD3DDeviceImpl_CreateBuffer,
6900 IWineD3DDeviceImpl_CreateVertexBuffer,
6901 IWineD3DDeviceImpl_CreateIndexBuffer,
6902 IWineD3DDeviceImpl_CreateStateBlock,
6903 IWineD3DDeviceImpl_CreateSurface,
6904 IWineD3DDeviceImpl_CreateRendertargetView,
6905 IWineD3DDeviceImpl_CreateTexture,
6906 IWineD3DDeviceImpl_CreateVolumeTexture,
6907 IWineD3DDeviceImpl_CreateVolume,
6908 IWineD3DDeviceImpl_CreateCubeTexture,
6909 IWineD3DDeviceImpl_CreateQuery,
6910 IWineD3DDeviceImpl_CreateSwapChain,
6911 IWineD3DDeviceImpl_CreateVertexDeclaration,
6912 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6913 IWineD3DDeviceImpl_CreateVertexShader,
6914 IWineD3DDeviceImpl_CreateGeometryShader,
6915 IWineD3DDeviceImpl_CreatePixelShader,
6916 IWineD3DDeviceImpl_CreatePalette,
6917 /*** Odd functions **/
6918 IWineD3DDeviceImpl_Init3D,
6919 IWineD3DDeviceImpl_InitGDI,
6920 IWineD3DDeviceImpl_Uninit3D,
6921 IWineD3DDeviceImpl_UninitGDI,
6922 IWineD3DDeviceImpl_SetMultithreaded,
6923 IWineD3DDeviceImpl_EvictManagedResources,
6924 IWineD3DDeviceImpl_GetAvailableTextureMem,
6925 IWineD3DDeviceImpl_GetBackBuffer,
6926 IWineD3DDeviceImpl_GetCreationParameters,
6927 IWineD3DDeviceImpl_GetDeviceCaps,
6928 IWineD3DDeviceImpl_GetDirect3D,
6929 IWineD3DDeviceImpl_GetDisplayMode,
6930 IWineD3DDeviceImpl_SetDisplayMode,
6931 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6932 IWineD3DDeviceImpl_GetRasterStatus,
6933 IWineD3DDeviceImpl_GetSwapChain,
6934 IWineD3DDeviceImpl_Reset,
6935 IWineD3DDeviceImpl_SetDialogBoxMode,
6936 IWineD3DDeviceImpl_SetCursorProperties,
6937 IWineD3DDeviceImpl_SetCursorPosition,
6938 IWineD3DDeviceImpl_ShowCursor,
6939 /*** Getters and setters **/
6940 IWineD3DDeviceImpl_SetClipPlane,
6941 IWineD3DDeviceImpl_GetClipPlane,
6942 IWineD3DDeviceImpl_SetClipStatus,
6943 IWineD3DDeviceImpl_GetClipStatus,
6944 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6945 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6946 IWineD3DDeviceImpl_SetDepthStencilSurface,
6947 IWineD3DDeviceImpl_GetDepthStencilSurface,
6948 IWineD3DDeviceImpl_SetGammaRamp,
6949 IWineD3DDeviceImpl_GetGammaRamp,
6950 IWineD3DDeviceImpl_SetIndexBuffer,
6951 IWineD3DDeviceImpl_GetIndexBuffer,
6952 IWineD3DDeviceImpl_SetBaseVertexIndex,
6953 IWineD3DDeviceImpl_GetBaseVertexIndex,
6954 IWineD3DDeviceImpl_SetLight,
6955 IWineD3DDeviceImpl_GetLight,
6956 IWineD3DDeviceImpl_SetLightEnable,
6957 IWineD3DDeviceImpl_GetLightEnable,
6958 IWineD3DDeviceImpl_SetMaterial,
6959 IWineD3DDeviceImpl_GetMaterial,
6960 IWineD3DDeviceImpl_SetNPatchMode,
6961 IWineD3DDeviceImpl_GetNPatchMode,
6962 IWineD3DDeviceImpl_SetPaletteEntries,
6963 IWineD3DDeviceImpl_GetPaletteEntries,
6964 IWineD3DDeviceImpl_SetPixelShader,
6965 IWineD3DDeviceImpl_GetPixelShader,
6966 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6967 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6968 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6969 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6970 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6971 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6972 IWineD3DDeviceImpl_SetRenderState,
6973 IWineD3DDeviceImpl_GetRenderState,
6974 IWineD3DDeviceImpl_SetRenderTarget,
6975 IWineD3DDeviceImpl_GetRenderTarget,
6976 IWineD3DDeviceImpl_SetFrontBackBuffers,
6977 IWineD3DDeviceImpl_SetSamplerState,
6978 IWineD3DDeviceImpl_GetSamplerState,
6979 IWineD3DDeviceImpl_SetScissorRect,
6980 IWineD3DDeviceImpl_GetScissorRect,
6981 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6982 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6983 IWineD3DDeviceImpl_SetStreamSource,
6984 IWineD3DDeviceImpl_GetStreamSource,
6985 IWineD3DDeviceImpl_SetStreamSourceFreq,
6986 IWineD3DDeviceImpl_GetStreamSourceFreq,
6987 IWineD3DDeviceImpl_SetTexture,
6988 IWineD3DDeviceImpl_GetTexture,
6989 IWineD3DDeviceImpl_SetTextureStageState,
6990 IWineD3DDeviceImpl_GetTextureStageState,
6991 IWineD3DDeviceImpl_SetTransform,
6992 IWineD3DDeviceImpl_GetTransform,
6993 IWineD3DDeviceImpl_SetVertexDeclaration,
6994 IWineD3DDeviceImpl_GetVertexDeclaration,
6995 IWineD3DDeviceImpl_SetVertexShader,
6996 IWineD3DDeviceImpl_GetVertexShader,
6997 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6998 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6999 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7000 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7001 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7002 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7003 IWineD3DDeviceImpl_SetViewport,
7004 IWineD3DDeviceImpl_GetViewport,
7005 IWineD3DDeviceImpl_MultiplyTransform,
7006 IWineD3DDeviceImpl_ValidateDevice,
7007 IWineD3DDeviceImpl_ProcessVertices,
7008 /*** State block ***/
7009 IWineD3DDeviceImpl_BeginStateBlock,
7010 IWineD3DDeviceImpl_EndStateBlock,
7011 /*** Scene management ***/
7012 IWineD3DDeviceImpl_BeginScene,
7013 IWineD3DDeviceImpl_EndScene,
7014 IWineD3DDeviceImpl_Present,
7015 IWineD3DDeviceImpl_Clear,
7016 IWineD3DDeviceImpl_ClearRendertargetView,
7018 IWineD3DDeviceImpl_SetPrimitiveType,
7019 IWineD3DDeviceImpl_GetPrimitiveType,
7020 IWineD3DDeviceImpl_DrawPrimitive,
7021 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7022 IWineD3DDeviceImpl_DrawPrimitiveUP,
7023 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7024 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7025 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7026 IWineD3DDeviceImpl_DrawRectPatch,
7027 IWineD3DDeviceImpl_DrawTriPatch,
7028 IWineD3DDeviceImpl_DeletePatch,
7029 IWineD3DDeviceImpl_ColorFill,
7030 IWineD3DDeviceImpl_UpdateTexture,
7031 IWineD3DDeviceImpl_UpdateSurface,
7032 IWineD3DDeviceImpl_GetFrontBufferData,
7033 /*** object tracking ***/
7034 IWineD3DDeviceImpl_EnumResources
7037 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
7038 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
7039 IUnknown *parent, IWineD3DDeviceParent *device_parent)
7041 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
7042 const struct fragment_pipeline *fragment_pipeline;
7043 struct shader_caps shader_caps;
7044 struct fragment_caps ffp_caps;
7045 WINED3DDISPLAYMODE mode;
7049 device->lpVtbl = &IWineD3DDevice_Vtbl;
7051 device->wined3d = (IWineD3D *)wined3d;
7052 IWineD3D_AddRef(device->wined3d);
7053 device->adapter = wined3d->adapter_count ? adapter : NULL;
7054 device->parent = parent;
7055 device->device_parent = device_parent;
7056 list_init(&device->resources);
7057 list_init(&device->shaders);
7059 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7060 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
7062 /* Get the initial screen setup for ddraw. */
7063 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
7066 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7067 IWineD3D_Release(device->wined3d);
7070 device->ddraw_width = mode.Width;
7071 device->ddraw_height = mode.Height;
7072 device->ddraw_format = mode.Format;
7074 /* Save the creation parameters. */
7075 device->createParms.AdapterOrdinal = adapter_idx;
7076 device->createParms.DeviceType = device_type;
7077 device->createParms.hFocusWindow = focus_window;
7078 device->createParms.BehaviorFlags = flags;
7080 device->devType = device_type;
7081 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7083 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7084 device->shader_backend = adapter->shader_backend;
7086 memset(&shader_caps, 0, sizeof(shader_caps));
7087 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7088 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7089 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7090 device->vs_clipping = shader_caps.VSClipping;
7092 memset(&ffp_caps, 0, sizeof(ffp_caps));
7093 fragment_pipeline = adapter->fragment_pipe;
7094 device->frag_pipe = fragment_pipeline;
7095 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7096 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7098 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7099 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7102 ERR("Failed to compile state table, hr %#x.\n", hr);
7103 IWineD3D_Release(device->wined3d);
7107 device->blitter = adapter->blitter;
7113 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7114 DWORD rep = This->StateTable[state].representative;
7115 struct wined3d_context *context;
7120 for(i = 0; i < This->numContexts; i++) {
7121 context = This->contexts[i];
7122 if(isStateDirty(context, rep)) continue;
7124 context->dirtyArray[context->numDirtyEntries++] = rep;
7125 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7126 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7127 context->isStateDirty[idx] |= (1 << shift);
7131 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7133 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7134 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7135 *width = surface->pow2Width;
7136 *height = surface->pow2Height;
7139 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7141 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7142 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7143 * current context's drawable, which is the size of the back buffer of the swapchain
7144 * the active context belongs to. */
7145 *width = swapchain->presentParms.BackBufferWidth;
7146 *height = swapchain->presentParms.BackBufferHeight;
7149 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7150 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7152 if (device->filter_messages)
7154 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7155 window, message, wparam, lparam);
7156 return DefWindowProcW(window, message, wparam, lparam);
7159 if (message == WM_DESTROY)
7161 TRACE("unregister window %p.\n", window);
7162 wined3d_unregister_window(window);
7164 if (device->focus_window == window) device->focus_window = NULL;
7165 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7168 return CallWindowProcW(proc, window, message, wparam, lparam);